# Twilio Paste 设计系统

## Twilio Paste 设计系统界面预览

编辑内容、查看手机预览，并准备单独的本地快照。

## Twilio Paste 设计系统设计参考

已核实上游 twilio-labs/paste 来源。下方取值区分了 YAML 令牌名称与其 JavaScript 风格名称。本参考不会将独立的 Paste DSys 分支说成 Twilio 文档。

### 间距别名

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| space10 | 0.125rem | 以 16px 根字号计算为 2px。 |
| space20 | 0.25rem | 以 16px 根字号计算为 4px。 |
| space30 | 0.5rem | 字段间距为 8px。 |
| space40 | 0.75rem | 控件内边距为 12px。 |
| space50 | 1rem | 16px，用于局部分组。 |
| space60 | 1.25rem | 20px。 |
| space70 | 1.5rem | 24px，用于区块间隔。 |
| space90 | 2rem | 32px，用于较大的分组。 |
| space130 | 3rem | 48px，用于更大的区域。 |
### 字体大小别名

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| fontSize20 | 0.75rem | 默认根字号为 12px。 |
| fontSize30 | 0.875rem | 14px 正文选项。 |
| fontSize40 | 1rem | 16px 正文选项。 |
| fontSize60 | 1.25rem | 20px 标题选项。 |
| fontSize70 | 1.5rem | 24px 标题选项。 |
| fontSize90 | 2rem | 32px 展示文字选项。 |
### 行高

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| lineHeight20 / lineHeight30 | 1.25rem | 20px，适用于紧凑文本。 |
| lineHeight40 | 1.5rem | 24px，适用于 16px 文本。 |
| lineHeight60 | 1.75rem | 28px，适用于 20px 文本。 |
| lineHeight70 | 2rem | 32px，适用于 24px 文本。 |
### 圆角

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| borderRadius10 | 2px | 最小圆角。 |
| borderRadius20 | 4px | 小型控件圆角。 |
| borderRadius30 | 8px | 中小型圆角。 |
| borderRadius40 | 12px | 中圆角。 |
| borderRadiusCircle | 50% | 圆形要求宽度和高度相等。 |
| borderRadiusPill | 100px | 胶囊形圆角，与圆形不同。 |
### 文本角色与搭配

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| colorText | palette-gray-100 | 主要正文；在关联调色板中解析为 #121c2d。 |
| colorTextWeak | palette-gray-60 | 次要文本；在关联调色板中解析为 #606b85。 |
| colorTextLink | palette-blue-60 | 链接；在关联调色板中解析为 #0263e0。 |
| colorTextError | palette-red-60 | 错误文本；在关联调色板中解析为 #db132a。 |
| colorTextSuccess | palette-green-70 | 成功文本；在关联调色板中解析为 #0e7c3a。 |
| colorTextWeaker | palette-gray-40 | 源码警告不要将其用于普通的启用状态文本。 |
### 按钮行为

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| variant | primary / secondary / destructive / link and other explicit variants | 示例使用了主要提交按钮和次要切换按钮。 |
| type | button by default | 表单提交时应显式设置 submit。 |
| pressed | Secondary family only | 主题切换使用次要按钮。 |
| loading | aria-busy and disabled control behavior | 仅在确实有待处理操作时使用。 |
| as="a" | Requires href | 导航链接不支持按钮的禁用或加载状态。 |
| tabIndex | 0 or -1 | 不接受正数 tabindex。 |
### 主题名称

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| default / dark | Theme variants | 主题选择是显式的。 |
| twilio / twilio-dark | Separate variants | 不要将每种变体都描述为与默认主题完全相同。 |
| sendgrid / evergreen | Additional variants | 应有意选择主题，而不是把品牌主题当作随意的装饰。 |
## Twilio Paste 设计系统完整指南

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

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

## Twilio Paste 设计系统：使用上游系统时，勿与文档分支混淆

### Twilio 源码与独立延续项目

> Paste 发布在 twilio-labs 仓库中。核验期间，旧的 paste.twilio.design 文档路由会重定向到该仓库。独立托管的 Paste DSys 网站称自己是与 Twilio 无关联的独立分支。因此，本指南依据上游源文件说明设计令牌值和组件行为。

