- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- Menubar
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
- Typography
2023 年 6 月 - 新 CLI、样式等更新
完整重写的 CLI,带来新样式、主题选项等功能。
今天我有很多更新要和你分享:
- 新 CLI - 从零重写 CLI。现在可以添加组件、依赖并配置导入路径。
- 主题 - 在使用 CSS 变量或 Tailwind CSS 工具类之间选择主题方案。
- 基础色 - 为项目配置基础色。它会用于生成组件的默认调色板。
- React Server Components - 可选择不使用 React Server Components。CLI 会自动添加或移除
use client指令。 - 样式 - 引入一个名为 Style 的新概念。样式会自带一套组件、动画、图标等内容。
- 退出动画 - 为所有组件添加了退出动画。
- 其他更新 - 新的
icon按钮尺寸、更新后的sheet组件等。 - 更新你的项目 - 如何更新项目以获取最新变更。
新 CLI
过去几周我一直在开发一个新的 CLI。它是一次彻底重写,带来了很多新功能和改进。
init
pnpm dlx shadcn@latest init
运行 init 命令时,系统会询问你一些问题来配置 components.json:
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › app/globals.css
Do you want to use CSS variables for colors? › no / yes
Where is your tailwind.config.js located? › tailwind.config.js
Configure the import alias for components: › @/components
Configure the import alias for utils: › @/lib/utils
Are you using React Server Components? › no / yes这个文件包含了组件的所有信息:安装位置、导入路径、样式方式等等。
你可以用这个文件来修改组件的导入路径、设置基础色,或者更改样式方法。
{
"style": "default",
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "zinc",
"cssVariables": true
},
"rsc": false,
"aliases": {
"utils": "~/lib/utils",
"components": "~/components"
}
}这意味着你现在可以在任何目录结构中使用 CLI,包括 src 和 app 目录。
add
pnpm dlx shadcn@latest add
add 命令现在更强大了。你现在不仅可以添加 UI 组件,还可以导入更复杂的组件(即将推出)。
CLI 会自动解析所有组件和依赖,依据你的自定义配置进行格式化,并把它们添加到项目中。
diff(实验性)
pnpm dlx shadcn diff
我们还引入了新的 diff 命令,帮助你跟踪上游更新。
你可以使用这个命令查看上游仓库发生了什么变化,并据此更新你的项目。
Run the diff command to get a list of components that have updates available:
pnpm dlx shadcn diff
以下组件有可用更新:
- button
- /path/to/my-app/components/ui/button.tsx
- toast
- /path/to/my-app/components/ui/use-toast.ts
- /path/to/my-app/components/ui/toaster.tsx然后运行 diff [component] 查看具体变更:
pnpm dlx shadcn diff alert
const alertVariants = cva(
- "relative w-full rounded-lg border",
+ "relative w-full pl-12 rounded-lg border"
)使用 CSS 变量或 Tailwind 颜色进行主题化
你可以在使用 CSS 变量或 Tailwind CSS 工具类之间选择主题方案。
当你添加新组件时,CLI 会根据你的 components.json 配置自动使用正确的主题方式。
Utility classes
<div className="bg-zinc-950 dark:bg-white" />如果要使用工具类进行主题化,请在 components.json 文件中把 tailwind.cssVariables 设为 false。
{
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": false
}
}CSS Variables
<div className="bg-background text-foreground" />如果要使用 CSS 变量进行主题化,请在 components.json 文件中把 tailwind.cssVariables 设为 true。
{
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true
}
}基础色
你现在可以为项目配置基础色。它会用于生成组件的默认调色板。
{
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "zinc",
"cssVariables": false
}
}可在 gray、neutral、slate、stone 或 zinc 之间选择。
如果你把 cssVariables 设为 true,我们会在你的 globals.css 文件中把基础颜色设置为 CSS 变量。如果你把 cssVariables 设为 false,我们就会把 Tailwind CSS 工具类直接内联到组件中。
React Server Components
如果你使用的框架不支持 React Server Components,现在可以通过把 rsc 设为 false 来退出。添加组件时,我们会自动添加或移除 use client 指令。
{
"rsc": false
}样式
我们正在引入一个名为 Style 的新概念。
你可以把 style 理解为视觉基础:形状、图标、动画和排版。 一种 style 会自带自己的组件、动画、图标等内容。
我们提供两种样式:default 和 new-york(后续还会有更多)。
default 样式就是你熟悉的那个样式。从项目开始我们一直在使用它。它使用 lucide-react 作为图标,并使用 tailwindcss-animate 作为动画。
new-york 是一种新样式。它包含更小的按钮、带阴影的卡片,以及来自 Radix Icons 的一套新图标。
运行 init 命令时,系统会询问你想使用哪种样式。这个选择会保存到你的 components.json 文件中。
{
"style": "new-york"
}主题化
先以某种样式作为基础,然后通过 CSS 变量或 Tailwind CSS 工具类进行主题化,就可以完全改变组件的外观。
退出动画
我为所有组件都添加了退出动画。点击下面的 combobox 可以看到细微的退出动画。
"use client"
import * as React from "react"这些动画可以通过工具类自定义。
其他更新
Button
- 新增了一个
icon按钮尺寸:
import { CircleFadingArrowUpIcon } from "lucide-react"
import { Button } from "@/components/ui/button"Sheet
- 将
position重命名为side,以与其他元素保持一致。
"use client"
import { Button } from "@/components/ui/button"- 移除了
size属性。请使用className="w-[200px] md:w-[450px]"来实现响应式尺寸。
更新你的项目
由于我们采用复制粘贴的方式,你需要手动更新项目才能获得最新变更。
注意:我们正在开发一个 diff 命令,帮助你跟踪上游更新。
添加 components.json
在根目录创建一个 components.json 文件:
{
"style": "default",
"rsc": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}请更新 tailwind.css 和 aliases 的值,以匹配你的项目结构。
Button
在 buttonVariants 中添加 icon 尺寸:
const buttonVariants = cva({
variants: {
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
})Sheet
- 将
sheet.tsx的内容替换为以下内容:
"use client"
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"
import { cn } from "@/lib/utils"
const Sheet = SheetPrimitive.Root
const SheetTrigger = SheetPrimitive.Trigger
const SheetClose = SheetPrimitive.Close
const SheetPortal = ({
className,
...props
}: SheetPrimitive.DialogPortalProps) => (
<SheetPrimitive.Portal className={cn(className)} {...props} />
)
SheetPortal.displayName = SheetPrimitive.Portal.displayName
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
))
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
)
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-none disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
))
SheetContent.displayName = SheetPrimitive.Content.displayName
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
SheetHeader.displayName = "SheetHeader"
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
SheetFooter.displayName = "SheetFooter"
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
))
SheetTitle.displayName = SheetPrimitive.Title.displayName
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
SheetDescription.displayName = SheetPrimitive.Description.displayName
export {
Sheet,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
}- Rename
positiontoside
- <Sheet position="right" />
+ <Sheet side="right" />感谢
我要感谢一直在使用这个项目、提供反馈并参与贡献的每一个人。我非常感激。谢谢你们。