# Nova 设计规范 > AI-Native 组件库:专为大模型代码生成优化的 AntV 类可视化 + UI 组件库。 > 核心目标:**让 AI 第一次生成的代码就能跑、就能看、就能用。** --- ## 一、核心理念 ### 1.1 AI 优先 (AI-First) 传统组件库(antd)面向人类开发者编写,Nova 面向 AI 编写。这意味着: | 原则 | 说明 | 反例 (antd 风格) | 正例 (Nova 风格) | |------|------|-------------------|------------------| | **零歧义** | 每个 prop 名称自解释,无简称、无隐式行为 | `allowClear` | `showClear` | | **零默认假设** | 所有视觉行为显式声明,不靠"常识" | `status` 默认 `undefined` 表示正常 | `status: 'default' \| 'error' \| 'warning' \| 'success'` | | **一致性** | 相同概念用相同 prop 名,跨组件统一 | Table `dataSource` / Select `options` | 统一 `data` | | **扁平化** | 最多一层嵌套,禁止深层 renderProps | `columns[].render()` | `column.renderCell` 函数 prop | | **确定性** | 相同输入始终产生相同输出,无随机行为 | 部分组件默认不带 `key` 警告 | 所有组件强制 `key` 或无状态 | ### 1.2 可视化 + UI 一体化 Nova 融合 AntV 的数据可视化能力与 antd 的 UI 能力,两者共享同一套设计 Token、交互模式、主题系统。 --- ## 二、AI 最友好的 API 设计规则 ### 规则 1: 统一数据模型 所有列表/表格/图表组件遵循同一数据接口: ```tsx // ✅ Nova 方式 — 所有数据组件统一 // ❌ antd 方式 — 不同名称增加 AI 混淆
// dataSource
// ❌ 魔法字符串 // "error" 还是 "Error"?还有哪些值? ``` ### 规则 8: 组件原子化 一个组件只做一件事,不做"大而全"的上帝组件: ```tsx // ✅ 拆分
// 纯表格 // 表格筛选 // 表格排序 // ❌ 不拆分
// 30+ props 的巨无霸 ``` --- ## 三、结合 AntV 的可视化组件规范 ### 3.1 图表组件统一接口 所有图表组件共享以下 props 契约: ```tsx interface ChartBaseProps { data: T[] // 统一数据源 xField: keyof T // X 轴字段名 yField: keyof T // Y 轴字段名 seriesField?: keyof T // 分组/系列字段 color?: string | string[] | ((d: T) => string) size?: number | ((d: T) => number) tooltip?: boolean | TooltipConfig legend?: boolean | LegendConfig animation?: boolean | AnimationConfig } ``` ### 3.2 支持的图表类型 ```tsx // 基础图表 // 组合图表 // 统计图表 // 地图 ``` ### 3.3 可视化交互 ```tsx // 所有图表支持标准交互 interface ChartInteraction { tooltip: boolean | { shared?: boolean; crosshairs?: boolean } zoom: boolean | { type: 'x' | 'y' | 'both' } brush: boolean | { type: 'rect' | 'polygon' } slider: boolean | { start?: number; end?: number } legendFilter: boolean } ``` ### 3.4 Stat 组件(数值 + 迷你图) ```tsx // AI 生成看板时最常用的组件 } /> ``` --- ## 四、可落地的 Token 体系 所有值用 TypeScript 常量 + CSS 自定义属性双重暴露: ```ts // theme/tokens.ts export const tokens = { color: { primary: '#6C5CE7', primaryHover: '#A29BFE', primaryActive: '#4A3DBF', success: '#00B894', warning: '#FDCB6E', error: '#FF7675', info: '#74B9FF', text: '#1a1a2e', bg: '#ffffff', bgElevated: '#f8f9fa', border: '#e2e8f0', }, radius: { xs: '4px', sm: '8px', md: '12px', lg: '16px', xl: '24px', round: '9999px', }, space: { xs: '4px', sm: '8px', md: '12px', lg: '16px', xl: '24px', '2xl': '32px', '3xl': '48px', }, font: { family: '"Inter", "SF Pro Display", -apple-system, sans-serif', familyMono: '"JetBrains Mono", "SF Mono", monospace', size: { xs: 12, sm: 14, md: 16, lg: 20, xl: 24 }, weight: { regular: 400, medium: 500, semibold: 600, bold: 700 }, }, shadow: { sm: '0 1px 3px rgba(0,0,0,0.08)', md: '0 4px 12px rgba(0,0,0,0.1)', lg: '0 8px 30px rgba(0,0,0,0.12)', xl: '0 20px 60px rgba(0,0,0,0.15)', }, motion: { fast: '100ms', normal: '200ms', slow: '350ms', easeOut: 'cubic-bezier(0.23, 1, 0.32, 1)', easeInOut: 'cubic-bezier(0.65, 0, 0.35, 1)', spring: 'cubic-bezier(0.34, 1.56, 0.64, 1)', }, } as const ``` CSS 变量注入: ```css :root { --nv-color-primary: #6C5CE7; --nv-radius-sm: 8px; --nv-space-md: 12px; /* ... 每个 token 对应一个 --nv-* 变量 */ } ``` --- ## 五、组件文件脚手架(AI 生成模板) 每个新组件创建时,AI 按此模板生成: ```tsx // Button.tsx — AI 生成的模板示例 import React from 'react' export interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> { variant?: 'solid' | 'outline' | 'ghost' | 'glass' size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' status?: 'default' | 'success' | 'warning' | 'error' loading?: boolean icon?: React.ReactNode iconPosition?: 'left' | 'right' fullWidth?: boolean } export const Button = React.forwardRef( ({ variant = 'solid', size = 'md', status = 'default', loading = false, icon, iconPosition = 'left', fullWidth = false, children, ...rest }, ref) => { return ( ) } ) Button.displayName = 'Button' ``` ### 每个组件必须包含: ``` Button/ ├── index.ts # export { Button } from './Button' ├── Button.tsx # 组件实现 + Props 类型导出 ├── Button.style.ts # 样式(vanilla-extract / CSS modules) ├── Button.test.tsx # 测试(至少 3 个用例:渲染、交互、边界) └── Button.stories.tsx # Storybook stories(至少展示所有 variant + size 组合) ``` --- ## 六、AI 友好的代码约束 ### 6.1 Props 声明规范 ```tsx // ✅ 正确做法 interface ButtonProps { /** 按钮风格变体 */ variant?: 'solid' | 'outline' | 'ghost' | 'glass' /** 按钮尺寸 */ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' } // ❌ 禁止做法 interface BadProps { type?: string // string 类型 — AI 不知道可选值 mode?: any // any 类型 — 无类型提示 [key: string]: any // 透传导致 AI 无法推理 } ``` ### 6.2 状态映射(禁止 switch-case 硬编码) ```tsx // ✅ 用对象映射,AI 容易理解 const STATUS_MAP = { default: { bg: '#f5f5f5', color: '#333' }, success: { bg: '#f0fff4', color: '#00b894' }, warning: { bg: '#fffbeb', color: '#fdcb6e' }, error: { bg: '#fff5f5', color: '#ff7675' }, } as const // ❌ switch-case 层层嵌套 switch (status) { case 'success': return { bg: '#f0fff4', color: '#00b894' } // ... } ``` ### 6.3 条件渲染 ```tsx // ✅ 提前 return / 三元表达式 if (!data.length) return return
{data.map(render)}
// ❌ 复杂 && 链 {!!data && data.length > 0 && data.map(item => item.active && )} ``` ### 6.4 样式绑定 ```tsx // ✅ data-* 属性 + CSS 属性选择器(AI 删改时不易出错)