通知编辑器是一个很实用的示例，因为它展示了静态按钮图库无法涵盖的多种状态：可编辑内容、确认审阅、已准备好的快照，以及发送前的明确边界。此预览不会调用任何 Twilio API。

阅读配套规范

## Twilio Paste 设计系统：选择后缀前先了解间距比例

### 令牌编号是名称，不是像素值

space30 是半个 rem，而 space70 是一个半 rem。后缀 30 和 70 表示比例中的位置，并非 30px 和 70px。在根字号为 16px 时，编辑器可以在标签与输入框之间使用 8px、控件内部使用 12px、区域之间使用 24px。

YAML 源文件使用连字符命名。参考表则展示 Paste 使用者采用的 JavaScript 样式名称，并列出解析后的值。基于 rem 的值会随根字号缩放；其像素等效值不应被视为浏览器中恒定不变的测量值。

阅读配套规范

## Twilio Paste 设计系统：字体大小应与独立的行高令牌搭配使用

### 比例中的编号并不代表数值相同

字体大小和行高别名彼此独立。默认根字号下，fontSize30 为 14px，而 lineHeight30 为 20px。fontSize70 为 24px，并有 32px 的行高选项。这些组合让标签和多行内容保持易读，同时避免把每个区块都变成大型营销标题。

嵌入式示例使用系统无衬线字体栈，以及由应用提供的手机插图。这些选择明确仅供示意。示例未重新分发任何专有字体文件，也未将手机边框尺寸标示为 Paste 设计令牌。

阅读配套规范

## Twilio Paste 设计系统：语义文本角色包含对比度限制

### 弱化文本不等同于禁用文本

上游颜色源码会记录各文本角色对应的对比度搭配。主要文本、次要文本、错误消息和成功消息各有不同的预期前景色角色。对于较弱的文本角色，源码警告不要将其用于普通的启用状态控件。字符计数等弱化信息不应直接使用最浅的灰色。

在示例中，蓝色表示操作，深色中性文本承载消息。草稿准备就绪后，不会仅仅因为用户按下按钮就变成绿色：其状态说明创建的是本地快照。示例值依据关联调色板；其他主题变体的解析结果可能有所不同。

阅读配套规范

## Twilio Paste 设计系统：主题选择是显式的状态变更

### Provider 变体与应用界面表面

Theme 会导出 Provider、Consumer、具名主题对象和实用工具。当前变体常量包括 default、dark、twilio、twilio-dark、sendgrid 和 evergreen。此示例有意仅在 default 与 dark 之间切换。

当主题提供器发生变化时，应用自有控件需要匹配的表面样式。主题提供器可以为 Paste 组件设置主题，但不会自动为所有外部控件重新设置样式。提供的代码显式设置周围区域的前景色和背景色，并标明文本区域归应用所有。

阅读配套规范

## Twilio Paste Paste 设计系统：仅在受支持的按钮类型上使用按下状态

### 操作、导航和待处理工作各有不同约定

Button 实现会验证某些属性组合。主题切换按钮使用 secondary 和 pressed。表单操作设置 type="submit"，因为该组件默认的类型是 button。锚点样式的按钮必须设置 href，不能将其当作禁用或加载中的操作。

- 使用 primary 来准备草稿，使用 secondary 来切换独立的主题。

- 导航应使用链接；不要在按钮上设置 href，除非使用相应的锚点形式。

- 只有在操作确实待处理时才使用 loading，因为它会同时改变忙碌和禁用行为。

- 避免使用正数 tabIndex；实现仅支持 0 和 -1。

阅读配套规范

## Twilio Paste Paste 设计系统：将可编辑内容与已审核快照分开

### 如实呈现操作顺序

实时预览会跟随当前文本区域的值。准备好的副本会单独存储，只有通过验证后才会更新。再次编辑时，不应悄然改写此前准备好的快照。审核复选框仅用于本地交互演示，并不代表收件人已同意，也不代表符合相关法律要求。

1. 在带有标签的文本区域中撰写内容。

2. 检查当前消息，并勾选本地审核复选框以确认。

3. 准备快照，不调用任何消息服务。

4. 再次编辑，并在准备新的快照前，将草稿与已准备的副本进行比较。

阅读配套规范

## Twilio Paste Paste 设计系统：让反馈一目了然，无需解读手机模型

### 说明标签和文本反馈位于插图之外

