22
33本指南专为 AI 模型设计,旨在提供标准化的代码模板和明确的步骤,以生成符合 SoybeanUI 架构规范的高质量组件代码。
44
5- ## 核心架构原则
5+ ## 1. 项目架构概览
66
7- 1 . ** Headless (逻辑层)** : 位于 ` headless/ ` 。负责状态、交互、A11y。** 严禁包含 CSS/样式** 。
8- 2 . ** UI (表现层)** : 位于 ` src/ ` 。负责视觉样式、主题变体。使用 ` tailwind-variants ` 。
9- 3 . ** 单向依赖** : UI 层依赖 Headless 层,Headless 层** 不** 依赖 UI 层。
7+ SoybeanUI 采用 ** Headless UI (逻辑层)** 与 ** Styled UI (表现层)** 分离的架构模式。
8+
9+ ### 1.1 核心分层
10+
11+ - ** Headless 层 (` headless/ ` )** :
12+ - ** 职责** : 负责组件的状态管理、交互逻辑、无障碍访问 (A11y) 和 DOM 结构。
13+ - ** 原则** : ** 严禁包含任何 CSS 样式** 。只关注功能,不关注长相。
14+ - ** 技术** : Vue 3 (Composition API), TypeScript.
15+ - ** UI 层 (` src/ ` )** :
16+ - ** 职责** : 负责组件的视觉样式、主题变体、动画效果。
17+ - ** 原则** : 依赖 Headless 层提供的逻辑组件,通过 ` tailwind-variants ` 注入样式。
18+ - ** 技术** : Vue 3, Tailwind CSS (UnoCSS), Tailwind Variants.
19+
20+ ### 1.2 依赖关系
21+
22+ ` UI 层 ` -> ` Headless 层 ` (单向依赖)
23+
24+ ---
25+
26+ ## 2. 目录结构详解
27+
28+ ```
29+ soybean-ui/
30+ ├── headless/ # [逻辑层] Headless 组件库 workspace
31+ │ └── src/
32+ │ ├── components/ # Headless 组件源码
33+ │ │ └── {component}/ # 单个组件目录
34+ │ │ ├── {component}-root.vue # 根组件
35+ │ │ ├── {component}-item.vue # 子组件
36+ │ │ ├── context.ts # 依赖注入上下文
37+ │ │ ├── types.ts # 类型定义
38+ │ │ └── index.ts # 导出文件
39+ │ ├── composables/ # 共享组合式函数 (useContext, useId 等)
40+ │ └── primitive/ # 基础图元组件
41+ ├── src/ # [表现层] UI 组件库 workspace
42+ │ ├── components/ # UI 组件源码
43+ │ │ └── {component}/ # 单个组件目录
44+ │ │ ├── {component}.vue # UI 组件实现
45+ │ │ ├── types.ts # UI 组件类型定义
46+ │ │ ├── context.ts # (可选) UI 层上下文
47+ │ │ └── index.ts # 导出文件
48+ │ ├── variants/ # [关键] 样式变体定义
49+ │ │ └── {component}.ts # 使用 tailwind-variants 定义样式
50+ │ └── theme/ # 主题配置与工具函数
51+ ├── package.json # 项目根配置
52+ └── uno.config.ts # UnoCSS 配置
53+ ```
54+
55+ ---
56+
57+ ## 3. 开发流程与代码规范
58+
59+ 开发一个新组件通常分为两个阶段:首先实现 Headless 逻辑,然后实现 UI 样式。
1060
1161---
1262
13- ## 第一阶段:Headless 层开发 (` headless/src/components/{component}/ ` )
63+ ### 第一阶段:Headless 层开发 (` headless/src/components/{component}/ ` )
1464
15- ### 1. 定义类型 (` types.ts ` )
65+ #### 1. 定义类型 (` types.ts ` )
1666
1767** 目标** : 定义组件的 Props, Emits, Context 参数以及样式槽 (Theme Slots)。
1868
@@ -66,7 +116,7 @@ export interface {ComponentName}ThemeContextParams {
66116}
67117```
68118
69- ### 2. 定义上下文 (` context.ts ` )
119+ #### 2. 定义上下文 (` context.ts ` )
70120
71121** 目标** : 创建类型安全的 Provide/Inject 对。
72122
@@ -94,7 +144,7 @@ export const [provide{ComponentName}ThemeContext, use{ComponentName}ThemeContext
94144);
95145```
96146
97- ### 3. 实现 Root 组件 (` {component}-root.vue ` )
147+ #### 3: 实现组件 (` {component}-root.vue ` , ` {component}-item .vue` )
98148
99149** 目标** : 初始化状态,提供 Context,渲染根元素。
100150
@@ -105,6 +155,8 @@ export const [provide{ComponentName}ThemeContext, use{ComponentName}ThemeContext
105155- 使用 ` use{ComponentName}ThemeContext ` 获取样式并应用 ` ui.root ` 。
106156- 使用 ` transformPropsToContext ` 传递 Props。
107157
158+ ** Root 组件示例** :
159+
108160``` vue
109161<script setup lang="ts">
110162import { computed, shallowRef } from 'vue';
@@ -143,7 +195,7 @@ provide{ComponentName}RootContext({
143195</template>
144196```
145197
146- ### 4. 实现子组件 (如 ` {component}-item.vue ` )
198+ ** Item 组件示例 ** :
147199
148200** 目标** : 消费 Context,渲染子元素。
149201
@@ -170,7 +222,7 @@ const cls = computed(() => themeContext?.ui?.value?.item);
170222</template>
171223```
172224
173- ### 5. 导出 Headless 组件 (` index.ts ` )
225+ #### 5. 导出 Headless 组件 (` index.ts ` )
174226
175227``` typescript
176228export { default as {ComponentName }Root } from ' ./{component}-root.vue' ;
@@ -186,9 +238,9 @@ export * from './types';
186238
187239---
188240
189- ## 第二阶段:UI 层开发 (` src/components/{component}/ ` )
241+ ### 第二阶段:UI 层开发 (` src/components/{component}/ ` )
190242
191- ### 1. 定义样式变体 (` src/variants/{component}.ts ` )
243+ #### 1. 定义样式变体 (` src/variants/{component}.ts ` )
192244
193245** 目标** : 使用 Tailwind CSS 定义组件样式。
194246
@@ -217,7 +269,7 @@ export const {componentName}Variants = tv({
217269});
218270```
219271
220- ### 2. 定义 UI 类型 (` src/components/{component}/types.ts ` )
272+ #### 2. 定义 UI 类型 (` src/components/{component}/types.ts ` )
221273
222274** 目标** : 扩展 Headless Props,添加 UI 属性。
223275
@@ -241,7 +293,7 @@ export type {ComponentName}Props = {ComponentName}RootProps & {
241293export type {ComponentName }Emits = {ComponentName }RootEmits ;
242294```
243295
244- ### 3. 实现 UI 组件 (` src/components/{component}/{component}.vue ` )
296+ #### 3. 实现 UI 组件 (` src/components/{component}/{component}.vue ` )
245297
246298** 目标** : 组合 Headless 组件,注入样式 Context。
247299
@@ -298,7 +350,7 @@ provide{ComponentName}ThemeContext({ ui });
298350</template>
299351```
300352
301- ### 4. 导出 UI 组件 (` index.ts ` )
353+ #### 4. 导出 UI 组件 (` index.ts ` )
302354
303355``` typescript
304356export { default as S {ComponentName } } from ' ./{component}.vue' ;
@@ -314,18 +366,24 @@ export * from './types';
314366| 函数名 | 用途 |
315367| :--------------------- | :---------------------------------------- |
316368| ` useContext ` | 创建 Provide/Inject 对。 |
317- | ` useId ` | 生成唯一 ID。 |
318369| ` useForwardElement ` | 在组件间传递 DOM 元素引用。 |
319370| ` useForwardListeners ` | 转发事件监听器。 |
320371| ` useOmitProps ` | 剔除 Props 中的特定属性,返回响应式对象。 |
321372| ` useSelection ` | 处理 v-model 选择逻辑 (单选/多选)。 |
322373| ` useControllableState ` | 处理受控/非受控状态。 |
323374
324- ## 检查清单
325-
326- 1 . [ ] ** Headless** : ` types.ts ` 定义了 ` ThemeSlot ` 和 ` Ui ` 类型?
327- 2 . [ ] ** Headless** : ` context.ts ` 导出了 ` ThemeContext ` ?
328- 3 . [ ] ** Headless** : 组件内部使用了 ` use{ComponentName}ThemeContext ` 获取样式?
329- 4 . [ ] ** UI** : ` variants ` 定义了所有 ` ThemeSlot ` ?
330- 5 . [ ] ** UI** : 组件使用了 ` useOmitProps ` 过滤 UI 属性?
331- 6 . [ ] ** UI** : 组件提供了 ` ThemeContext ` ?
375+ ## 关键注意事项
376+
377+ 1 . ** Headless** : ` types.ts ` 定义了 ` ThemeSlot ` 和 ` Ui ` 类型?
378+ 2 . ** Headless** : ` context.ts ` 导出了 ` ThemeContext ` ?
379+ 3 . ** Props 透传** : 使用 ` useOmitProps ` 确保 UI 特有的 Props (如 ` size ` , ` variant ` ) 不会被透传到 DOM 节点上导致 HTML 属性污染。
380+ 4 . ** 事件转发** : 使用 ` useForwardListeners ` 确保组件上的事件监听器能正确绑定到 Headless 组件内部的元素上。
381+ 5 . ** Slot 一致性** : ` headless/**/types.ts ` 中的 ` ThemeSlot ` 定义必须与 ` src/variants/**.ts ` 中的 ` slots ` 键名完全一致。
382+ 6 . ** Headless** : 组件内部使用了 ` use{ComponentName}ThemeContext ` 获取样式?
383+ 7 . ** UI** : ` variants ` 定义了所有 ` ThemeSlot ` ?
384+ 8 . ** UI** : 组件使用了 ` useOmitProps ` 过滤 UI 属性?
385+ 9 . ** UI** : 组件提供了 ` ThemeContext ` ?
386+ 10 . ** 命名规范** :
387+ - Headless 组件: ` {ComponentName}Root ` , ` {ComponentName}Item `
388+ - UI 组件: ` S{ComponentName} ` (S 前缀)
389+ - Context: ` provide{ComponentName}Context ` , ` use{ComponentName}Context `
0 commit comments