Files

902 lines
20 KiB
Markdown
Raw Permalink Normal View History

2026-05-31 09:36:23 +08:00
# Pika 其他组件开发计划与规范
> 基于 Pika 设计规范,参照 Ant Design 剩余组件体系,构建专为 AI 代码生成优化的其他组件库。
---
## 一、组件总览
Pika 其他组件分为以下几类:
| 类别 | 组件 | antd 对标 | 优先级 |
|------|------|-----------|--------|
| **通用组件** | Affix, Anchor, App, ConfigProvider, BackTop, Watermark | Ant Design 通用组件 | P0-P1 |
| **容器组件** | Drawer | Ant Design 抽屉 | P1 |
| **数据展示** | List | Ant Design 列表 | P1 |
---
## 二、核心设计原则(与根规范一致)
### 2.1 AI 优先设计原则
| 原则 | 说明 |
|------|------|
| **零歧义** | Props 名称自解释,无简称、无隐式行为 |
| **零默认假设** | 所有视觉行为显式声明 |
| **一致性** | 相同概念用相同 prop 名 |
| **扁平化** | 最多一层嵌套 |
| **确定性** | 相同输入始终产生相同输出 |
### 2.2 统一尺寸体系
所有组件使用统一的三级尺寸体系:
| 级别 | 说明 | 常用值 |
|------|------|-------|
| **small** | 小尺寸 | 紧凑列表、表格内 |
| **middle** | 中尺寸(默认) | 默认使用 |
| **large** | 大尺寸 | 突出显示、重点元素 |
---
## 三、通用组件
### 3.1 Affix 固钉
#### 组件定位
将页面元素固定在可视区域内,常用于导航栏、侧边栏、回到顶部按钮等。
#### Props 定义
```tsx
export interface AffixProps {
/** 距离窗口顶部达到指定偏移量后触发 */
offsetTop?: number;
/** 距离窗口底部达到指定偏移量后触发 */
offsetBottom?: number;
/** 指定 Affix 挂载的 HTML 节点 */
target?: () => HTMLElement | null;
/** 监听滚动事件的容器 */
getContainer?: () => HTMLElement | Window;
/** 固定状态改变时触发的回调 */
onChange?: (isAffixed: boolean) => void;
/** 子元素 */
children?: ReactNode;
/** 样式类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
}
```
#### 使用示例
```tsx
import { Affix, Button } from '@Pika/ui/affix';
// 基本使用
<Affix offsetTop={10}>
<Button variant="solid"></Button>
</Affix>;
// 固钉在底部
<Affix offsetBottom={10}>
<Button variant="solid"></Button>
</Affix>;
// 自定义容器
<Affix target={() => document.getElementById('scroll-container')} offsetTop={10}>
<Button variant="solid"></Button>
</Affix>;
```
#### Design Token
```css
--nv-affix-z-index: 10;
```
#### 开发优先级:P1
---
### 3.2 Anchor 锚点
#### 组件定位
用于跳转到页面指定位置,或显示当前滚动位置。
#### Props 定义
```tsx
export interface AnchorProps {
/** 锚点方向 */
direction?: 'vertical' | 'horizontal';
/** 当前激活的锚点链接 */
activeLink?: string;
/** 锚点滚动偏移量 */
targetOffset?: number;
/** 点击锚点链接的回调 */
onClick?: (
e: React.MouseEvent<HTMLElement>,
link: { href: string; title: ReactNode }
) => void;
/** 锚点链接改变时的回调 */
onChange?: (currentActiveLink: string) => void;
/** 获取锚点容器 */
getContainer?: () => HTMLElement | Window;
/** 是否改变 hash */
hash?: boolean;
/** 子元素 */
children?: ReactNode;
/** 样式类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
}
export interface AnchorLinkProps {
/** 锚点链接 */
href: string;
/** 锚点文本 */
title: ReactNode;
/** 子元素 */
children?: ReactNode;
}
```
#### 使用示例
```tsx
import { Anchor } from '@Pika/ui/anchor';
// 基本使用
<Anchor>
<Anchor.Link href="#section-1" title="第一章" />
<Anchor.Link href="#section-2" title="第二章">
<Anchor.Link href="#section-2-1" title="2.1 小节" />
<Anchor.Link href="#section-2-2" title="2.2 小节" />
</Anchor.Link>
<Anchor.Link href="#section-3" title="第三章" />
</Anchor>;
```
#### Design Token
```css
--nv-anchor-link-height: 32px;
--nv-anchor-link-color: var(--nv-text-color-secondary);
--nv-anchor-link-active-color: var(--nv-color-primary);
--nv-anchor-link-active-width: 2px;
--nv-anchor-wrapper-padding: 4px 0;
```
#### 开发优先级:P1
---
### 3.3 App 包裹组件
#### 组件定位
提供全局上下文,用于 Message、Modal、Notification 等组件的静态方法调用。
#### Props 定义
```tsx
export interface AppProps {
/** 子元素 */
children?: ReactNode;
}
export interface AppContextProps {
message: MessageStatic;
modal: ModalStatic;
notification: NotificationStatic;
}
export declare function useApp(): AppContextProps;
```
#### 使用示例
```tsx
import { App, Button } from '@Pika/ui/app';
// 基本使用
function AppDemo() {
const { message, modal, notification } = App.useApp();
const showMessage = () => {
message.success('操作成功');
};
const showModal = () => {
modal.info({ title: '提示', content: '这是一条提示信息' });
};
return (
<App>
<Button onClick={showMessage}></Button>
<Button onClick={showModal}></Button>
</App>
);
}
```
#### 开发优先级:P0
---
### 3.4 ConfigProvider 全局配置
#### 组件定位
为组件提供统一的全局配置,包括主题、语言、国际化等。
#### Props 定义
```tsx
export interface ConfigProviderProps {
/** 主题配置 */
theme?: {
token?: Record<string, any>;
components?: Record<string, any>;
algorithm?: 'default' | 'dark' | 'compact' | Array<'default' | 'dark' | 'compact'>;
};
/** 语言包 */
locale?: Record<string, any>;
/** 全局 zIndex */
zIndex?: number;
/** 设置主题色 */
colorPrimary?: string;
/** 设置图标前缀 */
iconPrefixCls?: string;
/** 设置组件类名前缀 */
prefixCls?: string;
/** 设置弹框的默认渲染容器 */
getPopupContainer?: (node: HTMLElement) => HTMLElement;
/** 子元素 */
children?: ReactNode;
}
```
#### 使用示例
```tsx
import { ConfigProvider, Button } from '@Pika/ui/config-provider';
// 基本使用
<ConfigProvider
theme={{
token: {
colorPrimary: '#1890ff',
borderRadius: 8,
},
}}
>
<App />
</ConfigProvider>;
```
#### Design Token
与根设计规范中的 Token 一致。
#### 开发优先级:P0
---
### 3.5 BackTop 回到顶部
#### 组件定位
提供快速回到页面顶部的功能。
#### Props 定义
```tsx
export interface BackTopProps {
/** 距离顶部多少像素时显示 */
visibilityHeight?: number;
/** 点击回调 */
onClick?: () => void;
/** 监听滚动的容器 */
target?: () => HTMLElement | Window;
/** 子元素 */
children?: ReactNode;
/** 样式类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
}
```
#### 使用示例
```tsx
import { BackTop } from '@Pika/ui/back-top';
// 基本使用
<BackTop />;
// 自定义图标
<BackTop>
<div style={{
height: 40,
width: 40,
lineHeight: '40px',
borderRadius: 4,
backgroundColor: '#1088e9',
color: '#fff',
textAlign: 'center',
fontSize: 20,
}}>
UP
</div>
</BackTop>;
```
#### Design Token
```css
--nv-back-top-size: 40px;
--nv-back-top-z-index: 10;
--nv-back-top-color: var(--nv-color-primary);
--nv-back-top-hover-color: var(--nv-color-primary-hover);
```
#### 开发优先级:P1
---
### 3.6 Watermark 水印
#### 组件定位
为页面或元素添加水印,防止截图泄露或证明来源。(注意:在 FEEDBACK_COMPONENTS.md 中已有定义,这里补充完整)
#### Props 定义
```tsx
export interface WatermarkProps {
/** 水印文字 */
content?: string | string[];
/** 自定义图片水印 */
image?: string;
/** 水印宽度(文字模式时为单个文字宽度) */
width?: number;
/** 水印高度(文字模式时为单个文字高度) */
height?: number;
/** 旋转角度 */
rotate?: number;
/** 水印之间的水平间距 */
gap?: [number, number];
/** 水印在 canvas 上绘制时的偏移量 */
offset?: [number, number];
/** 文字样式 */
font?: {
color?: string;
fontSize?: number;
fontFamily?: string;
fontWeight?: 'normal' | 'light' | 'weight' | number;
};
/** 水印层级 */
zIndex?: number;
/** 子元素 */
children?: ReactNode;
}
```
#### 使用示例
```tsx
import { Watermark, Card } from '@Pika/ui/watermark';
// 基本使用
<Watermark content="Pika UI">
<Card style={{ width: 600, height: 400 }}>
<p></p>
</Card>
</Watermark>;
// 多行水印
<Watermark content={['Pika UI', '内部文档']}>
<div></div>
</Watermark>;
// 自定义样式
<Watermark
content="Pika UI"
rotate={-25}
font={{
color: 'rgba(0, 0, 0, 0.08)',
fontSize: 16,
}}
>
<div></div>
</Watermark>;
```
#### Design Token
```css
--nv-watermark-font-size: 14px;
--nv-watermark-font-color: rgba(0, 0, 0, 0.08);
--nv-watermark-rotate: -22deg;
--nv-watermark-gap: [100, 100];
--nv-watermark-z-index: 9;
```
#### 开发优先级:P3
---
## 四、容器组件
### 4.1 Drawer 抽屉
#### 组件定位
抽屉组件,用于从屏幕边缘滑出内容面板,常用于详情页、表单页、筛选页等。
#### Props 定义
```tsx
export type DrawerPlacement = 'top' | 'right' | 'bottom' | 'left';
export type DrawerSize = 'small' | 'middle' | 'large' | number | string;
export interface DrawerProps {
/** 抽屉是否可见 */
open: boolean;
/** 抽屉标题 */
title?: ReactNode;
/** 抽屉宽度(placement 为 left/right 时生效) */
width?: number | string;
/** 抽屉高度(placement 为 top/bottom 时生效) */
height?: number | string;
/** 抽屉尺寸预设 */
size?: DrawerSize;
/** 抽屉放置位置 */
placement?: DrawerPlacement;
/** 是否显示遮罩 */
mask?: boolean;
/** 点击遮罩是否关闭 */
maskClosable?: boolean;
/** 是否显示右上角关闭按钮 */
closable?: boolean;
/** 自定义关闭图标 */
closeIcon?: ReactNode;
/** 点击关闭图标的回调 */
onClose?: () => void;
/** 抽屉打开后的回调 */
afterOpenChange?: (open: boolean) => void;
/** 抽屉的容器 */
getContainer?: HTMLElement | (() => HTMLElement) | null;
/** 预渲染,防止抖动 */
forceRender?: boolean;
/** 关闭时销毁 Drawer 里的子元素 */
destroyOnClose?: boolean;
/** 抽屉的样式 */
style?: React.CSSProperties;
/** 抽屉标题的样式 */
headerStyle?: React.CSSProperties;
/** 抽屉内容的样式 */
bodyStyle?: React.CSSProperties;
/** 自定义遮罩样式 */
maskStyle?: React.CSSProperties;
/** 抽屉的类名 */
className?: string;
/** 抽屉根元素的类名 */
rootClassName?: string;
/** 是否支持键盘 esc 关闭 */
keyboard?: boolean;
/** 子元素 */
children?: ReactNode;
/** 抽屉页脚 */
footer?: ReactNode;
/** 页脚的样式 */
footerStyle?: React.CSSProperties;
/** 是否显示页脚 */
footer?: ReactNode | null;
}
```
#### 使用示例
```tsx
import { Drawer, Button, Form, Input } from '@Pika/ui/drawer';
function DrawerDemo() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}></Button>
<Drawer
title="基本抽屉"
width={480}
open={open}
onClose={() => setOpen(false)}
>
<p></p>
<p></p>
</Drawer>
</>
);
}
// 表单抽屉
function FormDrawer() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}></Button>
<Drawer
title="新建"
width={480}
open={open}
onClose={() => setOpen(false)}
footer={
<div style={{ textAlign: 'right' }}>
<Button onClick={() => setOpen(false)} style={{ marginRight: 8 }}>
</Button>
<Button variant="solid" onClick={() => setOpen(false)}>
</Button>
</div>
}
>
<Form layout="vertical">
<Form.Item label="名称" name="name">
<Input placeholder="请输入名称" />
</Form.Item>
<Form.Item label="描述" name="description">
<TextArea placeholder="请输入描述" rows={4} />
</Form.Item>
</Form>
</Drawer>
</>
);
}
```
#### Design Token
```css
--nv-drawer-z-index: 1000;
--nv-drawer-header-height: 56px;
--nv-drawer-header-padding: 16px 24px;
--nv-drawer-body-padding: 24px;
--nv-drawer-footer-padding: 16px 24px;
--nv-drawer-mask-bg: rgba(0, 0, 0, 0.45);
--nv-drawer-bg: #fff;
--nv-drawer-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
--nv-drawer-width-small: 378px;
--nv-drawer-width-middle: 480px;
--nv-drawer-width-large: 736px;
```
#### 开发优先级:P1
---
## 五、数据展示组件
### 5.1 List 列表
#### 组件定位
通用列表组件,用于展示一系列同类数据。
#### Props 定义
```tsx
export interface ListProps<T> {
/** 列表数据 */
data?: T[];
/** 列表尺寸 */
size?: 'small' | 'middle' | 'large';
/** 列表边框 */
bordered?: boolean;
/** 是否显示分割线 */
split?: boolean;
/** 列表项头部 */
header?: ReactNode;
/** 列表项底部 */
footer?: ReactNode;
/** 列表加载状态 */
loading?: boolean;
/** 空列表时显示的内容 */
empty?: ReactNode;
/** 渲染列表项 */
renderItem?: (item: T, index: number) => ReactNode;
/** 列表项布局 */
itemLayout?: 'horizontal' | 'vertical';
/** 列表行高 */
rowKey?: string | ((item: T) => string);
/** 是否显示网格 */
grid?: {
gutter?: number;
column?: number;
xs?: number;
sm?: number;
md?: number;
lg?: number;
xl?: number;
xxl?: number;
};
/** 子元素 */
children?: ReactNode;
/** 样式类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
}
export interface ListItemProps {
/** 列表项内容 */
children?: ReactNode;
/** 列表项的额外内容 */
extra?: ReactNode;
/** 列表项的类名 */
className?: string;
/** 列表项的样式 */
style?: React.CSSProperties;
/** 列表项的 actions */
actions?: ReactNode[];
}
export interface ListItemMetaProps {
/** 头像 */
avatar?: ReactNode;
/** 标题 */
title?: ReactNode;
/** 描述 */
description?: ReactNode;
/** 类名 */
className?: string;
}
```
#### 使用示例
```tsx
import { List, Avatar, Button } from '@Pika/ui/list';
// 基本使用
const data = [
{ name: '张三', age: 25, avatar: 'https://example.com/avatar1.jpg' },
{ name: '李四', age: 30, avatar: 'https://example.com/avatar2.jpg' },
{ name: '王五', age: 28, avatar: 'https://example.com/avatar3.jpg' },
];
<List
data={data}
renderItem={(item) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href="#">{item.name}</a>}
description={`年龄: ${item.age}`}
/>
</List.Item>
)}
/>;
// 网格列表
<List
grid={{ gutter: 16, column: 4 }}
data={data}
renderItem={(item) => (
<List.Item>
<Card title={item.name}>
<p>{item.age}</p>
</Card>
</List.Item>
)}
/>;
```
#### Design Token
```css
--nv-list-item-height-small: 32px;
--nv-list-item-height-middle: 40px;
--nv-list-item-height-large: 48px;
--nv-list-item-padding-small: 8px 12px;
--nv-list-item-padding-middle: 12px 16px;
--nv-list-item-padding-large: 16px 24px;
--nv-list-border-color: var(--nv-color-border);
--nv-list-split-color: var(--nv-color-border);
```
#### 开发优先级:P1
---
## 六、开发计划与优先级
### 6.1 优先级规划
#### Phase 1: 核心通用组件(P0
| 组件 | 说明 | 预估工时 |
|------|------|---------|
| App | 包裹组件,提供全局上下文 | 0.5 天 |
| ConfigProvider | 全局配置组件 | 1 天 |
#### Phase 2: 重要通用组件(P1
| 组件 | 说明 | 预估工时 |
|------|------|---------|
| Affix | 固钉组件 | 0.5 天 |
| Anchor | 锚点组件 | 0.5 天 |
| BackTop | 回到顶部 | 0.5 天 |
| Drawer | 抽屉组件 | 1.5 天 |
| List | 列表组件 | 1.5 天 |
#### Phase 3: 高级组件(P3
| 组件 | 说明 | 预估工时 |
|------|------|---------|
| Watermark | 水印组件 | 0.5 天 |
### 6.2 开发里程碑
| 阶段 | 任务 | 时间 |
|------|------|------|
| Phase 1 | App 和 ConfigProvider | 1 周 |
| Phase 2 | Affix、Anchor、BackTop、Drawer、List | 2 周 |
| Phase 3 | Watermark | 0.5 周 |
---
## 七、通用设计规范
### 7.1 Props 命名规范
```tsx
// ✅ Pika 方式
interface ComponentProps {
// 尺寸统一
size?: 'small' | 'middle' | 'large';
// 状态统一
status?: 'default' | 'success' | 'warning' | 'error' | 'info';
// 数据统一
data?: T[];
// 布尔属性:动词/形容词 + 肯定形式
showIcon?: boolean;
showClose?: boolean;
closable?: boolean;
disabled?: boolean;
loading?: boolean;
// 事件:on + 动词 + 名词
onChange?: (value: any) => void;
onClick?: (event: MouseEvent) => void;
onClose?: () => void;
onOpenChange?: (open: boolean) => void;
}
```
### 7.2 样式绑定规范
```tsx
// ✅ Pika 方式:使用 data-* 属性
<div
data-size={size}
data-status={status}
data-variant={variant}
data-loading={loading}
/>
// CSS 中使用属性选择器
.component[data-size="small"] {
font-size: 12px;
}
```
### 7.3 类型定义规范
```tsx
// ✅ 使用联合类型字面量
type Size = 'small' | 'middle' | 'large';
type Status = 'default' | 'success' | 'warning' | 'error' | 'info';
// ❌ 避免使用 string 或 any
type Size = string; // 范围不明确
type Status = any; // 没有类型提示
```
---
## 八、无障碍设计
### 8.1 ARIA 属性
```tsx
// Drawer
<div
role="dialog"
aria-modal="true"
aria-labelledby="drawer-title"
aria-describedby="drawer-content"
>
<h2 id="drawer-title"></h2>
<div id="drawer-content"></div>
</div>
// List
<ul role="list">
<li role="listitem"> 1</li>
<li role="listitem"> 2</li>
</ul>
```
### 8.2 键盘操作
- Drawer 支持 Esc 关闭
- 所有可点击元素支持 Enter/Space 触发
- Tab 顺序合理
### 8.3 颜色对比度
- 文本与背景对比度 ≥ 4.5:1
- 大文本对比度 ≥ 3:1
- 图标与背景对比度 ≥ 3:1
---
## 九、与 Pika 根规范的对照
| Pika 根规范 | 实现方式 |
|------------|---------|
| **AI 优先** | 所有 Props 使用联合类型字面量,无魔法字符串 |
| **三级别尺寸** | `small`/`middle`/`large` 统一应用于所有组件 |
| **统一事件命名** | `on + 动词 + 名词` 规则 |
| **布尔属性** | 动词/形容词 + 肯定形式 |
| **data-* 样式绑定** | 使用 `data-*` 属性而非 class 拼接 |
| **自包含组件** | 每个组件独立导入,路径即名字 |
| **Apple HIG** | 圆角、间距、动效遵循 Apple 规范 |
---
## 十、完整组件清单
### 10.1 已规划完成的组件
-**通用组件**: Button, FloatButton, Icon, Typography
-**数据展示**: Avatar, Badge, Calendar, Card, Carousel, Collapse, Descriptions, Empty, Image, Popover, QRCode, Segmented, Statistic, Table, Tag, Timeline, Tooltip, Tour, Tree
-**数据录入**: AutoComplete, Cascader, Checkbox, Radio, Switch, DatePicker, Form, Input, InputNumber, Mention, RangePicker, Rate, Select, Slider, Textarea, TimePicker, Transfer, TreeSelect, Upload
-**布局组件**: Divider, Flex, Grid, Layout, Masonry, Space, Splitter, Stack
-**导航组件**: Breadcrumb, Dropdown, Menu, Pagination, Steps, Tabs
-**反馈组件**: Alert, Message, Notification, Modal, Popconfirm, Spin, Progress, Result, Skeleton, Watermark
### 10.2 本规范补充的组件
- 📋 **通用组件**: Affix, Anchor, App, ConfigProvider, BackTop
- 📋 **容器组件**: Drawer
- 📋 **数据展示**: List
---
## 十一、AI 生成提示
当 AI 生成 Pika 组件相关代码时,请遵循以下提示:
```
1. 导入路径 = @Pika/ui/组件名
2. 尺寸 prop 始终叫 size,值从 small/middle/large 选
3. 数据 prop 始终叫 data
4. 布尔 prop 用动词/形容词开头
5. 所有 prop 类型用联合类型字面量定义
6. 使用 data-* 属性进行样式绑定
7. 事件回调 = on + 动词 + 名词
8. 参考 Ant Design API 但按照 Pika 规范调整命名
```
---
&gt; **Pika 其他组件计划完成!所有必要组件的规范已制定完毕。**