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

661 lines
14 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 设计规范的布局组件设计
> 设计原则:以 Apple HIG 为准,AI-First,三级别尺寸体系
---
## 一、核心理念
### 1.1 设计价值观(与根规范一致)
Pika 布局组件基于 Apple Human Interface Guidelines 的三大核心原则构建:
| 原则 | 说明 |
|-----|------|
| **层级** | 建立清晰的视觉层级,区分内容和控件 |
| **和谐** | 与硬件和软件设计保持一致 |
| **一致性** | 采用平台约定,跨组件保持统一 |
### 1.2 AI-First 设计原则
所有布局组件遵循 Pika 的 AI-First 设计原则:
| 原则 | 说明 |
|-----|------|
| **零歧义** | Props 名称自解释,无简称、无隐式行为 |
| **零默认假设** | 所有视觉行为显式声明 |
| **一致性** | 相同概念用相同 prop 名 |
| **扁平化** | 最多一层嵌套 |
| **确定性** | 相同输入始终产生相同输出 |
---
## 二、统一尺寸体系(三级别)
所有布局组件使用统一的三级别尺寸体系:
| 级别 | 间距 | 圆角 | 字体大小 |
|-----|------|------|---------|
| **small** | 8px | 4px | 12px |
| **middle** | 16px | 8px | 14px |
| **large** | 24px | 12px | 16px |
### 2.1 Design Token(与根规范一致)
```css
--nv-spacing-small: 8px;
--nv-spacing-middle: 16px;
--nv-spacing-large: 24px;
--nv-radius-small: 4px;
--nv-radius-middle: 8px;
--nv-radius-large: 12px;
--nv-radius-full: 9999px;
--nv-font-size-small: 12px;
--nv-font-size-middle: 14px;
--nv-font-size-large: 16px;
```
---
## 三、组件体系
### 3.1 组件清单
| 组件 | 说明 | 优先级 |
|-----|------|-------|
| **Layout** | 页面布局容器 | P0 |
| **Header** | 顶部导航栏 | P0 |
| **Footer** | 底部区域 | P0 |
| **Content** | 内容区域 | P0 |
| **Sider** | 侧边栏 | P0 |
| **Row** | 栅格行 | P1 |
| **Col** | 栅格列 | P1 |
| **Space** | 间距组件 | P2 |
| **HStack** | 水平排列 | P2 |
| **VStack** | 垂直排列 | P2 |
| **Divider** | 分隔线 | P2 |
---
## 四、组件详细设计
### 4.1 Layout 布局容器
#### Props 定义(AI-First
```tsx
export interface LayoutProps {
/** 是否有侧边栏(用于 SSR 避免样式闪烁) */
hasSider?: boolean
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
export interface HeaderProps {
/** 高度 */
height?: number | string
/** 是否固定在顶部 */
fixed?: boolean
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
export interface FooterProps {
/** 内边距 */
padding?: number | string
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
export interface ContentProps {
/** 内边距 */
padding?: number | string
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
export interface SiderProps {
/** 宽度 */
width?: number | string
/** 折叠后的宽度 */
collapsedWidth?: number
/** 是否可折叠 */
collapsible?: boolean
/** 当前折叠状态 */
collapsed?: boolean
/** 默认折叠状态 */
defaultCollapsed?: boolean
/** 折叠状态变化回调 */
onCollapse?: (collapsed: boolean) => void
/** 响应式断点 */
breakpoint?: 'small' | 'middle' | 'large'
/** 断点变化回调 */
onBreakpoint?: (broken: boolean) => void
/** 是否反转箭头方向 */
reverseArrow?: boolean
/** 自定义触发器 */
trigger?: React.ReactNode
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
```
#### 使用示例
```tsx
// 基础布局
<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Content>Content</Layout.Content>
<Layout.Footer>Footer</Layout.Footer>
</Layout>
// 经典后台布局
<Layout>
<Layout.Sider
width={200}
collapsedWidth={80}
collapsible
breakpoint="middle"
>
<Menu />
</Layout.Sider>
<Layout>
<Layout.Header fixed>Header</Layout.Header>
<Layout.Content padding={24}>Content</Layout.Content>
</Layout>
</Layout>
```
#### Design Token
```css
--nv-layout-header-height: 64px;
--nv-layout-footer-padding: var(--nv-spacing-middle);
--nv-layout-sider-width: 200px;
--nv-layout-sider-collapsed-width: 80px;
--nv-layout-trigger-height: 48px;
--nv-layout-content-padding: var(--nv-spacing-middle);
```
---
### 4.2 Grid 栅格系统
#### Props 定义(AI-First
```tsx
export interface RowProps {
/** 栅格间隔 */
gutter?: number | [number, number]
/** 主轴对齐方式 */
justify?: 'start' | 'end' | 'center' | 'space-around' | 'space-between'
/** 交叉轴对齐方式 */
align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
export interface ColProps {
/** 栅格格数 (0-24) */
span?: number
/** 左侧偏移格数 */
offset?: number
/** 栅格顺序 */
order?: number
/** 响应式栅格 */
small?: number | { span?: number; offset?: number; order?: number }
middle?: number | { span?: number; offset?: number; order?: number }
large?: number | { span?: number; offset?: number; order?: number }
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
```
#### 使用示例
```tsx
// 基础栅格
<Row gutter={16}>
<Col span={12}><Card /></Col>
<Col span={12}><Card /></Col>
</Row>
// 响应式布局
<Row gutter={[16, 16]}>
<Col
small={24}
middle={12}
large={6}
>
</Col>
</Row>
// 间距和对齐
<Row
gutter={[16, 16]}
justify="space-between"
align="center"
>
<Col span={8} offset={2}></Col>
<Col span={12}></Col>
</Row>
```
#### Design Token
```css
--nv-grid-gutter: var(--nv-spacing-middle);
--nv-grid-columns: 24;
```
---
### 4.3 Space 间距组件
#### Props 定义(AI-First
```tsx
export interface SpaceProps {
/** 间距方向 */
direction?: 'horizontal' | 'vertical'
/** 间距大小 */
size?: 'small' | 'middle' | 'large'
/** 对齐方式 */
align?: 'start' | 'end' | 'center' | 'baseline'
/** 是否换行(仅水平方向有效) */
wrap?: boolean
/** 分隔符 */
split?: React.ReactNode
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
```
#### 使用示例
```tsx
// 基础使用
<Space size="middle">
<Button></Button>
<Button></Button>
</Space>
// 垂直排列
<Space direction="vertical" size="small">
<Input />
<Input />
</Space>
// 带分隔符
<Space split={<Divider type="vertical" />}>
<Text>Link 1</Text>
<Text>Link 2</Text>
</Space>
// 自动换行
<Space wrap size="middle">
{tags.map(tag => <Tag key={tag}>{tag}</Tag>)}
</Space>
```
#### Design Token
```css
--nv-space-gap-small: var(--nv-spacing-small);
--nv-space-gap-middle: var(--nv-spacing-middle);
--nv-space-gap-large: var(--nv-spacing-large);
```
---
### 4.4 Stack 弹性盒布局
#### Props 定义(AI-First
```tsx
export interface StackProps {
/** 排列方向 */
direction?: 'horizontal' | 'vertical'
/** 间距 */
gap?: 'small' | 'middle' | 'large' | number | string
/** 主轴对齐方式 */
justify?: 'start' | 'end' | 'center' | 'space-around' | 'space-between' | 'space-evenly'
/** 交叉轴对齐方式 */
align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
/** 是否换行 */
wrap?: boolean
/** 子元素 */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
// 便捷组件
export interface HStackProps extends Omit<StackProps, 'direction'> {}
export interface VStackProps extends Omit<StackProps, 'direction'> {}
```
#### 使用示例
```tsx
// 使用 Stack
<Stack direction="horizontal" gap="middle" justify="space-between">
<Logo />
<Nav />
</Stack>
// 使用 HStack
<HStack gap="middle" justify="space-between">
<Logo />
<Nav />
</HStack>
// 使用 VStack
<VStack gap="small" align="center">
<Avatar />
<Name />
<Desc />
</VStack>
```
---
### 4.5 Divider 分隔线
#### Props 定义(AI-First
```tsx
export interface DividerProps {
/** 方向 */
type?: 'horizontal' | 'vertical'
/** 是否虚线 */
dashed?: boolean
/** 子元素(居中文字) */
children?: React.ReactNode
className?: string
style?: React.CSSProperties
}
```
#### 使用示例
```tsx
// 水平分隔
<Divider />
// 带文字
<Divider></Divider>
// 垂直分隔
<Space split={<Divider type="vertical" />}>
<Text>Link 1</Text>
<Text>Link 2</Text>
</Space>
// 虚线
<Divider dashed />
```
#### Design Token
```css
--nv-divider-color: var(--nv-color-border);
--nv-divider-padding: var(--nv-spacing-middle);
```
---
## 五、AI-First 设计规范
### 5.1 Props 命名规范
| 规则 | 说明 |
|-----|------|
| **布尔属性** | 动词/形容词 + 肯定形式:`disabled`, `collapsible`, `fixed`, `wrap`, `dashed` |
| **事件回调** | `on + 动词 + 名词``onCollapse`, `onBreakpoint` |
| **尺寸** | 统一使用 `small`, `middle`, `large` |
| **响应式断点** | 统一使用 `small`, `middle`, `large` |
### 5.2 样式绑定规范
使用 `data-*` 属性进行样式绑定:
```tsx
<div
data-direction="horizontal"
data-size="middle"
data-wrap="true"
/>
```
### 5.3 组件导入规范
每个组件独立导入,路径即名字:
```tsx
import { Layout } from '@Pika/ui/layout'
import { Header, Footer, Sider, Content } from '@Pika/ui/layout'
import { Row, Col } from '@Pika/ui/grid'
import { Space } from '@Pika/ui/space'
import { Stack, HStack, VStack } from '@Pika/ui/stack'
import { Divider } from '@Pika/ui/divider'
```
---
## 六、完整使用示例
### 6.1 经典后台布局
```tsx
import { Layout, Row, Col, Space, HStack, VStack, Divider } from '@Pika/ui'
const App = () => {
const [collapsed, setCollapsed] = useState(false)
return (
<Layout>
<Layout.Sider
width={200}
collapsedWidth={80}
collapsible
collapsed={collapsed}
onCollapse={setCollapsed}
breakpoint="middle"
>
<Menu />
</Layout.Sider>
<Layout>
<Layout.Header fixed>
<HStack justify="space-between">
<Logo />
<UserMenu />
</HStack>
</Layout.Header>
<Layout.Content padding={24}>
<VStack gap="middle">
<PageTitle />
<Row gutter={[16, 16]}>
<Col
small={24}
middle={12}
large={6}
>
<Card />
</Col>
<Col
small={24}
middle={12}
large={6}
>
<Card />
</Col>
<Col
small={24}
middle={12}
large={6}
>
<Card />
</Col>
<Col
small={24}
middle={12}
large={6}
>
<Card />
</Col>
</Row>
<Divider />
<Space size="middle">
<Button></Button>
<Button variant="outline"></Button>
</Space>
</VStack>
</Layout.Content>
<Layout.Footer>
© 2024 Pika UI
</Layout.Footer>
</Layout>
</Layout>
)
}
```
---
## 七、文件结构
```
src/components/
├── layout/
│ ├── index.ts
│ ├── Layout.tsx
│ ├── Header.tsx
│ ├── Footer.tsx
│ ├── Sider.tsx
│ ├── Content.tsx
│ ├── Layout.module.css
│ └── Layout.test.tsx
├── grid/
│ ├── index.ts
│ ├── Row.tsx
│ ├── Col.tsx
│ ├── Grid.module.css
│ └── Grid.test.tsx
├── space/
│ ├── index.ts
│ ├── Space.tsx
│ ├── Space.module.css
│ └── Space.test.tsx
├── stack/
│ ├── index.ts
│ ├── Stack.tsx
│ ├── HStack.tsx
│ ├── VStack.tsx
│ ├── Stack.module.css
│ └── Stack.test.tsx
└── divider/
├── index.ts
├── Divider.tsx
├── Divider.module.css
└── Divider.test.tsx
```
---
## 八、优先级规划
### Phase 1: 核心布局 (P0)
| 组件 | 说明 | 预估工时 |
|-----|------|---------|
| Layout | 布局容器 | 1h |
| Header | 顶部导航栏 | 0.5h |
| Footer | 底部区域 | 0.5h |
| Content | 内容区域 | 0.5h |
| Sider | 侧边栏 | 2h |
### Phase 2: 栅格系统 (P1)
| 组件 | 说明 | 预估工时 |
|-----|------|---------|
| Row | 行容器 | 1h |
| Col | 列组件 | 1.5h |
### Phase 3: 间距和弹性盒 (P2)
| 组件 | 说明 | 预估工时 |
|-----|------|---------|
| Space | 间距组件 | 1h |
| Stack | 弹性盒容器 | 1h |
| HStack | 水平排列 | 0.25h |
| VStack | 垂直排列 | 0.25h |
| Divider | 分隔线 | 0.5h |
---
## 九、与根设计规范的对照
| 根规范 | 实现方式 |
|------|---------|
| **三级别尺寸** | `small`, `middle`, `large` 统一应用于所有组件 |
| **AI-First** | 所有 Props 使用联合类型字面量,无魔法字符串 |
| **Apple HIG** | 圆角、间距、动效遵循 Apple 规范 |
| **data-* 样式绑定** | 使用 `data-*` 属性而非 className 拼接 |
| **自包含组件** | 每个组件独立导入,路径即名字 |
| **统一事件命名** | `on + 动词 + 名词` 规则 |
---
## 十、设计总结
### Pika 布局组件的特点
1. **简洁统一** - 三级别尺寸体系,无过度设计
2. **AI 友好** - Props 自解释,类型安全,确定导入路径
3. **Apple HIG 优先** - 遵循 Apple 人机交互指南
4. **语义化** - Space, HStack, VStack 提供清晰的布局语义
5. **可扩展** - 支持响应式、折叠等高级功能
### AI 提示工程
```
1. 导入路径 = @Pika/ui/组件名 (layout/grid/space/stack/divider)
2. 尺寸 prop 始终叫 size,值从 small/middle/large 选
3. 响应式断点统一:small/middle/large
4. 布尔 prop 用动词开头 (collapsible, fixed, wrap, dashed)
5. 回调命名 = on + 动词 + 名词 (onCollapse, onBreakpoint)
6. 所有 prop 类型用联合类型字面量定义
7. 使用 Space 代替手动计算间距
8. 使用 HStack/VStack 进行弹性盒布局
```
> **Pika 布局组件:简洁、统一、AI-First**