文本区域有清晰可见的标签，并关联字符计数和错误说明。字符计数按 Unicode 码点计算，不代表短信分段、编码方式或费用。准备好的结果也会以普通文本形式显示在示意设备之外。

验证必须指出消息为空或尚未确认审核。状态区域会播报本地操作结果，不会让人误以为消息已发送。所有原生控件和按钮（包括窄视口下的控件和按钮）都应保持清晰可见的键盘焦点。

阅读配套规范

## Twilio Paste Paste 设计系统：单独验证软件包与离线演示

### 所提供示例能够证明的内容

此配置导入了真实的 Paste Theme 和 Button 软件包，并提供完整的 React 组合。原生表单控件明确标为应用自有控件，而非未经验证地归属于某个组件 API。内嵌版本是离线的 HTML 演示，不依赖外部 CDN。

在服务中使用之前，请先解决对等依赖、构建原生示例，并为发送功能添加真正的后端边界。本地预览测试成功只能证明编辑器行为正常，并不能证明已集成生产环境的消息服务，也不能据此声称 Twilio 已成功送达消息。

阅读配套规范

## Twilio Paste Paste 设计系统组件示例

### 完整的独立交互示例

将完整文档保存为 index.html 并在浏览器中打开。这是对上游 Paste 尺度规则和按钮状态规则的离线 HTML 演示，并非原生运行时或消息服务。

```
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Paste notification draft studio</title><style>
*{box-sizing:border-box}body{margin:0;background:#f4f4f6;color:#121c2d;font:14px/20px Arial,sans-serif}header{background:#121c2d;color:white;padding:20px 32px;display:flex;justify-content:space-between;gap:16px}.brand{font-weight:700;letter-spacing:.02em}header small{color:#cacdd8}main{max-width:1000px;padding:32px;margin:auto}h1{font-size:28px;line-height:40px;margin:0 0 8px}h2{font-size:18px;line-height:28px;margin:0 0 16px}.intro{color:#606b85;margin:0 0 32px}.layout{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:32px}form{background:white;border:1px solid #e1e3ea;border-radius:8px;padding:24px}label{display:block;font-weight:600}textarea{width:100%;font:16px/24px Arial,sans-serif;border:1px solid #8891aa;border-radius:4px;padding:12px;margin-top:8px;resize:vertical;min-height:150px}textarea:focus,button:focus-visible,input:focus-visible{outline:3px solid #0263e0;outline-offset:3px}.count{color:#606b85;font-size:12px;line-height:20px}.review{display:flex;align-items:start;gap:8px;margin-top:24px}.review label{font-weight:400}.review input{width:16px;height:16px;accent-color:#0263e0}button{font:600 14px/20px Arial,sans-serif;cursor:pointer;border:1px solid #0263e0;border-radius:4px;padding:10px 16px;background:#0263e0;color:white}button:hover{background:#043cb5}button.secondary{background:white;color:#0263e0}.error{color:#ad1111;min-height:20px}aside{text-align:center}.phone{margin:auto;background:white;border:8px solid #121c2d;border-radius:32px;min-height:400px;padding:24px 12px;box-shadow:0 12px 32px #121c2d14}.notch{width:72px;height:5px;background:#121c2d;border-radius:8px;margin:0 auto 24px}.sender{font-size:12px;color:#606b85;padding-bottom:16px;border-bottom:1px solid #e1e3ea}.bubble{background:#ebf4ff;border-radius:12px;padding:12px;margin-top:24px;text-align:left;white-space:pre-wrap;overflow-wrap:anywhere;min-height:70px}.caption{font-size:12px;color:#606b85}.prepared{padding:24px;background:#fff;border:1px solid #e1e3ea;border-radius:8px;margin-top:24px}.prepared p{white-space:pre-wrap;overflow-wrap:anywhere}.status{color:#606b85;font-size:12px}.foot{font-size:12px;color:#606b85;margin-top:24px}@media(max-width:650px){header{padding:16px}main{padding:24px 16px}.layout{grid-template-columns:1fr}.phone{max-width:250px;min-height:300px}form{padding:20px}.intro{margin-bottom:24px}}
</style><header><span class="brand">Paste / Message studio</span><small>Local preview</small></header><main><h1>Notification draft</h1><p class="intro">Write the message. Review the copy. Keep a prepared version.</p><div class="layout"><div><form id="composer" novalidate><h2>Compose your message</h2><label for="message">Message</label><textarea id="message" aria-describedby="count error">Your appointment is confirmed for Thursday at 10:00.</textarea><p id="count" class="count"></p><div class="review"><input id="reviewed" type="checkbox"><label for="reviewed">I reviewed this draft</label></div><p id="error" class="error" role="alert"></p><button>Prepare local draft</button></form><section class="prepared"><h2>Prepared copy</h2><p id="snapshot">No draft prepared yet.</p><p class="status" id="status" role="status">Nothing has been sent.</p></section></div><aside><div class="phone" aria-label="Illustrative phone preview"><div class="notch"></div><div class="sender">Sample service · Preview</div><div class="bubble" id="bubble"></div></div><p class="caption">Live preview of the editable message</p></aside></div><p class="foot">HTML interpretation of upstream Paste · Counts Unicode code points, not SMS segments · No messaging connection</p></main><script>
const $=id=>document.getElementById(id);function update(){$('bubble').textContent=$('message').value||'Your message will appear here.';$('count').textContent=Array.from($('message').value).length+' Unicode code points. Not an SMS segment estimate.'}$('message').oninput=()=>{update();$('reviewed').checked=false};$('composer').onsubmit=e=>{e.preventDefault();$('error').textContent='';$('message').removeAttribute('aria-invalid');if(!$('message').value.trim()){$('error').textContent='Write a message before preparing a draft.';$('message').setAttribute('aria-invalid','true');$('message').focus();return}if(!$('reviewed').checked){$('error').textContent='Confirm that you reviewed the message.';$('reviewed').focus();return}$('snapshot').textContent=$('message').value.trim();$('status').textContent='Draft prepared locally. Nothing was sent.'};update();
</script></html>
```

