diff --git a/.changeset/tame-brooms-fold.md b/.changeset/tame-brooms-fold.md new file mode 100644 index 000000000..51f20d9bf --- /dev/null +++ b/.changeset/tame-brooms-fold.md @@ -0,0 +1,5 @@ +--- +"shadcn": patch +--- + +use tw-merge to transform-style diff --git a/apps/v4/examples/base/ui-rtl/sidebar.tsx b/apps/v4/examples/base/ui-rtl/sidebar.tsx index bc5a29c2b..6d7f7b6f4 100644 --- a/apps/v4/examples/base/ui-rtl/sidebar.tsx +++ b/apps/v4/examples/base/ui-rtl/sidebar.tsx @@ -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" diff --git a/apps/v4/examples/base/ui/sidebar.tsx b/apps/v4/examples/base/ui/sidebar.tsx index ac4b8d709..6eec9b1e8 100644 --- a/apps/v4/examples/base/ui/sidebar.tsx +++ b/apps/v4/examples/base/ui/sidebar.tsx @@ -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" diff --git a/apps/v4/examples/radix/ui-rtl/sidebar.tsx b/apps/v4/examples/radix/ui-rtl/sidebar.tsx index 160453915..c53149c8e 100644 --- a/apps/v4/examples/radix/ui-rtl/sidebar.tsx +++ b/apps/v4/examples/radix/ui-rtl/sidebar.tsx @@ -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" diff --git a/apps/v4/examples/radix/ui/sidebar.tsx b/apps/v4/examples/radix/ui/sidebar.tsx index 05674d5f3..6c74aaed1 100644 --- a/apps/v4/examples/radix/ui/sidebar.tsx +++ b/apps/v4/examples/radix/ui/sidebar.tsx @@ -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" diff --git a/apps/v4/package.json b/apps/v4/package.json index d818dbc02..49fb6d881 100644 --- a/apps/v4/package.json +++ b/apps/v4/package.json @@ -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": { diff --git a/apps/v4/public/r/styles/base-lyra/command-example.json b/apps/v4/public/r/styles/base-lyra/command-example.json index 69137f688..39cb6bb29 100644 --- a/apps/v4/public/r/styles/base-lyra/command-example.json +++ b/apps/v4/public/r/styles/base-lyra/command-example.json @@ -10,7 +10,7 @@ "files": [ { "path": "registry/base-lyra/examples/command-example.tsx", - "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport {\n Example,\n ExampleWrapper,\n} from \"@/registry/base-lyra/components/example\"\nimport { Button } from \"@/registry/base-lyra/ui/button\"\nimport { Card, CardContent } from \"@/registry/base-lyra/ui/card\"\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@/registry/base-lyra/ui/command\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nexport default function CommandExample() {\n return (\n \n \n \n \n \n \n \n )\n}\n\nfunction CommandInline() {\n return (\n \n \n \n \n \n \n No results found.\n \n \n \n Calendar\n \n \n \n Search Emoji\n \n \n \n Calculator\n \n \n \n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n \n \n \n \n )\n}\n\nfunction CommandBasic() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n Calendar\n Search Emoji\n Calculator\n \n \n \n \n
\n
\n )\n}\n\nfunction CommandWithShortcuts() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n \n \n
\n
\n )\n}\n\nfunction CommandWithGroups() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n \n \n Calendar\n \n \n \n Search Emoji\n \n \n \n Calculator\n \n \n \n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n \n \n
\n
\n )\n}\n\nfunction CommandManyItems() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n \n \n Home\n ⌘H\n \n \n \n Inbox\n ⌘I\n \n \n \n Documents\n ⌘D\n \n \n \n Folders\n ⌘F\n \n \n \n \n \n \n New File\n ⌘N\n \n \n \n New Folder\n ⇧⌘N\n \n \n \n Copy\n ⌘C\n \n \n \n Cut\n ⌘X\n \n \n \n Paste\n ⌘V\n \n \n \n Delete\n \n \n \n \n \n \n \n Grid View\n \n \n \n List View\n \n \n \n Zoom In\n ⌘+\n \n \n \n Zoom Out\n ⌘-\n \n \n \n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n Notifications\n \n \n \n Help & Support\n \n \n \n \n \n \n Calculator\n \n \n \n Calendar\n \n \n \n Image Editor\n \n \n \n Code Editor\n \n \n \n \n \n
\n
\n )\n}\n", + "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport {\n Example,\n ExampleWrapper,\n} from \"@/registry/base-lyra/components/example\"\nimport { Button } from \"@/registry/base-lyra/ui/button\"\nimport { Card, CardContent } from \"@/registry/base-lyra/ui/card\"\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@/registry/base-lyra/ui/command\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nexport default function CommandExample() {\n return (\n \n \n \n \n \n \n \n )\n}\n\nfunction CommandInline() {\n return (\n \n \n \n \n \n \n No results found.\n \n \n \n Calendar\n \n \n \n Search Emoji\n \n \n \n Calculator\n \n \n \n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n \n \n \n \n )\n}\n\nfunction CommandBasic() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n Calendar\n Search Emoji\n Calculator\n \n \n \n \n
\n
\n )\n}\n\nfunction CommandWithShortcuts() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n \n \n
\n
\n )\n}\n\nfunction CommandWithGroups() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n \n \n Calendar\n \n \n \n Search Emoji\n \n \n \n Calculator\n \n \n \n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n \n \n
\n
\n )\n}\n\nfunction CommandManyItems() {\n const [open, setOpen] = React.useState(false)\n\n return (\n \n
\n setOpen(true)}\n variant=\"outline\"\n className=\"w-fit\"\n >\n Open Menu\n \n \n \n \n \n No results found.\n \n \n \n Home\n ⌘H\n \n \n \n Inbox\n ⌘I\n \n \n \n Documents\n ⌘D\n \n \n \n Folders\n ⌘F\n \n \n \n \n \n \n New File\n ⌘N\n \n \n \n New Folder\n ⇧⌘N\n \n \n \n Copy\n ⌘C\n \n \n \n Cut\n ⌘X\n \n \n \n Paste\n ⌘V\n \n \n \n Delete\n \n \n \n \n \n \n \n Grid View\n \n \n \n List View\n \n \n \n Zoom In\n ⌘+\n \n \n \n Zoom Out\n ⌘-\n \n \n \n \n \n \n Profile\n ⌘P\n \n \n \n Billing\n ⌘B\n \n \n \n Settings\n ⌘S\n \n \n \n Notifications\n \n \n \n Help & Support\n \n \n \n \n \n \n Calculator\n \n \n \n Calendar\n \n \n \n Image Editor\n \n \n \n Code Editor\n \n \n \n \n \n
\n
\n )\n}\n", "type": "registry:example" } ], diff --git a/apps/v4/public/r/styles/base-lyra/input-example.json b/apps/v4/public/r/styles/base-lyra/input-example.json index ecf33cbbb..b309e112a 100644 --- a/apps/v4/public/r/styles/base-lyra/input-example.json +++ b/apps/v4/public/r/styles/base-lyra/input-example.json @@ -13,7 +13,7 @@ "files": [ { "path": "registry/base-lyra/examples/input-example.tsx", - "content": "import {\n Example,\n ExampleWrapper,\n} from \"@/registry/base-lyra/components/example\"\nimport { Button } from \"@/registry/base-lyra/ui/button\"\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n} from \"@/registry/base-lyra/ui/field\"\nimport { Input } from \"@/registry/base-lyra/ui/input\"\nimport {\n NativeSelect,\n NativeSelectOption,\n} from \"@/registry/base-lyra/ui/native-select\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/base-lyra/ui/select\"\n\nexport default function InputExample() {\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n )\n}\n\nfunction InputBasic() {\n return (\n \n \n \n )\n}\n\nfunction InputInvalid() {\n return (\n \n \n \n )\n}\n\nfunction InputWithLabel() {\n return (\n \n \n Email\n \n \n \n )\n}\n\nfunction InputWithDescription() {\n return (\n \n \n Username\n \n \n Choose a unique username for your account.\n \n \n \n )\n}\n\nfunction InputDisabled() {\n return (\n \n \n Email\n \n \n \n )\n}\n\nfunction InputTypes() {\n return (\n \n
\n \n Password\n \n \n \n Phone\n \n \n \n URL\n \n \n \n Search\n \n \n \n Number\n \n \n \n Date\n \n \n \n Time\n \n \n \n File\n \n \n
\n
\n )\n}\n\nfunction InputWithSelect() {\n return (\n \n
\n \n \n
\n
\n )\n}\n\nfunction InputWithButton() {\n return (\n \n
\n \n \n
\n
\n )\n}\n\nfunction InputWithNativeSelect() {\n return (\n \n
\n \n \n +1\n +44\n +46\n \n
\n
\n )\n}\n\nfunction InputForm() {\n return (\n \n
\n \n \n Name\n \n \n \n Email\n \n \n We'll never share your email with anyone.\n \n \n
\n \n Phone\n \n \n \n Country\n \n \n
\n \n Address\n \n \n \n \n \n \n
\n
\n
\n )\n}\n", + "content": "import {\n Example,\n ExampleWrapper,\n} from \"@/registry/base-lyra/components/example\"\nimport { Button } from \"@/registry/base-lyra/ui/button\"\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n} from \"@/registry/base-lyra/ui/field\"\nimport { Input } from \"@/registry/base-lyra/ui/input\"\nimport {\n NativeSelect,\n NativeSelectOption,\n} from \"@/registry/base-lyra/ui/native-select\"\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/registry/base-lyra/ui/select\"\n\nexport default function InputExample() {\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n )\n}\n\nfunction InputBasic() {\n return (\n \n \n \n )\n}\n\nfunction InputInvalid() {\n return (\n \n \n \n )\n}\n\nfunction InputWithLabel() {\n return (\n \n \n Email\n \n \n \n )\n}\n\nfunction InputWithDescription() {\n return (\n \n \n Username\n \n \n Choose a unique username for your account.\n \n \n \n )\n}\n\nfunction InputDisabled() {\n return (\n \n \n Email\n \n \n \n )\n}\n\nfunction InputTypes() {\n return (\n \n
\n \n Password\n \n \n \n Phone\n \n \n \n URL\n \n \n \n Search\n \n \n \n Number\n \n \n \n Date\n \n \n \n Time\n \n \n \n File\n \n \n
\n
\n )\n}\n\nfunction InputWithSelect() {\n return (\n \n
\n \n \n
\n
\n )\n}\n\nfunction InputWithButton() {\n return (\n \n
\n \n \n
\n
\n )\n}\n\nfunction InputWithNativeSelect() {\n return (\n \n
\n \n \n +1\n +44\n +46\n \n
\n
\n )\n}\n\nfunction InputForm() {\n return (\n \n
\n \n \n Name\n \n \n \n Email\n \n \n We'll never share your email with anyone.\n \n \n
\n \n Phone\n \n \n \n Country\n \n \n
\n \n Address\n \n \n \n \n \n \n
\n
\n
\n )\n}\n", "type": "registry:example" } ], diff --git a/apps/v4/public/r/styles/base-lyra/sidebar.json b/apps/v4/public/r/styles/base-lyra/sidebar.json index 410c112a3..f96f53352 100644 --- a/apps/v4/public/r/styles/base-lyra/sidebar.json +++ b/apps/v4/public/r/styles/base-lyra/sidebar.json @@ -12,7 +12,7 @@ "files": [ { "path": "registry/base-lyra/ui/sidebar.tsx", - "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-lyra/lib/utils\"\nimport { Button } from \"@/registry/base-lyra/ui/button\"\nimport { Input } from \"@/registry/base-lyra/ui/input\"\nimport { Separator } from \"@/registry/base-lyra/ui/separator\"\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from \"@/registry/base-lyra/ui/sheet\"\nimport { Skeleton } from \"@/registry/base-lyra/ui/skeleton\"\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/registry/base-lyra/ui/tooltip\"\nimport { useIsMobile } from \"@/registry/new-york-v4/hooks/use-mobile\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nconst SIDEBAR_COOKIE_NAME = \"sidebar_state\"\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\nconst SIDEBAR_WIDTH = \"16rem\"\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\"\nconst SIDEBAR_WIDTH_ICON = \"3rem\"\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\"\n\ntype SidebarContextProps = {\n state: \"expanded\" | \"collapsed\"\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n}\n\nconst SidebarContext = React.createContext(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\")\n }\n\n return context\n}\n\nfunction SidebarProvider({\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n}) {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open]\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault()\n toggleSidebar()\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown)\n return () => window.removeEventListener(\"keydown\", handleKeyDown)\n }, [toggleSidebar])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\"\n\n const contextValue = React.useMemo(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]\n )\n\n return (\n \n \n {children}\n \n \n )\n}\n\nfunction Sidebar({\n side = \"left\",\n variant = \"sidebar\",\n collapsible = \"offcanvas\",\n className,\n children,\n dir,\n ...props\n}: React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\"\n variant?: \"sidebar\" | \"floating\" | \"inset\"\n collapsible?: \"offcanvas\" | \"icon\" | \"none\"\n}) {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n\n if (collapsible === \"none\") {\n return (\n \n {children}\n \n )\n }\n\n if (isMobile) {\n return (\n \n button]:hidden\"\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n \n Sidebar\n Displays the mobile sidebar.\n \n
{children}
\n \n
\n )\n }\n\n return (\n