# Tamagui 设计系统

## Tamagui 设计系统界面预览

添加习惯、标记进度、筛选未完成项目，并切换蓝色主题。

## Tamagui 设计系统设计参考

@tamagui/config/v5 和 @tamagui/themes 2.7.7 导出的值，以及已验证的原生组件约定。

### v5 尺寸令牌

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| size.$1 | 20 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| size.$2 | 28 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| size.$3 | 36 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| size.$4 | 44 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| size.$5 | 52 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| size.$6 | 64 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
### v5 间距令牌

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| space.$1 | 2 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$1.5 | 4 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$2 | 7 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$2.5 | 10 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$3 | 13 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$3.5 | 16 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$4 | 18 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$5 | 24 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| space.$6 | 32 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
### v5 圆角令牌

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| radius.0 | 0 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| radius.1 | 3 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| radius.2 | 5 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| radius.3 | 7 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| radius.4 | 9 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| radius.5 | 10 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
| radius.6 | 16 | 实际的 v5 配置值。同一个数字令牌标签在尺寸、间距和圆角中的含义各不相同；不要将 $4 视为通用像素值。 |
### light_blue 语义主题

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| light_blue.background | hsla(207, 100%, 98%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| light_blue.backgroundHover | hsla(210, 100%, 99%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| light_blue.backgroundPress | hsla(205, 92%, 95%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| light_blue.color | hsla(216, 71%, 23%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| light_blue.borderColor | hsla(203, 100%, 92%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| light_blue.borderColorFocus | hsla(203, 100%, 92%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| light_blue.placeholderColor | hsla(206, 100%, 50%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
### dark_blue 语义主题

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| dark_blue.background | hsla(218, 39%, 11%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| dark_blue.backgroundHover | hsla(212, 69%, 16%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| dark_blue.backgroundPress | hsla(215, 42%, 9%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| dark_blue.color | hsla(205, 100%, 88%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| dark_blue.borderColor | hsla(209, 100%, 19%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| dark_blue.borderColorFocus | hsla(209, 100%, 19%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
| dark_blue.placeholderColor | hsla(206, 100%, 50%, 1) | 从 v5 蓝色主题解析出的语义角色。组件可能会为悬停、按压或激活状态选择更具体的子主题。 |
### 系统字体角色

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| body.family | -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif | v5 系统字体栈无需请求远程字体。 |
| body.$2 | 13px / 20px | 字号与行高配对构成字体角色，独立于具有相同标签的组件尺寸令牌。 |
| body.$3 | 14px / 21px | 字号与行高配对构成字体角色，独立于具有相同标签的组件尺寸令牌。 |
| body.$4 | 15px / 23px | 字号与行高配对构成字体角色，独立于具有相同标签的组件尺寸令牌。 |
| body.$5 | 16px / 24px | 字号与行高配对构成字体角色，独立于具有相同标签的组件尺寸令牌。 |
| body.$6 | 18px / 27px | 字号与行高配对构成字体角色，独立于具有相同标签的组件尺寸令牌。 |
| body.$8 | 26px / 38px | 字号与行高配对构成字体角色，独立于具有相同标签的组件尺寸令牌。 |
### 原生组合约定

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| createTamagui | defaultConfig from @tamagui/config/v5 | 在 React 外部创建一个配置实例；getCSS() 提供 Web 主题 CSS。 |
| TamaguiProvider | config + defaultTheme | 应用选择浅色或深色外观，同时保留看板状态。 |
| Theme | name="blue" | 解析当前外观对应的蓝色子主题。 |
| Checkbox | checked + onCheckedChange | 看板仅将 value === true 视为已完成；不确定状态不代表完成。 |
| Input | value + onChangeText | 受控草稿、去除首尾空格后校验，并明确处理重复项。 |
| Progress | value from 0 to 100 | 进度指示器根据已完成数除以总行数计算得出。 |
| YStack / XStack | directional layout with token gap | 保持阅读布局自适应，无需另写仿制样式表。 |
## Tamagui 设计系统完整指南

实用指南，介绍如何为真实界面选择、应用和评审此系统。

完整指导、实现起点和源代码链接。

## Tamagui 设计系统版本化配置与 CSS

### 使用指定的 v5 预设

> 此示例固定使用 tamagui 和 @tamagui/config 的 2.7.7 版本，并从 @tamagui/config/v5 导入 defaultConfig。配置名称是 v5，并非 npm 包的主版本号。混淆这两个数字会导致读者使用错误的安装命令。createTamagui 在组件外运行一次，其生成的 CSS 会在界面板渲染前插入，确保主题变量和原生样式在 Web 上有实际定义。

### 明确说明小型配置覆写

提供的源代码将 onlyAllowShorthands 设为 false，因为此教学示例使用 padding 和 backgroundColor 等易读的完整属性名。这是基于预设做出的应用层选择。v5 基础配置不包含动画驱动程序，此示例也不会凭空添加驱动程序或声称支持动画过渡。简单的进度和复选框交互无需额外添加动画依赖。

## Tamagui 设计系统尺寸、间距与圆角令牌

### 不要混淆名称相同的令牌

在固定使用的 v5 配置中，尺寸令牌 $4 为 44，间距令牌 $4 为 18，圆角令牌 4 为 9。因此，组件尺寸、布局间距和圆角不能通过同一套乘数规则换算。参考内容分别列出各个类别，示例则通过实际的 Tamagui 属性使用对应类别的值。这比罗列配置中并未采用的通用 4px 增量更实用。

- size.$4 = 44

- space.$4 = 18

- radius.4 = 9

- 正文文本字体 $4 = 15px，行高为 23px

### 字号比例也应单独处理

正文文本字体 $4 为 15px，行高为 23px，而组件尺寸 $4 仍为 44。系统字体栈由 v5 提供，无需下载字体文件。H1、H2 和 Text 会继承其原生字体上下文；源代码中的显式 fontSize 和 lineHeight 值决定了原界面板的层级。外层宽度 880px 是本地布局选择，并非全局 Tamagui 令牌。

## Tamagui 设计系统语义主题与外观

### 将浅色或深色外观与蓝色子主题组合

TamaguiProvider 接收所选的 defaultTheme，Theme name="blue" 则解析对应的子主题。源代码使用 background、backgroundHover、color 和 borderColor 角色，避免在整个组件树中反复填写十六进制颜色值。表格列出实际的 light_blue 和 dark_blue 值，便于读者比较解析后的配置，而不是假设品牌配色只有一套固定值。

### 切换外观时保留界面板状态

dark 标记与行数据、输入草稿和筛选条件相互独立。切换外观会更新原生组件，同时保留界面板内容。按钮和复选框可以选择各自的组件子主题值，因此它们计算出的颜色不一定与父级背景令牌相同。将层级简化为自定义 CSS 前，请先检查渲染后的状态。

## Tamagui 设计系统复选框与派生进度

### 将完成状态保存在同一组行数据中

每一行都有稳定的 ID、易读的文本和 done 布尔值。Checkbox 接收 checked 和 onCheckedChange；只有值严格等于 true 时，项目才会标记为已完成。Checkbox.Indicator 用于显示勾选标记。相邻文本和无障碍名称都指向同一项习惯，删除线则以视觉方式重复呈现已完成状态。源代码不会单独创建一个可能与行数据不同步的计数。

### 根据整个界面板计算进度

根据所有行数据计算已完成数量，再将其转换为百分比并传给 Progress。筛选未完成项目只会改变显示内容，不会改变分母。这样一来，已完成的行从视图中隐藏时，进度条也不会重置。计数还会以易读文本的形式显示在 polite 实时区域中，因此不会只通过进度条长度传达百分比。

## Tamagui 设计系统草稿验证与重复项处理

### 添加真正受控的输入框

Input 通过 value 和 onChangeText 保存当前草稿。“添加习惯”操作会去除首尾空白，并在输入为空时显示提示、设置 aria-invalid 并提供错误说明。空内容提交后，焦点会返回输入框。不区分大小写的重复项检查可防止添加文本相同的第二行，并保留草稿以供修改。这些规则属于原界面板，而非库本身。

### 仅在成功添加后更新界面板

有效的草稿会添加一行新的未完成习惯、清空输入并移除错误。进度分母会立即变化，因为它是根据新列表计算得出的。添加习惯不会注册提醒，也不会创建账户。看板数据有意保存在本地 React 状态中，重新加载文档后会恢复为示例内容。

## Tamagui 设计系统：筛选视图与空状态恢复

### 明确筛选范围

“仅显示未完成项”会隐藏已完成的行，但这些行仍保留在列表中。如果此视图中没有剩余内容，空状态文案会说明完整列表仍然存在，并提供直接返回的操作。这是由用户选择产生的有效空状态，而不是通过切换来替换任意占位卡片的装饰性控件。

### 让重置与外观设置彼此独立

“重置示例看板”会恢复初始的三行内容、清空草稿和错误，并返回完整列表，但不会改变当前外观。由于每项变化都是显式状态，重置时无需重新加载文档，也无需丢弃已配置的提供程序。主题与内容恢复可以分别测试。

## Tamagui 设计系统：响应式堆叠与无障碍阅读

### 让堆叠内容决定高度

YStack 用于布局主要阅读内容流，XStack 用于对齐标题控件、复选框行和操作按钮。控件组会自动换行，而不是强制使用固定的桌面宽度。外层容器最大宽度为 880px，并使用真实的 $4 间距令牌设置内边距。每一行都允许文本收缩和换行，同时确保在 280px 及更大的测试宽度下仍可使用控件。

### 在重新排版后测试交互

浏览器测试会先添加一个习惯、将其标记为已完成、筛选列表并切换外观，然后测量内容是否溢出。仅截取初始布局的屏幕截图，无法发现错误提示、长标签或筛选状态是否会破坏窄屏布局。测试还实际检查了原生复选框语义和可见文本，以及派生的进度值，而不是只确认它们存在就假定功能正常。

## Tamagui 设计系统：完整的浏览器构建

### 提供程序、CSS 和构建定义

这三个提供的文件足以构成本地 Web 示例。JSX 包含提供程序、一份配置、生成的主题 CSS 和完整看板。build.mjs 固定了 Web 目标和生产环境，并为其他仅限浏览器的环境读取提供空的 process.env 回退值。缺少最后这项定义时，即使代码可以编译，这个纯浏览器打包也可能因 process is not defined 而失败。

1. 将 tamagui.jsx、build.mjs 和 index.html 保存在同一目录中。

2. 安装固定版本的 React 和 Tamagui 包。

3. 构建并提供本地目录。

4. 测试空内容和重复项的添加、完成状态、筛选、主题与重置。

### 将原生端与 Web 端的采用方式分开

此示例是在浏览器中组合使用实际 Tamagui 组件。它不能证明原生构建、导航集成或平台特定的输入行为。生产应用应采用所选框架支持的设置方式，并分别评估代码提取、服务端渲染和动画需求。此处提供的本地打包方案足以完整检查这里展示的主题与状态约定。

## Tamagui 设计系统：组件示例

### tamagui.jsx

配置、生成的 CSS、原生组件与完整的看板状态。

```
import React,{useState} from 'react';import{createRoot}from'react-dom/client';
import{createTamagui,TamaguiProvider,Theme,YStack,XStack,Text,H1,H2,Button,Input,Checkbox,Progress,Separator}from'tamagui';import{defaultConfig}from'@tamagui/config/v5';
const config=createTamagui({...defaultConfig,settings:{...defaultConfig.settings,onlyAllowShorthands:false}});const sheet=document.createElement('style');sheet.textContent=config.getCSS();document.head.append(sheet);
const initial=[{id:1,text:'Read ten pages',done:false},{id:2,text:'Step outside for a break',done:true},{id:3,text:'Write one useful note',done:false}];
function App(){const[dark,setDark]=useState(false),[rows,setRows]=useState(initial),[draft,setDraft]=useState(''),[error,setError]=useState(''),[filter,setFilter]=useState(false);const done=rows.filter(x=>x.done).length;let shown=rows.filter(x=>!filter||!x.done);function add(){let text=draft.trim();if(!text){setError('Write a small habit before adding it.');document.querySelector('#habit-input')?.focus();return}if(rows.some(x=>x.text.toLowerCase()===text.toLowerCase())){setError('That habit is already in this list.');return}setRows([...rows,{id:Date.now(),text,done:false}]);setDraft('');setError('')}return <TamaguiProvider config={config} defaultTheme={dark?'dark':'light'}><Theme name="blue"><YStack backgroundColor="$background" color="$color" padding="$4" gap="$4" maxWidth={880} margin="auto" width="100%" minHeight={0}><XStack justifyContent="space-between" alignItems="center" flexWrap="wrap" gap="$3"><Text fontSize="$2" fontWeight="700">TAMAGUI / ORIGINAL HABIT BOARD</Text><Button size="$3" onPress={()=>setDark(!dark)}>{dark?'Light appearance':'Dark appearance'}</Button></XStack><H1 fontSize="$8" lineHeight="$8">A little progress, every day.</H1><Text fontSize="$4" lineHeight="$5">A local board built with Tamagui 2.7.7 and its v5 blue theme. Your changes stay in this page; no account or daily reminder is connected.</Text><YStack backgroundColor="$backgroundHover" borderWidth={1} borderColor="$borderColor" borderRadius="$4" padding="$4" gap="$3"><XStack justifyContent="space-between" gap="$3" flexWrap="wrap"><H2 fontSize="$5">Today’s small steps</H2><Text id="progress-count" aria-live="polite">{done} of {rows.length} complete</Text></XStack><Progress value={rows.length?done/rows.length*100:0} size="$2" aria-label="Completed habits"><Progress.Indicator animation={undefined}/></Progress><Button size="$3" alignSelf="flex-start" onPress={()=>setFilter(!filter)}>{filter?'Show all habits':'Show unfinished only'}</Button><Separator/>{shown.length?shown.map(row=><XStack key={row.id} gap="$3" alignItems="center" paddingVertical="$2"><Checkbox id={'habit-'+row.id} checked={row.done} onCheckedChange={value=>setRows(rows.map(x=>x.id===row.id?{...x,done:value===true}:x))} aria-label={row.text} size="$4"><Checkbox.Indicator><Text fontWeight="700">✓</Text></Checkbox.Indicator></Checkbox><Text flex={1} fontSize="$4" lineHeight="$5" textDecorationLine={row.done?'line-through':'none'} opacity={row.done?.65:1}>{row.text}</Text></XStack>):<YStack gap="$3"><Text fontWeight="700">Nothing unfinished in this view</Text><Text>All your habits remain in the full list. You can revisit any completed item.</Text><Button onPress={()=>setFilter(false)}>Return to all habits</Button></YStack>}</YStack><YStack gap="$3"><Text htmlFor="habit-input" tag="label" fontWeight="700">Add one small habit</Text><Input id="habit-input" value={draft} onChangeText={v=>{setDraft(v);setError('')}} placeholder="For example, stretch for five minutes" aria-describedby={error?'habit-error':undefined} aria-invalid={!!error} onKeyPress={e=>{if(e.nativeEvent.key==='Enter')add()}}/><Text id="habit-error" color="$color" aria-live="polite">{error}</Text><XStack gap="$3" flexWrap="wrap"><Button theme="active" onPress={add}>Add habit</Button><Button onPress={()=>{setRows(initial);setDraft('');setError('');setFilter(false)}}>Reset sample board</Button></XStack></YStack><Text fontSize="$2" lineHeight="$3">Native Checkbox, Input, Button and Progress components; original board content and state. Theme changes preserve the current board.</Text></YStack></Theme></TamaguiProvider>}
createRoot(document.getElementById('root')).render(<App/>);
```

代码参考

- 请将这三个完整文件配套使用。

### build.mjs

测试所用打包文件的浏览器环境定义。

```
import {build} from 'esbuild';
await build({entryPoints:['tamagui.jsx'],bundle:true,minify:true,outfile:'tamagui.bundle.js',define:{'process.env.NODE_ENV':'"production"','process.env.TAMAGUI_TARGET':'"web"','process.env':'{}'}});
```

代码参考

- 请将这三个完整文件配套使用。

### index.html

独立的根文档与打包文件导入。

```
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Small habits board</title><style>body{margin:0}*{box-sizing:border-box}button,input{max-width:100%}</style></head><body><div id="root"></div><script src="./tamagui.bundle.js"></script></body></html>
```

代码参考

- 请将这三个完整文件配套使用。

## Tamagui 设计系统：AI Agent 设置

### 实现起点

先保存提供的文件，然后打开 http://localhost:8000/。此设置专用于浏览器。

```
npm init -y
npm install react@19.2.0 react-dom@19.2.0 tamagui@2.7.7 @tamagui/config@2.7.7
npm install --save-dev esbuild
node build.mjs
python3 -m http.server 8000
```

### 适用于你项目的提示词

```
使用 v5 预设，实现完整的 Tamagui 2.7.7 Web 习惯看板。保持尺寸、间距、圆角和字体令牌类别彼此独立；保留生成的主题 CSS、浅色与深色蓝色子主题、受控复选框、去除首尾空格与重复项验证、包含所有行的进度分母、未完成视图的恢复功能，以及不改变外观的重置功能。
```

## Tamagui 设计系统：来源与范围

使用 v5 预设的实际 Tamagui 2.7.7 Web 组件。习惯看板及其状态规则为原创 OpenDesign 代码；未连接账户、提醒或原生设备行为。

- 配置 提供程序、预设与配置的职责。

- 令牌 按类别解析令牌。

- 复选框 受控状态与指示器结构。

- 进度 进度值与指示器组合。

- 官方安装指南 框架与平台的设置选项。

## Tamagui 设计系统：相关资源

### UIkit

UIkit 结合了 CSS 框架、Less 自定义配置和由属性驱动的 JavaScript 组件。下方的工作坊规划器展示了 Switcher、Accordion 和响应式网格如何协同工作，并说明原生组件行为与应用选择状态的边界。

### Vant

使用 Vant 4 构建移动端地址选择流程：采用真实的 CSS 变量、受控的地址标识、字段验证、主题切换，以及明确的仅本地保存功能。

### Vuestic UI

原生 Vuestic 评价表，采用经来源核实的浅色和深色预设、无障碍评分标签、文本区域验证、自动计算的平均分，以及可保留已完成评估的保存状态。


- [实现参考](https://tamagui.dev/docs/core/configuration)
- [来源](https://cdn.jsdelivr.net/npm/@tamagui/themes@2.7.7/src/v5-tokens.ts)
- [来源](https://cdn.jsdelivr.net/npm/@tamagui/themes@2.7.7/src/generated-v5.ts)
- [来源](https://cdn.jsdelivr.net/npm/@tamagui/config@2.7.7/src/v5-fonts.ts)
- [来源](https://tamagui.dev/docs/core/configuration)
- [代码参考](https://tamagui.dev/docs/core/configuration)
- [配置 提供程序、预设与配置的职责。](https://tamagui.dev/docs/core/configuration)
- [令牌 按类别解析令牌。](https://tamagui.dev/docs/core/tokens)
- [复选框 受控状态与指示器结构。](https://tamagui.dev/ui/checkbox)
- [进度 进度值与指示器组合。](https://tamagui.dev/ui/progress)
- [官方安装指南 框架与平台的设置选项。](https://tamagui.dev/docs/intro/installation)
