Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions docs/white-book/03-UI-Ref/06-KeyUI/00-Overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Key UI 组件库

> 源码: [`packages/key-ui/`](https://github.com/BioforestChain/KeyApp/tree/main/packages/key-ui)

## 概述

`@biochain/key-ui` 是 KeyApp 的共享 UI 组件库,供主应用和 MiniApps 共同使用。

采用 [Base UI](https://base-ui.com) 风格的 headless 架构:
- **Compound Components** - 复合组件模式 (如 `TokenIcon.Root` / `TokenIcon.Image`)
- **useRenderElement** - 统一的渲染抽象,支持 `render` prop 自定义
- **State + Props 分离** - 组件暴露 `State` 类型供样式函数使用

## 安装

```bash
pnpm add @biochain/key-ui
```

## 组件列表

| 组件 | 路径 | 说明 |
|------|------|------|
| `AddressDisplay` | `@biochain/key-ui/address-display` | 地址显示 (智能截断 + 复制) |
| `AmountDisplay` | `@biochain/key-ui/amount-display` | 金额显示 (动画 + 紧凑模式) |
| `AmountWithFiat` | `@biochain/key-ui/amount-display` | 金额 + 法币复合显示 |
| `TokenIcon` | `@biochain/key-ui/token-icon` | Token 图标 (Compound) |

## 工具包

`@biochain/key-utils` 提供底层工具函数:

| 函数 | 说明 |
|------|------|
| `cn()` | className 合并 (clsx + tailwind-merge) |
| `formatAmount()` | 金额格式化 (紧凑模式、千分位) |
| `truncateAddress()` | 地址截断 (预设模式) |
| `measureText()` | Canvas 文字宽度测量 |
| `useCopyToClipboard()` | 复制到剪贴板 Hook |

## 架构

```
packages/
├── key-utils/ # @biochain/key-utils - 工具函数
│ └── src/
│ ├── cn.ts
│ ├── format-amount.ts
│ ├── truncate-address.ts
│ └── use-copy-to-clipboard.ts
│
└── key-ui/ # @biochain/key-ui - UI 组件
└── src/
├── address-display/
│ ├── AddressDisplay.tsx
│ └── use-address-display.ts
├── amount-display/
│ ├── AmountDisplay.tsx
│ └── AmountWithFiat.tsx
├── token-icon/
│ ├── root/
│ ├── image/
│ └── fallback/
└── utils/
├── types.ts
└── use-render-element.tsx
```

## 与 shadcn/ui 的关系

- shadcn/ui 基础组件 (Button, Card, Input) 由各项目独立维护
- key-ui 只提供**业务组件** (AddressDisplay, AmountDisplay, TokenIcon)
- 样式策略:默认 Tailwind class,可通过 `className` 函数覆盖
125 changes: 125 additions & 0 deletions docs/white-book/03-UI-Ref/06-KeyUI/01-AddressDisplay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# AddressDisplay 组件

> 源码: [`packages/key-ui/src/address-display/`](https://github.com/BioforestChain/KeyApp/tree/main/packages/key-ui/src/address-display)

## 概述

智能地址显示组件,支持响应式截断和一键复制。

## 显示模式

| 模式 | 格式 | 适用场景 |
|------|------|---------|
| `full` | 完整地址 | 转账确认、签名授权 |
| `auto` | 响应式截断 | 钱包卡片、地址选择器 |
| `compact` | `6...4` | 列表项、小空间 |
| `standard` | `8...6` | 联系人选择 |
| `detailed` | `10...8` | 链选择器 |

## 使用

### 基础用法

```tsx
import { AddressDisplay } from '@biochain/key-ui/address-display'

// 自动截断
<AddressDisplay address="0x742d35Cc6634C0532925a3b844Bc454e4438f44e" />

// 固定模式
<AddressDisplay address={address} mode="compact" />

// 完整显示
<AddressDisplay address={address} mode="full" />
```

### 自定义样式

```tsx
// 使用状态函数
<AddressDisplay
address={address}
className={(state) => state.copied ? 'text-green-500' : 'text-gray-500'}
/>

// 使用 render prop
<AddressDisplay
address={address}
render={(props, state) => (
<div {...props} className="custom-class">
{state.truncated && <span>...</span>}
</div>
)}
/>
```

### 使用 Hook

```tsx
import { useAddressDisplay } from '@biochain/key-ui/address-display'

function CustomAddress({ address }) {
const { displayText, copy, copied, containerRef, truncated } = useAddressDisplay({
address,
mode: 'auto',
})

return (
<span ref={containerRef} onClick={copy}>
{displayText}
{copied && ' ✓'}
</span>
)
}
```

## Props

```typescript
interface AddressDisplayProps {
address: string
mode?: 'full' | 'auto' | 'compact' | 'standard' | 'detailed'
startChars?: number // 固定截断:开头字符数
endChars?: number // 固定截断:结尾字符数
placeholder?: string // 空地址占位符 (默认 '---')
copyable?: boolean // 可复制 (默认 true)
onCopy?: () => void // 复制回调
testId?: string // data-testid
className?: string | ((state: State) => string)
style?: CSSProperties | ((state: State) => CSSProperties)
render?: ComponentRenderFn | ReactElement
}

interface AddressDisplayState {
copied: boolean
truncated: boolean
mode: TruncationMode
}
```

## 截断预设

```typescript
const TRUNCATION_PRESETS = {
compact: { start: 6, end: 4 }, // 总长 13 字符
standard: { start: 8, end: 6 }, // 总长 17 字符
detailed: { start: 10, end: 8 }, // 总长 21 字符
}
```

## 场景对照表

| 场景 | 推荐模式 |
|------|---------|
| 转账确认页 | `full` + `break-all` |
| 钱包卡片 | `auto` |
| 交易列表 | `compact` |
| 联系人选择 | `standard` |
| 链选择器 | `detailed` |
| 小程序授权 | `full` |

## 无障碍

- 复制按钮有 `aria-label` 说明完整地址
- 复制成功后更新 `aria-label` 为 "已复制"
- 使用 `role="status"` 区域播报复制状态
133 changes: 133 additions & 0 deletions docs/white-book/03-UI-Ref/06-KeyUI/02-AmountDisplay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# AmountDisplay 组件

> 源码: [`packages/key-ui/src/amount-display/`](https://github.com/BioforestChain/KeyApp/tree/main/packages/key-ui/src/amount-display)

## 概述

金额显示组件,支持动画数字、紧凑模式、隐私模式。

## 显示模式

| 模式 | 格式 | 适用场景 |
|------|------|---------|
| 完整精度 | `1,234.56789012` | 转账确认 |
| 自适应 | `1,234.5679` | 余额显示 |
| 隐藏尾零 | `1,234.5` | 一般显示 |
| 紧凑 | `1.5M` / `12.5K` | 列表概览 |

## 使用

### 基础用法

```tsx
import { AmountDisplay } from '@biochain/key-ui/amount-display'

// 基础
<AmountDisplay value={1234.5678} symbol="ETH" />

// 紧凑模式
<AmountDisplay value={1500000} compact /> // 显示 1.5M

// 带正负号
<AmountDisplay value={-2.3} sign="always" color="auto" />

// 隐私模式
<AmountDisplay value={100} hidden /> // 显示 ••••••

// 加载态
<AmountDisplay value={0} loading />
```

### 带法币显示

```tsx
import { AmountWithFiat } from '@biochain/key-ui/amount-display'

<AmountWithFiat
value={1.5}
symbol="ETH"
fiatValue={3750}
fiatSymbol="$"
layout="vertical"
/>

// 渲染:
// 1.5 ETH
// ≈ $3,750
```

## Props

### AmountDisplay

```typescript
interface AmountDisplayProps {
value: string | number
symbol?: string // 代币符号
decimals?: number // 小数位 (默认 8)
sign?: 'auto' | 'always' | 'never' // 正负号
color?: 'auto' | 'default' | 'positive' | 'negative'
compact?: boolean // 紧凑模式 (1K, 1M, 1B)
hidden?: boolean // 隐私模式
loading?: boolean // 加载态
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
weight?: 'normal' | 'medium' | 'semibold' | 'bold'
mono?: boolean // 等宽字体 (默认 true)
animated?: boolean // 动画 (默认 true)
fixedDecimals?: boolean | 'auto' // 小数位模式
className?: string | ((state: State) => string)
style?: CSSProperties | ((state: State) => CSSProperties)
}

interface AmountDisplayState {
isNegative: boolean
isZero: boolean
isLoading: boolean
isHidden: boolean
}
```

### AmountWithFiat

```typescript
interface AmountWithFiatProps extends AmountDisplayProps {
fiatValue?: string | number
fiatSymbol?: string // 默认 '$'
fiatDecimals?: number // 默认 2
layout?: 'vertical' | 'horizontal'
}
```

## 紧凑模式阈值

```typescript
if (value >= 1_000_000_000) return `${value / 1e9}B`
if (value >= 1_000_000) return `${value / 1e6}M`
if (value >= 1_000) return `${value / 1e3}K`
```

## 小数位规则

| 资产类型 | 默认精度 | 最大精度 |
|---------|---------|---------|
| 法币 (USD, CNY) | 2 | 2 |
| 主流币 (ETH, BTC) | 4 | 8 |
| 代币 (ERC20) | 4 | 18 |
| BioForest 链 | 4 | 8 |

## fixedDecimals 模式

| 值 | 行为 |
|---|------|
| `false` | 隐藏尾随零 |
| `true` | 显示完整小数位 |
| `'auto'` | 根据容器宽度自适应 |

## 场景对照表

| 场景 | 推荐配置 |
|------|---------|
| 转账确认 | `fixedDecimals={true}` |
| 钱包余额 | `fixedDecimals="auto"` |
| 交易列表 | `fixedDecimals={false}` |
| 资产统计 | `compact={true}` |
Loading