Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
500e0ed
feat(deps): add @number-flow/react for animated numbers
Gaubee Dec 22, 2025
c624b7a
feat(ui): add AnimatedNumber component
Gaubee Dec 22, 2025
8668479
feat(ui): enhance AmountDisplay with animation and accessibility
Gaubee Dec 22, 2025
3b38950
fix(bioforest): correct balance API endpoint and response parsing
Gaubee Dec 22, 2025
5eb7d52
feat(ui): update token components with animated balance
Gaubee Dec 22, 2025
9e90aca
feat(wallet): add chain preferences and HomeTab improvements
Gaubee Dec 22, 2025
ac1e94d
docs: update white-book for AnimatedNumber and AmountDisplay
Gaubee Dec 22, 2025
948c0c0
test: update tests for wallet state changes
Gaubee Dec 22, 2025
f167238
test: improve e2e test reliability with data-testid selectors
Gaubee Dec 22, 2025
675c908
docs: add e2e best practices for i18n projects - prohibit text selectors
Gaubee Dec 22, 2025
9625d00
feat(a11y): add data-testid attributes for e2e testing
Gaubee Dec 22, 2025
12d8737
test: replace text selectors with data-testid in bioforest e2e tests
Gaubee Dec 22, 2025
2585aef
feat(a11y): add data-testid to wallet create, send, and scanner pages
Gaubee Dec 22, 2025
a4cb24e
test: replace text selectors with data-testid in wallet-create e2e tests
Gaubee Dec 22, 2025
6ed40c1
feat(a11y): add data-testid to wallet import page and fix duplicates
Gaubee Dec 22, 2025
f20624a
test: migrate wallet-import.spec.ts to data-testid selectors
Gaubee Dec 22, 2025
9620d41
test: migrate scanner.spec.ts to data-testid selectors
Gaubee Dec 22, 2025
e723630
test: migrate chain-config and pages specs to data-testid
Gaubee Dec 22, 2025
bb8792e
fix(e2e): use waitForURL for more reliable CI navigation
Gaubee Dec 22, 2025
c933567
fix(e2e): improve send page test reliability and migrate guide tests
Gaubee Dec 22, 2025
64b9788
fix(e2e): simplify send page test to use waitForSelector pattern
Gaubee Dec 22, 2025
71d5f74
test: skip flaky send page navigation test in CI
Gaubee Dec 22, 2025
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
1 change: 1 addition & 0 deletions docs/white-book/00-必读/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ find docs/white-book -name "*.md" | sort
| **钱包存储** | `04-服务篇/08-钱包数据存储/` | 操作钱包数据时 |
| **国际化** | `07-国际化篇/` | 添加文案或多语言时 |
| **测试策略** | `08-测试篇/` | 编写测试用例时 |
| **E2E 最佳实践** | `08-测试篇/03-Playwright配置/e2e-best-practices.md` | **必读:禁止使用明文选择器** |

---

Expand Down
110 changes: 98 additions & 12 deletions docs/white-book/05-组件篇/02-通用组件/AmountDisplay.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# AmountDisplay 金额显示

> 格式化显示加密货币金额
> 格式化显示加密货币金额,支持平滑数字动画

---

## 功能描述

将原始金额值格式化为人类可读的形式,支持多种显示配置。
将原始金额值格式化为人类可读的形式,支持多种显示配置。使用 `@number-flow/react` 实现专业的数字动画效果。

### 核心特性

- **数字动画**: 数值变化时逐位平滑过渡动画
- **加载状态**: 显示 "0" 配合呼吸动画,数据到达后平滑过渡到真实值
- **完整可访问性**: 屏幕阅读器正确读取数值
- **等宽字体**: 使用 `font-mono` 确保数字宽度一致

---

