贡献

了解如何为 shadcn/vue 贡献代码。

简介

感谢您对 shadcn-vue.com 的贡献。我们很高兴您能来这里。

在提交您的第一个拉取请求之前,请花点时间查看这份文档。我们强烈建议您检查开放的问题和拉取请求,看看是否有其他人正在做类似的事情。

如果您需要任何帮助,请随时在 Discord 上联系核心团队。

本指南提供了详细的信息,帮助新贡献者。

关于这个仓库

这个仓库是一个单仓库。

项目结构

GitHub 仓库由几个文件夹组成。这里有一个快速视图。

  1. packages - 包含支持 nuxt 作为模块和 cli 添加新组件的源代码。

  2. apps/www - 主文件夹,包含网站和所有 shadcn/vue 组件的源代码。此文件夹包含重要的子文件夹,并且是一个带有自己的 package.json 的子项目。

  3. .vitepress - 包含 vitepressshadcn/vue 网站的配置和源代码。

  4. src - 托管所有 shadcn/vue 组件或演示以及它们在网站上的文档的源代码。

  5. __registry__ - 保存由 scripts/build-registry.ts 生成的注册文件,以用于为 cli 提供组件。此文件夹的内容是自动生成的,不应手动编辑。

  6. scripts - 包含各种辅助脚本,如 build-registry.ts,它会自动生成 __registry__ 文件夹。

  7. content - 此文件夹包含 /docs 路由的所有文档。每个组件都有一个 .md 文件,记录组件的安装和使用。

  8. examples - 包含所有不在 /docs 中的示例,例如 主页

  9. lib/registry - 主文件夹包含每个组件不同样式的源代码。这可能是您要更改的主要文件夹。

我们支持 shadcn/vue 中每个组件的两种不同样式

  1. 默认
  2. 纽约

添加到仓库的每个组件都必须支持这两个版本,包括主要源代码和相关的演示。

添加或修改组件时,请确保

  1. 您对每种样式都进行了更改。
  2. 您更新了文档。
  3. 您运行了 pnpm build:registry 以更新注册表。

开发

首先克隆仓库

bash
git clone [email protected]:radix-vue/shadcn-vue.git

安装依赖项

bash
pnpm install

运行工作区

您可以使用 pnpm --filter=[WORKSPACE] 命令来启动工作区或我们设置的一些快捷命令的开发过程。

示例

  1. 要运行 shadcn-vue.com 网站
pnpm dev
  1. 要运行 shadcn-vue cli 包
pnpm dev:cli

文档

此项目的文档位于 www 工作区中。您可以通过运行以下命令在本地运行文档

bash
pnpm dev

文档使用 md 编写。您可以在 apps/www/src/content 目录中找到文档文件。

CLI

shadcn-vue 包是一个用于将组件添加到项目的 CLI。您可以在 此处 找到 CLI 的文档。

对 CLI 的任何更改都应在 packages/cli 目录中进行。如果您能做到,最好为您的更改添加测试。

测试

测试使用 Vitest 编写。您可以从仓库根目录运行所有测试。

bash
pnpm test

提交拉取请求时,请确保测试通过。如果您添加了新功能,请包含测试。

提交约定

在创建拉取请求之前,请检查您的提交是否符合此仓库中使用的提交约定。

创建提交时,我们恳请您在提交消息中遵循约定 category(scope or module): message,同时使用以下类别之一

  • feat / feature:所有引入全新代码或新功能的更改

  • fix:修复错误的更改(理想情况下,您还会参考现有的问题)

  • refactor:任何与代码相关的更改,既不是修复也不是功能

  • docs:更改现有文档或创建新文档(例如 README、库使用文档或 cli 使用文档)

  • build:所有与软件构建相关的更改,依赖项更改或添加新依赖项

  • test:所有与测试相关的更改(添加新测试或更改现有测试)

  • ci:所有与持续集成配置相关的更改(例如 github actions、ci 系统)

  • chore:所有不属于上述任何类别的仓库更改

    例如 feat(components): add new prop to the avatar component

如果您有兴趣了解详细规范,您可以访问 Conventional Commits

SFC - 单文件组件

多个组件集成到 shadcn/uishadcn 的 React 版本)中的一个文件中,而 Vue 每个文件只支持一个组件,因此称为单文件组件 (SFC)。在这种情况下,您需要为每个组件部分创建单独的文件,然后在 index.ts 文件中导出它们。

Accordion 源代码为例。

包装 Radix-Vue 组件

Radix-Vue 托管许多用于构建可重用组件的低级 UI 组件。在许多情况下,您需要包装 Radix-Vue 组件。

属性和事件

所有 Radix-Vue 组件都公开其属性和发射类型。我们需要转发来自外部的任何属性/事件到 Radix-Vue 组件。

为此,我们有一个名为 useForwardPropsEmits 的辅助函数,它组合必须绑定到子 radix 组件的属性和事件。

更明确地说,函数 useForwardPropsEmits 接收属性和可选的发射函数,并返回一个计算对象,该对象将解析后的属性和发射组合为属性。

以下是 Accordion 根组件的示例。

vue
<script setup lang="ts">
import {
  AccordionRoot,
  type AccordionRootEmits,
  type AccordionRootProps,
  useForwardPropsEmits,
} from 'radix-vue'

