Annotation
annotation手写风格标注 · 荧光笔底色 + 手绘箭头 + 手写旁注就地讲解行内内容(文档/演示/组件解剖图) · 八方位(标签在哪,箭头自动指回) + 6 语气(含彩虹) + 只圈不注 · 标签是真节点故可放 ReactNode 且读屏可读(区别 Callout 块级提示框·零依赖)
用法
基础用法
包住一段行内内容,note 就是那句手写旁注。side 说的是**标签在哪**(同 Tooltip/Popover),箭头自动从标签指回目标。标注绝对定位、不占布局位置,所以要给容器留出四周空间。
<p>
任务 ID 写成 <Annotation note="稳定 ID" side="ne">CLI-042</Annotation>,
改标题也不会失联。
</p>解剖一行代码
标注最典型的用法:把一行东西拆开逐块讲。同一行里挂多条标注时靠 side 错开方位,必要时再用 offset 微调。末尾三条彼此紧挨,用 --hl-ann-spread 收窄荧光笔的外扩量,免得底色连成一整片分不出边界。
- [ ] CLI-042稳定 ID Add export command #cli标签 !high优先级 @blocked_by:CLI-041自定义字段<code>
- [ ] <Annotation note="稳定 ID" side="n" tone="primary">CLI-042</Annotation>{" "}
Add export command{" "}
<Annotation note="标签" side="n" tone="success" className="[--hl-ann-spread:0.1em]">#cli</Annotation>{" "}
<Annotation note="优先级" side="s" tone="danger" className="[--hl-ann-spread:0.1em]">!high</Annotation>{" "}
<Annotation note="自定义字段" side="se" tone="warning" className="[--hl-ann-spread:0.1em]">
@blocked_by:CLI-041
</Annotation>
</code>八个方位
side 是标签所在的方位。四个正方位在对应边居中,四个对角方位锚在目标角上、朝外侧对齐 —— 标签变长时只会向远离目标的方向生长。
{["n", "ne", "e", "se", "s", "sw", "w", "nw"].map((side) => (
<Annotation key={side} note={side} side={side}>目标</Annotation>
))}语气色
tone 只染标注自己(荧光笔底色由它派生),被标注的正文保持原色不变。rainbow 是循环色相,纯装饰用;降低动效偏好下它会停在起始色。
<Annotation note="中性" tone="neutral">默认</Annotation>
<Annotation note="主色" tone="primary">强调</Annotation>
<Annotation note="正解" tone="success">通过</Annotation>
<Annotation note="注意" tone="warning">警告</Annotation>
<Annotation note="坑" tone="danger">危险</Annotation>
<Annotation note="彩虹" tone="rainbow">装饰</Annotation>只圈不注
不传 note 就只留荧光笔底色,不画箭头也不画标签 —— 用来单纯圈出一段内容。反过来 mark={false} 则保留标注、去掉底色。
<p>
真正要紧的是 <Annotation tone="warning">这一句</Annotation>,
其余是<Annotation note="可以跳过" side="s" mark={false}>背景交代</Annotation>。
</p>标签放 ReactNode
note 是真实 DOM 节点而不是 CSS 伪元素的 content,所以能放任意 ReactNode —— 内嵌代码、链接、强调都行,读屏也读得到。
docs/specs<Annotation
note={<>见 <code>docs/specs</code></>}
side="e"
tone="primary"
>
spec 文件
</Annotation>手写字体与摆正
手写字体栈里的中文字体(手札体 / 翩翩体 / 行楷)是系统字体,装了才有;没装则回落到正文字体,倾斜角与配色仍在。要在正式文档里更克制,可以 handwritten={false} 配 rotate={0}。
<Annotation note="手写 · 默认倾斜" side="n">默认</Annotation>
<Annotation note="正文字体 · 摆正" side="n" handwritten={false} rotate={0}>克制</Annotation>何时用
要在文档、演示、组件解剖图里贴着一段行内内容讲「这一块是什么」时用它 —— 典型场景是把一行代码、一条配置、一个 URL 拆开逐块标注。
它和 Callout 互补:Callout 是打断正文的块级提示框,Annotation 是不占布局位置的旁注。要指着某个 UI 元素做产品引导用 Tour(带遮罩、分步、可交互);要给一段文本挂可点击的悬停解释用 Tooltip。
导入
import { Annotation } from "@hulianui/ui/annotation"Props
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| note | ReactNode | — | 手写旁注的内容。省略或传空时只留荧光笔底色,不画箭头也不画标签。 |
| side | "n"|"ne"|"e"|"se"|"s"|"sw"|"w"|"nw" | ne | 标签所在的方位(与 Tooltip/Popover 的 side 同义),箭头自动从标签指回目标。 |
| tone | "neutral"|"primary"|"success"|"warning"|"danger"|"rainbow" | neutral | 语气色。只染标注自身,被标注的正文保持原色。rainbow 为循环色相,纯装饰。 |
| mark | boolean | true | 荧光笔底色。外扩量见下方 --hl-ann-spread。 |
| rotate | number | -4 | 标签倾斜角(deg)。传 0 摆正。 |
| labelWidth | number | 150 | 标签折行前的最大宽度(px)。 |
| gap | number | 5 | 目标与箭头之间的留白(px)。 |
| labelGap | number | 6 | 箭头与标签之间的留白(px)。 |
| offset | { x?: number; y?: number } | — | 微调。side 占据的那根轴上正值 = 远离目标(左右两侧对称);另一根轴上正值 = 向右 / 向下。 |
| handwritten | boolean | true | 标签是否套手写字体栈(见下方「中文手写体」)。 |
| as | ElementType | span | 宿主标签。需要语义高亮时可传 mark。 |
| className | string | — | 落在宿主(被标注的内容)上。 |
| labelClassName | string | — | 落在标签上,用来改字号 / 字重。 |
CSS 变量
| 变量 | 默认 | 说明 |
|---|---|---|
--hl-annotation-font | 手写字体栈 | 全局的手写字体栈,定义在 @hulianui/tokens 的 semantic.css,可整站覆盖。 |
--hl-ann-spread | 0.3em | 荧光笔底色左右外扩量(模仿马克笔涂过头)。用 className="[--hl-ann-spread:0.1em]" 单条覆盖。 |
禁忌 / 坑
标签会被 `overflow: hidden` 的祖先裁掉。 箭头与标签都是绝对定位、故意溢出目标盒子的。放进 ScrollArea、裁剪卡片、表格单元格时它们会被切掉半截 —— 给那个祖先留出内边距,或换一个 side。同理,容器四周要留够空间(示例里的 py-16 不是装饰)。
相邻标注的荧光笔底色会连成一片。 底色向左右各外扩 0.3em 模仿马克笔涂过头,同一行里几条标注紧挨着时就会糊成一整条。用 className="[--hl-ann-spread:0.1em]" 收窄,或 0px 完全断开 —— 单位不能省:calc(-1 * 0) 得到的是 <number> 而非 <length>,box-shadow 会拒收整条声明,底色反而变成不外扩也不圆角的裸方块。
中文手写体是系统字体,装了才有。 --hl-annotation-font 的字体栈里,拉丁部分(Shantell Sans / Comic Sans)与中文部分(手札体 / 翩翩体 / 行楷)都不由本库打包 —— 中文手写体动辄数 MB,塞进设计系统不合理。一个都没命中时回落到正文字体:倾斜角与配色仍在,只是少了手写笔触。要保证中文也是手写体,自行 @font-face 引入后覆盖 --hl-annotation-font 即可。
别把必读信息只写在 note 里。 标签是真实 DOM 节点(不是 ::after + content),读屏能读到,但它在视觉上是旁注、在阅读顺序上跟在目标后面。操作指令、校验错误、状态这类必须被感知的信息要有正文里的正式出处。
tone 不会给被标注的正文染色,这是刻意的:色只经 --hl-ann-color 下发给箭头与标签。想让目标本身也变色,自己在 className 上加 text-*。
相关
Playground
<Annotation note="稳定 ID" side="ne" tone="neutral">CLI-042</Annotation>