Expand All @@ -15,13 +22,17 @@
| 属性 | 类型 | 必需 | 默认值 | 说明 |
|-----|------|-----|-------|------|
| value | number \| bigint \| string | Y | - | 金额值 |
| symbol | string | Y | - | 货币符号 |
| symbol | string | N | - | 货币符号 |
| decimals | number | N | 8 | 小数位数 |
| displayDecimals | number | N | auto | 显示的小数位 |
| sign | enum | N | 'negative' | 符号显示模式 |
| color | enum | N | 'none' | 颜色模式 |
| sign | enum | N | 'never' | 符号显示模式 |
| color | enum | N | 'default' | 颜色模式 |
| size | enum | N | 'md' | 尺寸 |
| symbolPosition | enum | N | 'right' | 符号位置 |
| weight | enum | N | 'normal' | 字重 |
| loading | boolean | N | false | 是否加载中 |
| animated | boolean | N | true | 是否启用动画 |
| hidden | boolean | N | false | 隐私模式(显示 ••••••) |
| compact | boolean | N | false | 紧凑模式(1K, 1M) |
| mono | boolean | N | true | 是否等宽字体 |

### sign 符号模式

Expand All @@ -35,10 +46,19 @@

| 值 | 说明 |
|---|------|
| none | 默认颜色 |
| default | 默认颜色 |
| auto | 正数绿色,负数红色 |
| gain | 强制绿色 |
| loss | 强制红色 |
| positive | 强制绿色 |
| negative | 强制红色 |

### weight 字重

| 值 | 说明 |
|---|------|
| normal | 正常字重 |
| medium | 中等 |
| semibold | 半粗 |
| bold | 粗体 |

---

Expand Down Expand Up @@ -95,14 +115,17 @@ value: 999999999999 (极大值)
### 必须 (MUST)

