feat: add a test:apps script

This commit is contained in:
shadcn
2026-02-04 13:14:04 +04:00
parent a012542015
commit e0063070a6
69 changed files with 779 additions and 138 deletions

View File

@@ -0,0 +1,5 @@
---
"shadcn": patch
---
use tw-merge to transform-style

View File

@@ -1,6 +1,7 @@
"use client"
import * as React from "react"
import { useIsMobile } from "@/examples/base/hooks/use-mobile"
import { cn } from "@/examples/base/lib/utils"
import { Button } from "@/examples/base/ui-rtl/button"
import { Input } from "@/examples/base/ui-rtl/input"
@@ -22,7 +23,6 @@ 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 { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const SIDEBAR_COOKIE_NAME = "sidebar_state"

View File

@@ -1,6 +1,7 @@
"use client"
import * as React from "react"
import { useIsMobile } from "@/examples/base/hooks/use-mobile"
import { cn } from "@/examples/base/lib/utils"
import { Button } from "@/examples/base/ui/button"
import { Input } from "@/examples/base/ui/input"
@@ -22,7 +23,6 @@ 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 { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const SIDEBAR_COOKIE_NAME = "sidebar_state"

View File

@@ -1,6 +1,7 @@
"use client"
import * as React from "react"
import { useIsMobile } from "@/examples/radix/hooks/use-mobile"
import { cn } from "@/examples/radix/lib/utils"
import { Button } from "@/examples/radix/ui-rtl/button"
import { Input } from "@/examples/radix/ui-rtl/input"
@@ -21,7 +22,6 @@ import {
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const SIDEBAR_COOKIE_NAME = "sidebar_state"

View File

@@ -1,6 +1,7 @@
"use client"
import * as React from "react"
import { useIsMobile } from "@/examples/radix/hooks/use-mobile"
import { cn } from "@/examples/radix/lib/utils"
import { Button } from "@/examples/radix/ui/button"
import { Input } from "@/examples/radix/ui/input"
@@ -21,7 +22,6 @@ import {
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const SIDEBAR_COOKIE_NAME = "sidebar_state"

View File

@@ -19,6 +19,7 @@
"examples:build": "bun run ./scripts/build-examples.ts && prettier --log-level silent --write \"examples/**/*.{ts,tsx}\" --cache",
"registry:capture": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/capture-registry.mts",
"validate:registries": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/validate-registries.mts",
"test:apps": "bun run ./scripts/build-test-app.mts",
"postinstall": "fumadocs-mdx"
},
"dependencies": {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
"files": [
{
"path": "registry/base-maia/ui/drawer.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/base-maia/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background flex h-auto flex-col bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"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 flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-base font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/base-maia/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background before:border-border flex h-auto flex-col bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl before:border data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"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 flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-base font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"type": "registry:ui"
}
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
"files": [
{
"path": "registry/base-mira/ui/drawer.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/base-mira/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"gap-1 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:text-left flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/base-mira/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background before:border-border flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl before:border data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"gap-1 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:text-left flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"type": "registry:ui"
}
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
"files": [
{
"path": "registry/radix-maia/ui/drawer.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/radix-maia/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background flex h-auto flex-col bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"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 flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-base font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/radix-maia/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background before:border-border flex h-auto flex-col bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl before:border data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"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 flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-base font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"type": "registry:ui"
}
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
"files": [
{
"path": "registry/radix-mira/ui/drawer.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/radix-mira/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"gap-1 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:text-left flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/radix-mira/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"before:bg-background before:border-border flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl before:border data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mt-4 h-1.5 w-[100px] rounded-full mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\"gap-1 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:text-left flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"gap-2 p-4 mt-auto flex flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-xs/relaxed\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n",
"type": "registry:ui"
}
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -36,7 +36,7 @@ export default function CommandExample() {
function CommandInline() {
return (
<Example title="Inline">
<Card className="p-0">
<Card className="w-full p-0">
<CardContent className="p-0">
<Command>
<CommandInput placeholder="Type a command or search..." />

View File

@@ -17,6 +17,7 @@ import {
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -167,9 +168,11 @@ function InputWithSelect() {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="usd">USD</SelectItem>
<SelectItem value="eur">EUR</SelectItem>
<SelectItem value="gbp">GBP</SelectItem>
<SelectGroup>
<SelectItem value="usd">USD</SelectItem>
<SelectItem value="eur">EUR</SelectItem>
<SelectItem value="gbp">GBP</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
@@ -239,9 +242,11 @@ function InputForm() {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
<SelectGroup>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>

View File

@@ -5,6 +5,7 @@ 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 { useIsMobile } from "@/registry/bases/base/hooks/use-mobile"
import { cn } from "@/registry/bases/base/lib/utils"
import { Button } from "@/registry/bases/base/ui/button"
import { Input } from "@/registry/bases/base/ui/input"
@@ -22,7 +23,6 @@ import {
TooltipContent,
TooltipTrigger,
} from "@/registry/bases/base/ui/tooltip"
import { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const SIDEBAR_COOKIE_NAME = "sidebar_state"

View File

@@ -30,6 +30,7 @@ import { Label } from "@/registry/bases/radix/ui/label"
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -251,9 +252,11 @@ function ButtonGroupWithSelect() {
<SelectValue />
</SelectTrigger>
<SelectContent align="start">
<SelectItem value="$">$</SelectItem>
<SelectItem value=""></SelectItem>
<SelectItem value="£">£</SelectItem>
<SelectGroup>
<SelectItem value="$">$</SelectItem>
<SelectItem value=""></SelectItem>
<SelectItem value="£">£</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Input placeholder="Enter amount to send" />
@@ -410,9 +413,11 @@ function ButtonGroupWithSelectAndInput() {
<SelectValue placeholder="Select duration" />
</SelectTrigger>
<SelectContent align="start">
<SelectItem value="hours">Hours</SelectItem>
<SelectItem value="days">Days</SelectItem>
<SelectItem value="weeks">Weeks</SelectItem>
<SelectGroup>
<SelectItem value="hours">Hours</SelectItem>
<SelectItem value="days">Days</SelectItem>
<SelectItem value="weeks">Weeks</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Input />

View File

@@ -36,7 +36,7 @@ export default function CommandExample() {
function CommandInline() {
return (
<Example title="Inline">
<Card className="p-0">
<Card className="w-full p-0">
<CardContent className="p-0">
<Command>
<CommandInput placeholder="Type a command or search..." />

View File

@@ -43,6 +43,7 @@ import {
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectSeparator,
SelectTrigger,
@@ -308,9 +309,11 @@ function DialogChatSettings() {
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent align="end">
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
<SelectItem value="system">System</SelectItem>
<SelectGroup>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
<SelectItem value="system">System</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>
@@ -327,30 +330,32 @@ function DialogChatSettings() {
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent align="end">
<SelectItem value="default">
<div className="size-3 rounded-full bg-neutral-500 dark:bg-neutral-400" />
Default
</SelectItem>
<SelectItem value="red">
<div className="size-3 rounded-full bg-red-500 dark:bg-red-400" />
Red
</SelectItem>
<SelectItem value="blue">
<div className="size-3 rounded-full bg-blue-500 dark:bg-blue-400" />
Blue
</SelectItem>
<SelectItem value="green">
<div className="size-3 rounded-full bg-green-500 dark:bg-green-400" />
Green
</SelectItem>
<SelectItem value="purple">
<div className="size-3 rounded-full bg-purple-500 dark:bg-purple-400" />
Purple
</SelectItem>
<SelectItem value="pink">
<div className="size-3 rounded-full bg-pink-500 dark:bg-pink-400" />
Pink
</SelectItem>
<SelectGroup>
<SelectItem value="default">
<div className="size-3 rounded-full bg-neutral-500 dark:bg-neutral-400" />
Default
</SelectItem>
<SelectItem value="red">
<div className="size-3 rounded-full bg-red-500 dark:bg-red-400" />
Red
</SelectItem>
<SelectItem value="blue">
<div className="size-3 rounded-full bg-blue-500 dark:bg-blue-400" />
Blue
</SelectItem>
<SelectItem value="green">
<div className="size-3 rounded-full bg-green-500 dark:bg-green-400" />
Green
</SelectItem>
<SelectItem value="purple">
<div className="size-3 rounded-full bg-purple-500 dark:bg-purple-400" />
Purple
</SelectItem>
<SelectItem value="pink">
<div className="size-3 rounded-full bg-pink-500 dark:bg-pink-400" />
Pink
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>
@@ -374,16 +379,20 @@ function DialogChatSettings() {
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent align="end" position="item-aligned">
<SelectItem value="auto">Auto</SelectItem>
<SelectGroup>
<SelectItem value="auto">Auto</SelectItem>
</SelectGroup>
<SelectSeparator />
{spokenLanguages.map((language) => (
<SelectItem
key={language.value}
value={language.value}
>
{language.label}
</SelectItem>
))}
<SelectGroup>
{spokenLanguages.map((language) => (
<SelectItem
key={language.value}
value={language.value}
>
{language.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Field>
@@ -395,11 +404,16 @@ function DialogChatSettings() {
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent align="end" position="item-aligned">
{voices.map((voice) => (
<SelectItem key={voice.value} value={voice.value}>
{voice.label}
</SelectItem>
))}
<SelectGroup>
{voices.map((voice) => (
<SelectItem
key={voice.value}
value={voice.value}
>
{voice.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Field>

View File

@@ -211,9 +211,11 @@ function SelectFields() {
<SelectValue placeholder="Choose an option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
<SelectGroup>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>
@@ -224,9 +226,11 @@ function SelectFields() {
<SelectValue placeholder="Select your country" />
</SelectTrigger>
<SelectContent>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
<SelectGroup>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FieldDescription>
@@ -243,9 +247,11 @@ function SelectFields() {
<SelectValue placeholder="Select timezone" />
</SelectTrigger>
<SelectContent>
<SelectItem value="utc">UTC</SelectItem>
<SelectItem value="est">Eastern Time</SelectItem>
<SelectItem value="pst">Pacific Time</SelectItem>
<SelectGroup>
<SelectItem value="utc">UTC</SelectItem>
<SelectItem value="est">Eastern Time</SelectItem>
<SelectItem value="pst">Pacific Time</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>
@@ -256,9 +262,11 @@ function SelectFields() {
<SelectValue placeholder="This field has an error" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
<SelectGroup>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FieldDescription>
@@ -274,9 +282,11 @@ function SelectFields() {
<SelectValue placeholder="Cannot select" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
<SelectGroup>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FieldDescription>This field is currently disabled.</FieldDescription>

View File

@@ -17,6 +17,7 @@ import {
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -167,9 +168,11 @@ function InputWithSelect() {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="usd">USD</SelectItem>
<SelectItem value="eur">EUR</SelectItem>
<SelectItem value="gbp">GBP</SelectItem>
<SelectGroup>
<SelectItem value="usd">USD</SelectItem>
<SelectItem value="eur">EUR</SelectItem>
<SelectItem value="gbp">GBP</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
@@ -239,9 +242,11 @@ function InputForm() {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
<SelectGroup>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="uk">United Kingdom</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>

View File

@@ -4,6 +4,7 @@ import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { useIsMobile } from "@/registry/bases/radix/hooks/use-mobile"
import { cn } from "@/registry/bases/radix/lib/utils"
import { Button } from "@/registry/bases/radix/ui/button"
import { Input } from "@/registry/bases/radix/ui/input"
@@ -21,7 +22,6 @@ import {
TooltipContent,
TooltipTrigger,
} from "@/registry/bases/radix/ui/tooltip"
import { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const SIDEBAR_COOKIE_NAME = "sidebar_state"

View File

@@ -478,7 +478,7 @@
}
.cn-drawer-content {
@apply before:bg-background relative flex h-auto flex-col bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm;
@apply before:bg-background before:border-border relative flex h-auto flex-col bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl before:border data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm;
}
.cn-drawer-handle {
@@ -1072,11 +1072,11 @@
}
.cn-sidebar-header {
@apply gap-2 p-2;
@apply gap-2 p-2 [--radius:var(--radius-xl)];
}
.cn-sidebar-content {
@apply no-scrollbar gap-2;
@apply no-scrollbar gap-2 [--radius:var(--radius-xl)];
}
.cn-sidebar-footer {
@@ -1108,7 +1108,7 @@
}
.cn-sidebar-menu-button {
@apply ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-lg p-2 text-left text-sm transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 data-active:font-medium;
@apply ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-lg px-3 py-2 text-left text-sm transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 data-active:font-medium;
}
.cn-sidebar-menu-button-variant-default {
@@ -1128,7 +1128,7 @@
}
.cn-sidebar-menu-button-size-lg {
@apply h-12 text-sm group-data-[collapsible=icon]:p-0!;
@apply h-14 px-3 text-sm group-data-[collapsible=icon]:p-0!;
}
.cn-sidebar-menu-action {

View File

@@ -478,7 +478,7 @@
}
.cn-drawer-content {
@apply before:bg-background relative flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm;
@apply before:bg-background before:border-border relative flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl before:border data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm;
}
.cn-drawer-handle {

View File

@@ -0,0 +1,415 @@
/**
* Build Test Apps Script
*
* This script populates the ui-test-apps repository with components and examples
* from the shadcn/ui registry for testing different style configurations.
*
* Prerequisites:
* 1. Clone the test apps repo: git clone https://github.com/shadcn-ui/ui-test-apps
* 2. Place it at ../../../ui-test-apps (relative to apps/v4) or set TEST_APPS_PATH
*
* Usage:
* pnpm test:apps [STYLE]
*
* Examples:
* pnpm test:apps nova # Build with nova style
* pnpm test:apps maia # Build with maia style
* pnpm test:apps vega # Build with vega style
*
* Available styles: vega, nova, maia, lyra, mira
*
* What it does:
* 1. Copies UI components to next-radix/components/ui and next-base/components/ui
* 2. Copies hooks to next-radix/hooks and next-base/hooks
* 3. Transforms canonical CSS classes (cn-*) to actual Tailwind classes
* 4. Transforms IconPlaceholder to lucide-react icons
* 5. Generates example pages at app/{example}/page.tsx
* 6. Generates block pages at app/blocks/{block}/page.tsx
* 7. Updates the STYLE constant in layout.tsx
*
* After running:
* cd ../../../ui-test-apps
* pnpm install
* pnpm dev
*
* Then visit:
* - http://localhost:3000 (next-radix)
* - http://localhost:3001 (next-base)
*/
import { promises as fs } from "fs"
import path from "path"
import { rimraf } from "rimraf"
import { registrySchema } from "shadcn/schema"
import {
createStyleMap,
transformIcons,
transformStyle,
} from "shadcn/utils"
import { Project, ScriptKind } from "ts-morph"
import { BASES, type Base } from "@/registry/bases"
import { STYLES } from "@/registry/styles"
// Default path to test apps repo.
const DEFAULT_TEST_APPS_PATH = "../../../ui-test-apps"
// Parse CLI arguments.
const args = process.argv.slice(2)
const styleName = args[0]
const testAppsPath =
args[1] || process.env.TEST_APPS_PATH || DEFAULT_TEST_APPS_PATH
if (!styleName) {
console.error("❌ Usage: pnpm test:apps [STYLE] [TEST_APPS_PATH]")
console.error(" Example: pnpm test:apps nova")
console.error("")
console.error(` Available styles: ${STYLES.map((s) => s.name).join(", ")}`)
console.error("")
console.error(` Default test apps path: ${DEFAULT_TEST_APPS_PATH}`)
console.error(` Override with: pnpm test:apps nova /path/to/ui-test-apps`)
console.error(` Or set TEST_APPS_PATH environment variable`)
process.exit(1)
}
// Validate style exists.
const style = STYLES.find((s) => s.name === styleName)
if (!style) {
console.error(`❌ Unknown style: "${styleName}"`)
console.error(` Available styles: ${STYLES.map((s) => s.name).join(", ")}`)
process.exit(1)
}
// Resolve test apps path.
const resolvedTestAppsPath = path.resolve(process.cwd(), testAppsPath)
// Check if test apps path exists.
try {
await fs.access(resolvedTestAppsPath)
} catch {
console.error(`❌ Test apps path not found: ${resolvedTestAppsPath}`)
process.exit(1)
}
console.log(`🏗️ Building test apps with style "${styleName}"...`)
console.log(` Test apps path: ${resolvedTestAppsPath}`)
// Create ts-morph project for icon transformation.
const project = new Project({
useInMemoryFileSystem: true,
})
try {
// Build bases with the selected style.
console.log("\n📦 Building bases...")
const builtRegistries = await buildBasesWithStyle(Array.from(BASES), style)
// Process each base.
for (const { base, registryItems, styleMap } of builtRegistries) {
const testAppDir = path.join(resolvedTestAppsPath, `next-${base.name}`)
// Check if test app exists.
try {
await fs.access(testAppDir)
} catch {
console.log(` ⚠️ ${testAppDir} not found, skipping.`)
continue
}
console.log(`\n📋 Processing ${base.name}...`)
// Clear existing generated content.
await rimraf(path.join(testAppDir, "components/ui"))
await rimraf(path.join(testAppDir, "hooks"))
// Clear example routes (directories in app/).
const appDir = path.join(testAppDir, "app")
const appContents = await fs.readdir(appDir)
for (const item of appContents) {
const itemPath = path.join(appDir, item)
const stat = await fs.stat(itemPath)
if (stat.isDirectory()) {
await rimraf(itemPath)
}
}
// Copy UI components.
console.log(` 📁 Copying UI components...`)
await copyTransformedFiles(
path.join(process.cwd(), `registry/bases/${base.name}/ui`),
path.join(testAppDir, "components/ui"),
base,
styleMap
)
// Copy hooks.
console.log(` 📁 Copying hooks...`)
await copyTransformedFiles(
path.join(process.cwd(), `registry/bases/${base.name}/hooks`),
path.join(testAppDir, "hooks"),
base,
styleMap
)
// Generate example pages.
console.log(` 📄 Generating example pages...`)
const examplesDir = path.join(
process.cwd(),
`registry/bases/${base.name}/examples`
)
let exampleFiles: string[] = []
try {
exampleFiles = (await fs.readdir(examplesDir)).filter(
(f) =>
f.endsWith(".tsx") &&
!f.startsWith("_") &&
f !== "component-example.tsx" // Skip the generic component example.
)
} catch {
console.log(` ⚠️ No examples directory found for ${base.name}.`)
}
const generatedExamples: string[] = []
for (const exampleFile of exampleFiles) {
// Extract example name: "accordion-example.tsx" -> "accordion".
const exampleName = exampleFile
.replace("-example.tsx", "")
.replace(".tsx", "")
const sourcePath = path.join(examplesDir, exampleFile)
const targetDir = path.join(appDir, exampleName)
const targetPath = path.join(targetDir, "page.tsx")
// Read and transform the example file.
let content = await fs.readFile(sourcePath, "utf-8")
// Apply style transformation.
content = await transformStyle(content, { styleMap })
// Transform icons using shadcn transformer.
content = await applyIconTransform(content, exampleFile)
// Rewrite imports.
content = rewriteImports(content, base.name)
// Transform the default export function name to Page.
content = transformDefaultExport(content)
// Write the transformed example as a page.
await fs.mkdir(targetDir, { recursive: true })
await fs.writeFile(targetPath, content)
generatedExamples.push(exampleName)
}
console.log(` ✅ Generated ${generatedExamples.length} example pages`)
// Generate block pages.
console.log(` 📄 Generating block pages...`)
const blocksDir = path.join(
process.cwd(),
`registry/bases/${base.name}/blocks`
)
let blockFiles: string[] = []
try {
blockFiles = (await fs.readdir(blocksDir)).filter(
(f) => f.endsWith(".tsx") && !f.startsWith("_")
)
} catch {
console.log(` ⚠️ No blocks directory found for ${base.name}.`)
}
const generatedBlocks: string[] = []
for (const blockFile of blockFiles) {
// Extract block name: "chatgpt.tsx" -> "chatgpt".
const blockName = blockFile.replace(".tsx", "")
const sourcePath = path.join(blocksDir, blockFile)
const targetDir = path.join(appDir, `blocks/${blockName}`)
const targetPath = path.join(targetDir, "page.tsx")
// Read and transform the block file.
let content = await fs.readFile(sourcePath, "utf-8")
// Apply style transformation.
content = await transformStyle(content, { styleMap })
// Transform icons using shadcn transformer.
content = await applyIconTransform(content, blockFile)
// Rewrite imports.
content = rewriteImports(content, base.name)
// Transform the default export function name to Page.
content = transformDefaultExport(content)
// Write the transformed block as a page.
await fs.mkdir(targetDir, { recursive: true })
await fs.writeFile(targetPath, content)
generatedBlocks.push(blockName)
}
console.log(` ✅ Generated ${generatedBlocks.length} block pages`)
// Update STYLE constant in layout.tsx.
await updateLayoutStyle(testAppDir, styleName)
}
console.log(`\n✅ Test apps built successfully!`)
console.log(`\n📌 Next steps:`)
console.log(` cd ${resolvedTestAppsPath}`)
console.log(` pnpm install`)
console.log(` pnpm dev`)
} catch (error) {
console.error("\n❌ Build failed:", error)
process.exit(1)
}
async function buildBasesWithStyle(bases: Base[], style: (typeof STYLES)[0]) {
// Load style map.
const styleContent = await fs.readFile(
path.join(process.cwd(), `registry/styles/style-${style.name}.css`),
"utf8"
)
const styleMap = createStyleMap(styleContent)
// Load registries for each base.
const results: Array<{
base: Base
registryItems: Array<{ name: string; files?: Array<{ path: string }> }>
styleMap: Record<string, string>
}> = []
for (const base of bases) {
const { registry: baseRegistry } = await import(
`../registry/bases/${base.name}/registry.ts`
)
const result = registrySchema.safeParse(baseRegistry)
if (!result.success) {
console.error(`❌ Registry validation failed for ${base.name}:`)
console.error(result.error.format())
throw new Error(`Invalid registry schema for ${base.name}`)
}
const registryItems = result.data.items.filter(
(item) => item.type !== "registry:internal"
)
results.push({ base, registryItems, styleMap })
console.log(` ✅ Loaded ${base.name} registry`)
}
return results
}
async function copyTransformedFiles(
sourceDir: string,
targetDir: string,
base: Base,
styleMap: Record<string, string>
) {
try {
await fs.access(sourceDir)
} catch {
return
}
await fs.mkdir(targetDir, { recursive: true })
const files = await fs.readdir(sourceDir)
for (const file of files) {
// Skip _registry.ts files.
if (file.startsWith("_")) {
continue
}
const sourcePath = path.join(sourceDir, file)
const targetPath = path.join(targetDir, file)
const stat = await fs.stat(sourcePath)
if (stat.isDirectory()) {
await copyTransformedFiles(sourcePath, targetPath, base, styleMap)
} else {
let content = await fs.readFile(sourcePath, "utf-8")
// Apply style transformation for .tsx and .ts files.
if (file.endsWith(".tsx") || file.endsWith(".ts")) {
content = await transformStyle(content, { styleMap })
content = await applyIconTransform(content, file)
content = rewriteImports(content, base.name)
}
await fs.writeFile(targetPath, content)
}
}
}
async function applyIconTransform(content: string, filename: string) {
const sourceFile = project.createSourceFile(filename, content, {
scriptKind: ScriptKind.TSX,
overwrite: true,
})
// Create a minimal config with just iconLibrary.
const config = { iconLibrary: "lucide" } as { iconLibrary: string }
await transformIcons({
sourceFile,
config,
filename,
raw: content,
})
return sourceFile.getText()
}
function rewriteImports(content: string, baseName: string) {
// Rewrite base registry imports to test app paths.
content = content.replace(
new RegExp(`@/registry/bases/${baseName}/ui/`, "g"),
"@/components/ui/"
)
content = content.replace(
new RegExp(`@/registry/bases/${baseName}/lib/`, "g"),
"@/lib/"
)
content = content.replace(
new RegExp(`@/registry/bases/${baseName}/hooks/`, "g"),
"@/hooks/"
)
content = content.replace(
new RegExp(`@/registry/bases/${baseName}/components/`, "g"),
"@/components/"
)
// Remove imports from @/app (like IconPlaceholder).
content = content.replace(/^import.*from\s+["']@\/app\/.*["'].*\n/gm, "")
return content
}
function transformDefaultExport(content: string) {
// Replace "export default function XxxExample" with "export default function Page".
content = content.replace(
/export\s+default\s+function\s+\w+\s*\(/,
"export default function Page("
)
return content
}
async function updateLayoutStyle(testAppDir: string, styleName: string) {
const layoutPath = path.join(testAppDir, "app/layout.tsx")
try {
let content = await fs.readFile(layoutPath, "utf-8")
// Replace the STYLE constant value.
content = content.replace(
/const STYLE = ["'][^"']*["']/,
`const STYLE = "${styleName}"`
)
await fs.writeFile(layoutPath, content)
console.log(` ✅ Updated STYLE in layout.tsx to "${styleName}"`)
} catch {
console.log(` ⚠️ Could not update layout.tsx`)
}
}

View File

@@ -39,7 +39,8 @@
"pub:release": "cd packages/shadcn && pnpm pub:release",
"test:dev": "turbo run test --filter=!shadcn-ui --force",
"test": "start-server-and-test v4:dev http://localhost:4000 test:dev",
"validate:registries": "pnpm --filter=v4 validate:registries"
"validate:registries": "pnpm --filter=v4 validate:registries",
"test:apps": "pnpm --filter=v4 test:apps"
},
"packageManager": "pnpm@9.0.6",
"dependencies": {

View File

@@ -794,6 +794,186 @@ function Foo({ className, ...props }: { className?: string }) {
`)
})
it("handles conflicting color classes with tailwind-merge", async () => {
const source = `import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("cn-foo bg-primary", className)} {...props} />
)
}
`
const styleMap: StyleMap = {
"cn-foo": "bg-muted text-foreground",
}
const result = await applyTransform(source, styleMap)
// bg-muted from style map should be overridden by bg-primary from existing.
expect(result).toMatchInlineSnapshot(`
"import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("text-foreground bg-primary", className)} {...props} />
)
}
"
`)
})
it("handles conflicting size classes with tailwind-merge", async () => {
const source = `import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("cn-foo text-lg rounded-lg", className)} {...props} />
)
}
`
const styleMap: StyleMap = {
"cn-foo": "text-sm rounded-md border",
}
const result = await applyTransform(source, styleMap)
// text-sm and rounded-md from style map should be overridden.
expect(result).toMatchInlineSnapshot(`
"import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("border text-lg rounded-lg", className)} {...props} />
)
}
"
`)
})
it("handles multiple duplicates in cva base and variants", async () => {
const source = `import * as React from "react"
import { cva } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"cn-button rounded-md",
{
variants: {
variant: {
default: "cn-button-default bg-primary",
},
},
}
)
function Button({ className, ...props }: React.ComponentProps<"button">) {
return (
<button className={cn(buttonVariants({ className }))} {...props} />
)
}
`
const styleMap: StyleMap = {
"cn-button": "rounded-lg border font-medium",
"cn-button-default": "bg-muted text-foreground",
}
const result = await applyTransform(source, styleMap)
// rounded-lg should be overridden by rounded-md, bg-muted should be overridden by bg-primary.
expect(result).toMatchInlineSnapshot(`
"import * as React from "react"
import { cva } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"border font-medium rounded-md",
{
variants: {
variant: {
default: "text-foreground bg-primary",
},
},
}
)
function Button({ className, ...props }: React.ComponentProps<"button">) {
return (
<button className={cn(buttonVariants({ className }))} {...props} />
)
}
"
`)
})
it("handles conflicting spacing classes with tailwind-merge", async () => {
const source = `import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("cn-foo mx-4 py-2", className)} {...props} />
)
}
`
const styleMap: StyleMap = {
"cn-foo": "mx-2 py-4 flex",
}
const result = await applyTransform(source, styleMap)
// mx-2 and py-4 should be overridden by mx-4 and py-2.
expect(result).toMatchInlineSnapshot(`
"import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("flex mx-4 py-2", className)} {...props} />
)
}
"
`)
})
it("handles arbitrary values with tailwind-merge", async () => {
const source = `import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("cn-foo p-[20px]", className)} {...props} />
)
}
`
const styleMap: StyleMap = {
"cn-foo": "p-4 rounded-xl",
}
const result = await applyTransform(source, styleMap)
// p-4 should be overridden by p-[20px].
expect(result).toMatchInlineSnapshot(`
"import * as React from "react"
import { cn } from "@/lib/utils"
function Foo({ className, ...props }: { className?: string }) {
return (
<div className={cn("rounded-xl p-[20px]", className)} {...props} />
)
}
"
`)
})
it("preserves allowlisted classes in cva base string", async () => {
const source = `import * as React from "react"
import { cva } from "class-variance-authority"