代码参考

- 手机面板显示草稿快照。不发送短信；原生 Paste Theme 和 Button 行为需要使用单独的 React 示例。

### 使用真实 Paste 主题和按钮状态的本地草稿

Theme.Provider 包裹整个内容编辑器。secondary 的 pressed 状态会更改预览主题；primary 提交按钮会在应用完成验证后准备快照。标签、文本区域和复选框均明确标为应用原生控件。

```
// npm install @twilio-paste/button @twilio-paste/theme react react-dom
import React, {useState} from 'react';
import {createRoot} from 'react-dom/client';
import {Theme} from '@twilio-paste/theme';
import {Button} from '@twilio-paste/button';
// Native textarea and labels are application-owned; this is not Paste TextArea.
function Composer() {
  const [message,setMessage] = useState('Your appointment is confirmed for Thursday at 10:00.');
  const [snapshot,setSnapshot] = useState('');
  const [error,setError] = useState('');
  const [confirmed,setConfirmed] = useState(false);
  const [mode,setMode] = useState('default');
  const length = Array.from(message).length;
  const background = mode === 'dark' ? '#121c2d' : '#ffffff';
  const foreground = mode === 'dark' ? '#ffffff' : '#121c2d';
  function prepare(event) {
    event.preventDefault();
    if (!message.trim()) return setError('Write a message before preparing a draft.');
    if (!confirmed) return setError('Confirm that you reviewed the message.');
    setError(''); setSnapshot(message.trim());
  }
  return <Theme.Provider theme={mode}>
    <main style={{padding:24,background,color:foreground,maxWidth:760,margin:'auto'}}>
      <h1>Notification draft</h1>
      <Button variant="secondary" pressed={mode==='dark'} onClick={() => setMode(mode==='dark'?'default':'dark')}>Dark preview</Button>
      <form onSubmit={prepare}>
        <label htmlFor="message" style={{display:'block',marginTop:24}}>Message</label>
        <textarea id="message" rows={5} value={message} onChange={e=>{setMessage(e.target.value);setConfirmed(false);}}
          aria-describedby="count error" aria-invalid={!!error}
          style={{width:'100%',padding:12,margin:'8px 0',font:'inherit',borderRadius:4}} />
        <p id="count">{length} Unicode code points. This is not an SMS segment estimate.</p>
        <label><input type="checkbox" checked={confirmed} onChange={e=>setConfirmed(e.target.checked)} /> I reviewed this draft</label>
        <p id="error" role="alert">{error}</p>
        <Button variant="primary" type="submit">Prepare local draft</Button>
      </form>
      <section aria-label="Prepared draft" style={{marginTop:24}}>
        <h2>Prepared copy</h2>
        <p style={{whiteSpace:'pre-wrap'}}>{snapshot || 'No draft prepared yet.'}</p>
        <p role="status">{snapshot ? 'Draft prepared locally. Nothing was sent.' : ''}</p>
      </section>
    </main>
  </Theme.Provider>;
}
createRoot(document.getElementById('root')).render(<Composer />);
```