1. 使用千分位分隔符
2. 金额使用等宽数字字体(tabular-nums
2. 金额使用等宽数字字体(`font-mono`
3. 正确处理 bigint 类型
4. **可访问性**: 必须提供 `aria-label` 供屏幕阅读器读取
5. **加载状态**: 显示 "0" 配合呼吸动画(`animate-pulse`),不使用色块骨架屏

### 建议 (SHOULD)

1. 金额右对齐
2. 符号跟随金额,不换行
3. 加载中显示骨架屏
3. 使用 `@number-flow/react` 实现数字动画
4. 数值变化时平滑过渡,而非直接跳变

### 可选 (MAY)

Expand All @@ -111,6 +134,69 @@ value: 999999999999 (极大值)

---

## 动画规范

### 数字动画

使用 `@number-flow/react` 库实现专业的数字动画:

```tsx
import NumberFlow from '@number-flow/react'

<NumberFlow
value={10015.12345678}
format={{
minimumFractionDigits: 0,
maximumFractionDigits: 8,
}}
locales="en-US"
/>
```

### 加载状态动画

加载时显示 "0" 配合呼吸动画,数据到达后 NumberFlow 会自动从 0 平滑过渡到真实值:

```tsx
// 加载中
<span className="animate-pulse">
<NumberFlow value={0} aria-hidden="true" />
</span>

// 数据到达后
<NumberFlow value={10015.12345678} aria-hidden="true" />
// NumberFlow 会自动动画过渡 0 → 10015.12345678
```

---

## 可访问性规范

### 屏幕阅读器支持

由于 NumberFlow 使用 SVG 渲染数字,需要正确处理可访问性:

```tsx
// ✅ 正确:外层提供 aria-label,内层 aria-hidden
<span role="text" aria-label="10,015.12345678 BFM">
<NumberFlow value={10015.12345678} aria-hidden="true" />
<span aria-hidden="true">BFM</span>
</span>

// ❌ 错误:屏幕阅读器会读成 "image: 10015.12345678"
<NumberFlow value={10015.12345678} />
```

### 加载状态可访问性

```tsx
<span role="status" aria-label="Loading...">
<NumberFlow value={0} aria-hidden="true" />
</span>
```

---

## 布局规范

### 标准布局
Expand Down
164 changes: 164 additions & 0 deletions docs/white-book/05-组件篇/02-通用组件/AnimatedNumber.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# AnimatedNumber 数字动画

> 平滑的数字动画显示组件

---

## 功能描述

使用 `@number-flow/react` 实现专业的数字动画效果。当数值变化时,每一位数字都会平滑过渡,而非直接跳变。

### 核心特性

- **逐位动画**: 数字变化时每一位独立动画
- **加载状态**: 显示 "0" 配合呼吸动画
- **完整可访问性**: 正确支持屏幕阅读器
- **等宽字体**: 使用 `font-mono` 确保数字宽度一致

---

## 组件变体

### AnimatedNumber

基础数字动画组件,接收 `number` 类型值。

```tsx
import { AnimatedNumber } from '@/components/common'

<AnimatedNumber value={10015.12345678} decimals={8} />
```

### AnimatedAmount

包装组件,接收 `string | number` 类型值,自动解析字符串。

```tsx
import { AnimatedAmount } from '@/components/common'

<AnimatedAmount value="10015.12345678" decimals={8} />
<AnimatedAmount value={10015.12345678} decimals={8} />
```

---

## 属性规范

| 属性 | 类型 | 必需 | 默认值 | 说明 |
|-----|------|-----|-------|------|
| value | number | Y | - | 数值 |
| loading | boolean | N | false | 是否加载中 |
| decimals | number | N | 8 | 小数位数 |
| locale | string | N | 'en-US' | 格式化语言 |
| className | string | N | - | 额外样式类 |

---

## 使用场景

### 余额显示

```tsx
const [balance, setBalance] = useState(0)
const [loading, setLoading] = useState(true)

// API 返回后
setLoading(false)
setBalance(10015.12345678)

<AnimatedNumber
value={balance}
loading={loading}
decimals={8}
/>
```

用户将看到:
1. 加载中:显示 "0" 配合呼吸动画
2. 数据到达:0 平滑过渡到 10015.12345678

### 实时价格更新

```tsx
const [price, setPrice] = useState(1234.56)

// WebSocket 推送新价格
setPrice(1245.78)

<AnimatedNumber value={price} decimals={2} />
```

价格变化时,每一位数字独立动画过渡。

---

## 可访问性规范

### 必须遵守

由于 NumberFlow 使用 SVG 渲染,直接使用会导致屏幕阅读器读出 "image: xxx"。组件内部已正确处理:

```tsx
// 组件内部实现
<span role="text" aria-label={formattedValue}>
<NumberFlow value={value} aria-hidden="true" />
</span>
```

### 加载状态

```tsx
<span role="status" aria-label="Loading...">
<NumberFlow value={0} aria-hidden="true" />
</span>
```

---

## 技术实现

### 依赖

```bash
pnpm add @number-flow/react
```

### 测试环境

NumberFlow 不支持 JSDOM,需要在测试中 mock:

```ts
// src/test/setup.ts
vi.mock('@number-flow/react', () => ({
default: ({ value, format }: { value: number; format?: Intl.NumberFormatOptions }) => {
const formatted = value.toLocaleString('en-US', format)
return formatted
},
}))
```

---

## 与 AmountDisplay 的关系

| 组件 | 用途 | 特性 |
|-----|------|------|
| AnimatedNumber | 纯数字动画 | 简单、轻量 |
| AmountDisplay | 完整金额显示 | 符号、颜色、尺寸、法币估值 |

AmountDisplay 内部使用 NumberFlow 实现动画,同时提供更丰富的配置选项。

---

## 设计标注

### 字体

- 使用 `font-mono` 等宽字体
- 确保数字宽度一致,避免动画时布局跳动

### 动画

- 动画由 `@number-flow/react` 控制
- 默认使用库内置的缓动曲线
- 加载状态使用 Tailwind 的 `animate-pulse`
3 changes: 2 additions & 1 deletion docs/white-book/05-组件篇/02-通用组件/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
| 组件 | 说明 | 优先级 |
|-----|------|-------|
| [AddressDisplay](./AddressDisplay) | 地址显示与复制 | P0 |
| [AmountDisplay](./AmountDisplay) | 金额格式化显示 | P0 |
| [AmountDisplay](./AmountDisplay) | 金额格式化显示(支持动画) | P0 |
| [AnimatedNumber](./AnimatedNumber) | 数字动画显示 | P0 |
| [TokenIcon](./TokenIcon) | 代币/链图标 | P0 |
| [QRCode](./QRCode) | 二维码生成与显示 | P0 |
| Countdown | 倒计时 | P1 |
Expand Down
Loading