const props = defineProps<AccordionRootProps>()
const emits = defineEmits<AccordionRootEmits>()

const forwarded = useForwardPropsEmits(props, emits)
</script>

<template>
  <AccordionRoot v-bind="forwarded">
    <slot />
  </AccordionRoot>
</template>

如您所见,AccordionRootEmitsAccordionRootProps 类型从 radix 导入,与 useForwardPropsEmits 组合,然后使用 v-bind 语法绑定。

CSS 类

在某些情况下,我们希望在 shadcn/vue 组件中接受 class 作为属性,然后通过 cn 实用程序函数将其与 radix-vue 组件上的默认 tailwind 类组合起来。

在这种情况下,我们不能使用 v-bind,因为这会导致 双重类绑定

看一下 DrawerDescription.vue

vue
<script lang="ts" setup>
import type { DrawerDescriptionProps } from 'vaul-vue'
import { DrawerDescription } from 'vaul-vue'
import { type HtmlHTMLAttributes, computed } from 'vue'
import { cn } from '@/lib/utils'

const props = defineProps<DrawerDescriptionProps & { class?: HtmlHTMLAttributes['class'] }>()

const delegatedProps = computed(() => {
  const { class: _, ...delegated } = props

  return delegated
})
</script>

<template>
  <DrawerDescription v-bind="delegatedProps" :class="cn('text-sm text-muted-foreground', props.class)">
    <slot />
  </DrawerDescription>
</template>

如您所见,我们创建了一个名为 delegatedProps 的计算属性,从属性中删除 class,然后将返回值绑定到我们的 radix 组件(在本例中为 DrawerDescription)。

至于我们的类,我们首先将其声明为 HtmlHTMLAttributes['class'] 类型,并使用 cn 合并来自 class 属性的 tailwind 类和我们自己的类。

此模式仅在需要 cn 实用程序时才需要应用。在不需要将默认的 Tailwind 类与用户提供的类合并的情况下,此模式是不必要的。SelectValue.vue 组件就是一个很好的例子。

vue
<script setup lang="ts">
import { SelectValue, type SelectValueProps } from 'radix-vue'

const props = defineProps<SelectValueProps>()
</script>

<template>
  <SelectValue v-bind="props">
    <slot />
  </SelectValue>
</template>

布尔属性

当您为组件构建包装器时,在某些情况下您可能希望忽略 Vue Props 布尔值转换。您可以将所有布尔字段的默认值设置为 undefined,或者使用 useForwardProps 可组合函数。

查看 AccordionItem.vue

vue
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { AccordionItem, type AccordionItemProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'

const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()

const delegatedProps = computed(() => {
  const { class: _, ...delegated } = props

  return delegated
})

const forwardedProps = useForwardProps(delegatedProps)
</script>

<template>
  <AccordionItem
    v-bind="forwardedProps"
    :class="cn('border-b', props.class)"
  >
    <slot />
  </AccordionItem>
</template>

由于 AccordionItemProps 类型至少有一个布尔属性,因此我们需要在整个 props 对象上使用 useForwardProps

请注意,useForwardPropsEmits 在幕后使用了 useForwardProps

组件作为根节点

当您的根组件是来自 vue 的 Component 原生组件时,使用 Primitive 会更方便。

让我们看一下 Button.vue

vue
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { Primitive, type PrimitiveProps } from 'radix-vue'
import { type ButtonVariants, buttonVariants } from '.'
import { cn } from '@/lib/utils'

interface Props extends PrimitiveProps {
  variant?: ButtonVariants['variant']
  size?: ButtonVariants['size']
  class?: HTMLAttributes['class']
}

const props = withDefaults(defineProps<Props>(), {
  as: 'button',
})
</script>

<template>
  <Primitive
    :as="as"
    :as-child="asChild"
    :class="cn(buttonVariants({ variant, size }), props.class)"
  >
    <slot />
  </Primitive>
</template>

您需要在您的 props 中扩展 PrimitiveProps 以支持 Primitive 组件。在大多数情况下,您还需要为 as 属性设置默认值。

使用 shadcn/ui 更新

shadcn/vueshadcn/ui 的非官方社区主导的 Vue 端口,随着时间的推移,它们可能会失去同步。

截至今天,我们与 shadcn/ui 的这个 提交 保持同步。

点击以下链接检查是否有我们应该同步的较新提交。

  1. 没有变化 - 如果您看到“没有要比较的内容”,则无需执行任何操作,因为我们已与最新版本同步。
  2. 如果有变化,您应该查看这些变化并尝试将它们应用到 shadcn/vue 代码库中,并创建一个 PR,请记住在 此文件 中更新 latestSyncCommitTag

调试

以下是一些工具和技术,可以帮助您在为 shadcn/vue 做贡献或开发自己的项目时更有效地进行调试。

安装 Vue Dev Tools

为了轻松检查组件 props、属性、事件等等,您可以利用浏览器上的 Vue DevTools 扩展。此扩展为调试 Vue 组件提供了一个用户友好的界面,可以改善您的开发体验。

启用自定义格式化程序

Vue 以一种方式包装存储在 ref 中的值,当记录时,会导致嵌套对象,并且需要手动检查才能访问存储在 ref 中的值。

您可以在浏览器中启用自定义格式化程序来自动执行此过程。

在 GitHub 上编辑此页面