代码参考

- 此示例不会声称原生控件就是 Paste TextArea 组件。

- 字符计数按 Unicode 码点计算，不代表短信分段、编码单元或计费量。

- 原生软件包示例已通过源码检查；离线 HTML 预览则单独测试。

## Twilio Paste Paste 设计系统 Agent 配置

### 实现起点

使用上方完整的 React 入口，并提供一个根元素。模块化软件包提供原生主题提供器和按钮；请选择兼容的对等依赖，并在应用锁定文件中固定解析后的版本。

```
npm install @twilio-paste/button @twilio-paste/theme react react-dom
```

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

```
使用 Paste Theme.Provider 和 Button 构建通知草稿编辑器。保留次级按钮的按下态切换语义、rem 间距、有来源依据的文本角色，以及彼此独立的草稿状态和快照状态。不要虚构短信分段数或送达结果。
```

## Twilio Paste 设计系统来源与范围

OpenDesign 对上游 Paste 的独立参考。Paste DSys 是一个独立且无关联的分支。本示例不会发送任何消息。

- 上游 Paste 权威仓库与系统身份。

- 间距 基于 rem 的别名。

- 字体阶梯 字号别名。

- 行高 独立的行高比例。

- 圆角 圆角别名。

- 文本角色 语义颜色及对比度搭配。

- 调色板 解析后的源调色板值。

- Button 来源 受支持的属性组合与行为。

- 主题导出项 原生提供程序与实用工具。

- 主题变体 明确支持的变体名称。

## Twilio Paste 设计系统相关资源

### Visa Product 设计系统

使用 Visa 的 Nova CSS，通过原生单选控件、替代色标题栏和确认摘要，打造清晰的账单格式偏好设置。查看精确的 1.6.5 主题值、可缩放间距和完整的样式表集成。

### Volvo Cars Web 设计系统

通过完整的行李规划示例，检查 Volvo Cars 以 HTML 为先的 Web 基础、实际的浅色模式令牌和原生可选卡片样式；支持独立选择、主题切换和重置。

### Wonderflow Wanda

在完整的反馈阅读工作区中使用 Wanda 的真实主题角色和令牌语法，支持主题筛选、展开查看证据背景，以及持久保存到本地的笔记本。


- [实现参考](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-core/components/button/src/Button.tsx)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/spacing.yml)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/font-size.yml)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/line-height.yml)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/border-radius.yml)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/global/text-color.yml)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-core/components/button/src/Button.tsx)
- [来源](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-theme/src/constants.ts)
- [阅读配套规范](https://github.com/twilio-labs/paste)
- [阅读配套规范](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/spacing.yml)
- [阅读配套规范](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/font-size.yml)
- [阅读配套规范](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/global/text-color.yml)
- [阅读配套规范](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-theme/src/index.tsx)
- [阅读配套规范](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-core/components/button/src/Button.tsx)
- [代码参考](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-core/components/button/src/Button.tsx)
- [上游 Paste 权威仓库与系统身份。](https://github.com/twilio-labs/paste)
- [间距 基于 rem 的别名。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/spacing.yml)
- [字体阶梯 字号别名。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/font-size.yml)
- [行高 独立的行高比例。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/line-height.yml)
- [圆角 圆角别名。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/border-radius.yml)
- [文本角色 语义颜色及对比度搭配。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/global/text-color.yml)
- [调色板 解析后的源调色板值。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-design-tokens/tokens/aliases/color-palette.yml)
- [Button 来源 受支持的属性组合与行为。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-core/components/button/src/Button.tsx)
- [主题导出项 原生提供程序与实用工具。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-theme/src/index.tsx)
- [主题变体 明确支持的变体名称。](https://raw.githubusercontent.com/twilio-labs/paste/main/packages/paste-theme/src/constants.ts)
