Files
RustUI/_plans/other-components-plan.md
2026-05-31 09:36:23 +08:00

902 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 其他组件计划完成!所有必要组件的规范已制定完毕。**