简体中文
SignaturePad 签名板
用指针书写的画布:按下落笔、移动成迹、抬起收笔,输出可缩放、可直接提交的 SVG;签名数据可存下后原样回显,逐步撤销与重做。
用法
一块画布加一条笔迹路径即可:按下落笔、移动成迹、抬起收笔
组件结构
加粗的是必需部件。
data-scope="signature-pad":root · label · control · guide · path · undo-trigger · redo-trigger · clear-trigger · status · hidden-input
示例
标题、基准线与清空
基准线是纯画面(带 aria-hidden),清空按钮是原生 button,读屏朗读的是 translations 中的文案
请在下方签名
参与表单
提供 name 后带上表单影子,提交的是一份独立 SVG;表单重置会把画布清空
笔迹外形
drawing 调整笔宽与压感:thinning 越大,划得越快笔画越细,simulatePressure 决定压感取设备值还是按速度计算
只读与禁用
只读时已绘制的笔迹可见但不可修改,禁用时连清空按钮都不可按下;两者都使用原生 disabled,不只是视觉置灰
只读
禁用
取出签名
签名定稿时 draw-end 带上一份可直接入库的 SVG;提交前用 empty 拦截一次,空签名不应离开客户端
SVG 0 字节
撤销与重做
一笔或一次清空是一步;没有可撤销、可重做的一步时按钮置灰,焦点仍留在原处
回显已存的签名
存下 value-change 给出的数据,编辑页把它交回 defaultValue 即原样回显,之后照常续写与撤销
共 2 笔
设计指引
何时使用
- 承诺书、回执、验收单上需要手写签名。
- 交付确认、上门服务签收等需要留下确认痕迹的场景。
何时不用
特性
- 笔迹是 SVG 填充路径,放大不模糊;每一笔是同一条路径上的一条子路径。
- 第一笔落下时测量一次画布并固定这套坐标,画布的
viewBox与导出的 SVG 都使用它:容器变宽变窄时,已有笔迹跟随缩放而不是停留在原像素上错位。清空后重新测量。 drawing一组选项调整笔画外形:size决定粗细,thinning让粗细随压感变化,simulatePressure决定压感取设备值还是按落笔速度计算。- 签名数据
value是逐笔的点加上笔迹坐标系({ strokes, surface }),无损:原样存下,编辑页交回defaultValue即回显,之后照常续写、撤销与重做;提供value即受控,定稿只经value-change送出。导出的 SVG 是它的一种画法,轮廓已偏移成填充面,读不回逐笔的点,所以回显要存数据而不是 SVG。 - 撤销与重做以一步为单位:一笔、一次清空都是一步,误清之后撤销能找回整份签名。再落一笔或清空后重做栈作废;宿主从外面换了一份签名(受控写回另一条记录、换了
defaultValue后重置)时撤销与重做栈一并作废。落笔途中不认撤销与重做。 - 带
name即参与表单提交,提交的是一份独立的 SVG 文档;表单重置回到defaultValue(未提供时清空画布)并清掉撤销历史。 - 笔迹变化时发出
draw,签名定稿时发出draw-end与value-change:抬笔、清空、撤销、重做、表单重置都发出,落笔途中逐点只发draw。按draw-end缓存待提交的 SVG 不会取到过期版本。 - 指针划出画布甚至划出窗口都持续跟随,抬起即收笔;落笔的指针被捕获,手掌与第二根手指的移动不会续进这一笔。
- 画布是一块字段外壳:静息不填底 +
--xh-border-control描边 + 4px 控件圆角、无影;落笔时描边加深,只读只换淡底,禁用退到--xh-border-default+--xh-bg-subtle。画布按宽高比撑高,吃不下字段家族配方钉死的控件行高,因此外壳按同一套字段规则自绘。 - 标签走字段标签档(14 / 500 /
--xh-fg-default),贴画布--xh-space-1;状态句是说明角色(13 /--xh-fg-muted)。 - 清空按钮走 Action Control text 档 sm:缺省
outline描边,白底承载阶梯悬停 100 → 按下 200,按下缩放并换底;空画布时只把静息前景压淡,按钮照常可按。 - 撤销与重做按钮与清空按钮同一身份;没有可撤销、可重做的一步时投影
aria-disabled与家族置灰面,焦点仍留在钮上。 - 不写结构时按标准结构铺出整套部件(Vue 不写默认插槽、React 不给 children、Web Components 不写部件或只写
root),三端出自同一个结构函数:label给标题文字,接着是画布(基准线与笔迹)、清空按钮与状态,给了name再带表单影子;清空按钮的字与状态句取 translations。撤销与重做按钮不在其中,要用时手写结构。Web Components 里标题可以写在宿主的直接子节点slot="label"上接管。
组合
- 与表单字段搭配:标题、说明与错误提示交给字段,签名板只负责画布。直接放进字段时,字段的标题并进画布的名字,说明与错误文案进描述链;点字段标题,焦点交给签名板里第一颗可聚焦的按钮(画布本身不可聚焦,一笔都没有时按钮都不可用,焦点不动)。
- 放入表单,提供
name后随表单提交与重置。 - 与对话框搭配做签名确认:确认按钮的可用状态读取
empty。
节点形状是硬约束
画布这一族部件必须落在特定标签上,写错不报错,但无法绘制:
control必须是<svg>;guide必须是control内的<line>;path必须是control内的<path>;undo-trigger、redo-trigger、clear-trigger必须是原生<button>,hidden-input必须是原生<input>。
viewBox 由组件写入,作者不要在 control 上再写。
两个适配器的分工
- Vue:
XhSignaturePadRoot的默认插槽给出value/empty/paths/drawing/canUndo/canRedo/statusText与toSvg()/clear()/undo()/redo(),签名数据走v-model:value;也可以用useSignaturePad()自行获取。XhSignaturePadGuide与XhSignaturePadPath必须写在XhSignaturePadControl内:SVG 命名空间由该子树带下,移出后会成为 HTML 元素,无法绘制。 - Web Components:结构由作者编写(Light DOM,不投影插槽)。
<xh-signature-pad>上有clear()、undo()、redo()、toSvg()与只读的empty/canUndo/canRedo;value/defaultValue是对象,只走 property。提交前取签名用toSvg(),不需要缓存上一次draw-end。 - 两侧的
status部件内都不需要自行写文字:节点为空时由适配器填入语言包里的文案;写了文字则以作者的为准。
最佳实践
- 给清空按钮一句可见文字或稳定的图标语义,不只依靠一个叉。
- 清空之后安置焦点:按钮被禁用或收起时焦点会回到
<body>,键盘用户每清空一次就丢失一次位置。要么让按钮始终可按(本组件的默认做法),要么清空后显式把焦点交给下一个落点。 - 提交前用
empty拦截:空签名与潦草签名是两回事,前者应在客户端拦截。 - 需要缓存待提交的 SVG 时按
draw-end缓存:清空与表单重置同样会发出它,缓存不会停留在旧版本。不要嗅探清空按钮的点击。 - 存储的是 SVG 文本,不是位图。需要位图时在服务端渲染,不在前端截屏。
- 需要在编辑页回显、续写的签名,同时存下
value-change给出的数据;只存 SVG 的签名只能展示,不能再改。
反模式
- 把画布做得很窄:手写需要面积,过窄的画布只会产生无法辨认的字迹。
- 让签名成为唯一的确认方式却不提供替代路径,这是可达性问题。
- 把签名图当作身份凭证。它证明的是有人在画布上书写过,不是书写者的身份。
API 参考
产物
| 层 | 值 |
|---|---|
| 自定义元素 | <xh-signature-pad> |
| Vue 组件 | XhSignaturePadClearTrigger XhSignaturePadControl XhSignaturePadGuide XhSignaturePadHiddenInput XhSignaturePadLabel XhSignaturePadPath XhSignaturePadRedoTrigger XhSignaturePadRoot XhSignaturePadStatus XhSignaturePadUndoTrigger |
| 组合式函数 | useSignaturePad |
| 状态机 | signaturePadMachine |
| 皮肤 | @xihan-ui/styles/signature-pad.css |
Props
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
labelled | boolean | 作者渲染了 label 部件时置真,由适配器统计而不是判断标题文字是否有值。 为假时可聚焦部件不把 label 的 id 写进 aria-labelledby:指向未渲染的 id 是无效引用,作者写在控件上的 aria-label 也会被它压住。 | |
ariaLabel | string | 不显示出来的名字,写成 aria-label 落在与字段标签同一个部件上。 放进字段(字段接线)或渲染了 label 部件时名字以它们为准,aria-labelledby 盖过它。 | |
disabled | boolean | 整块不可交互:不响应落笔,清空、撤销与重做按钮也不可按下。 | |
readOnly | boolean | 只读:已绘制的签名照常显示,但不可修改。 | |
required | boolean | ||
invalid | boolean | 校验未通过的标记,只改变外观与表单影子上的 aria-invalid。 | |
name | string | 表单字段名;提供后表单影子才带 name 并参与提交。 | |
value | SignaturePadValue | 签名数据。提供即受控:抬笔、清空、撤销与重做都只发 onValueChange,由宿主写回。 | |
defaultValue | SignaturePadValue | 非受控的初值,也是表单重置回到的那一份;编辑页回显已存的签名用它。 | |
drawing | SignaturePadDrawingOptions | 笔迹外形。默认为 4px 恒定粗细。 | |
translations | Partial<SignaturePadTranslations> | ||
onDraw | (details: SignaturePadDrawDetails) => void | 每收进一个点通知一次,清空、撤销、重做与表单重置时也通知一次。 | |
onDrawEnd | (details: SignaturePadDrawEndDetails) => void | 签名定稿时通知一次并附带可直接提交的 SVG:抬笔、清空、撤销、重做与表单重置都发出。 | |
onValueChange | (details: SignaturePadValueChangeDetails) => void | 签名数据变了:与 onDrawEnd 同一批时机,落笔途中不发。受控时是唯一出口。 | |
onClear | () => void | 用户按清空钮(clear-trigger)清掉了值;先发值变化,再发它。程序化的 clear() 不发。 |
事件
自定义元素将载荷放在 detail;Vue 使用同名 emit。
| 事件 | 载荷 | 说明 |
|---|---|---|
draw | SignaturePadDrawDetails | 笔迹变化时通知一次(含清空、撤销、重做与表单重置);detail 为 { paths: string[], path: string } |
draw-end | SignaturePadDrawEndDetails | 签名定稿时通知一次(抬笔、清空、撤销、重做、表单重置);detail 为 { paths: string[], svg: string },svg 可直接存储 |
value-change | SignaturePadValueChangeDetails | 签名数据定稿,时机同 draw-end;detail 为 { value: { strokes, surface } },可原样存下再赋回 defaultValue 回显 |
clear | `` | 用户按清空钮(clear-trigger)清掉了值;先发值变化,再发它。程序化的 clear() 不发。 |
插槽
仅列出带载荷的插槽。
| Vue 组件 | 插槽 | 载荷 | 说明 |
|---|---|---|---|
XhSignaturePadRoot | default | SignaturePadRootSlotProps | |
XhSignaturePadRoot | label | — |
React 适配器 props
只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。
| React 组件 | 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
XhSignaturePadRoot | label | ReactNode | 标题。不给 children 时铺 label 部件。 | |
XhSignaturePadRoot | children | SlotChildren<SignaturePadRootSlotProps> |
状态
以下名称仅用于内部状态机。
状态:drawing · idle
事件:DRAW.START · DRAW.MOVE · DRAW.END · STROKES.CLEAR · HISTORY.UNDO · HISTORY.REDO · FORM.RESET · PRESS.START · PRESS.END
判据:canDraw · canPress
connect API
getXxxProps() 返回对应部件的宿主属性。
| 成员 | 类型 | 说明 |
|---|---|---|
value | SignaturePadValue | 已定稿的签名数据,可原样存下、再作为 value / defaultValue 交回来回显。 |
paths | readonly string[] | 逐笔的填充轮廓 d 串,按落笔先后排列(含正在写的那一笔)。 |
empty | boolean | 没有任何笔迹。 |
drawing | boolean | 笔正落在画布上。 |
disabled | boolean | |
readOnly | boolean | |
canUndo | boolean | 有可撤销的一步:上一笔、上一次清空或上一次重做。 |
canRedo | boolean | 有被撤销、还能重做的一步。 |
statusText | string | 是否已签名的文案,写入 status 部件;适配器在作者未自行编写文字时把它填入节点。 |
translations | SignaturePadTranslations | 合上作者覆盖后的文案。 |
toSvg | () => string | 当前签名的独立 SVG 文档,与表单影子提交的是同一份;空签名为空串。 |
clear | () => void | |
undo | () => void | 撤销最近一步(一笔、一次清空或一次重做);没有可撤销的就什么都不做。 |
redo | () => void | 重做最近撤销的一步;没有可重做的就什么都不做。 |
getRootProps | () => T['element'] | |
getLabelProps | () => T['element'] | |
getControlProps | () => T['element'] | |
getGuideProps | () => T['element'] | |
getPathProps | () => T['element'] | |
getClearTriggerProps | () => T['button'] | |
getUndoTriggerProps | () => T['button'] | 撤销按钮:没有可撤销的一步时 aria-disabled,焦点留在原处。 |
getRedoTriggerProps | () => T['button'] | 重做按钮:没有可重做的一步时 aria-disabled,焦点留在原处。 |
getStatusProps | () => T['element'] | 状态出口:一块 role=status 的活区域,签名与清空都会播报一次。 |
getHiddenInputProps | () => T['input'] | 表单出口:一份视觉隐藏的原生输入,随表单提交当前签名。 |
无障碍
键盘
规格出处:W3C APG
| 按键 | 生效条件 | 行为 |
|---|---|---|
Enter / Space | focus on clear-trigger, 未禁用且非只读 | 清空整块画布;清空也是一步,可撤销找回;按钮是原生 button,这两个键由平台翻成 click |
Enter / Space | focus on undo-trigger, 未禁用且非只读,且有可撤销的一步 | 撤销最近一步(一笔或一次清空);没有可撤销的一步时按钮 aria-disabled,按下是空操作,焦点留在原处 |
Enter / Space | focus on redo-trigger, 未禁用且非只读,且有被撤销的一步 | 重做最近撤销的一步;再落一笔或清空后重做栈作废,按钮 aria-disabled |
Enter / Space | held in clear-trigger / undo-trigger / redo-trigger, 未禁用、非只读且按钮可用 | 按住期间投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下 |
ARIA
以下属性由 connect 生成。
| 部件 | 属性 | 值 |
|---|---|---|
control | aria-label | props.ariaLabel |
control | aria-labelledby | label 部件的 id | undefined |
control | role | 'img' |
guide | aria-hidden | 'true' |
undo-trigger | aria-disabled | 'true' | undefined |
undo-trigger | aria-label | translations.undoTrigger |
redo-trigger | aria-disabled | 'true' | undefined |
redo-trigger | aria-label | translations.redoTrigger |
clear-trigger | aria-label | translations.clearTrigger |
status | aria-atomic | 'true' |
status | aria-live | 'polite' |
status | role | 'status' |
hidden-input | aria-hidden | 'true' |
hidden-input | aria-invalid | 'true' | 'false' |
- 签名天然依赖指针,键盘和读屏无法完成。凡是要求签名的流程,必须同时提供一条不依赖指针的替代路径:打字签名、上传签名图或线下核验。只放一块画布等于把这些用户挡在流程之外。
- 画布报告为
role="img",不是控件:它不接受键盘、不进入 Tab 序列,伪装成控件只会让读屏用户进入无法操作的位置。 - 画布的名称来自
label部件;未渲染标题时退回translations.label。 - 是否已签名由
status部件播报。画布是role="img",名称固定,签名、清空、表单重置后读屏读出的都是同一句,用户无法确认笔迹是否保留。status是role="status"的活动区域,值每变一次播报一次,文案使用translations.statusEmpty/translations.statusSigned。要求签名的表单请渲染它。 - 基准线是纯画面,带
aria-hidden,读屏不读。没有translations.guide文案:给装饰线命名只会增加无信息量的播报。 - 撤销、重做与清空按钮都是原生
<button>,Enter / Space 由平台激活;按钮内只有图标时读屏读translations.undoTrigger/translations.redoTrigger/translations.clearTrigger。 - 撤销、重做没东西可做时用
aria-disabled而不是原生disabled:刚把最后一笔撤掉的那颗钮若变成原生禁用,焦点会掉回<body>,键盘用户每撤到头一次就丢失一次位置。整块禁用或只读时三颗按钮才走原生disabled。
样式参考
皮肤
@xihan-ui/styles/signature-pad.css 按 [data-scope="signature-pad"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-signature-pad 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。
forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。
数据属性
由 connect 生成;条件不成立时不输出无值属性。
| 部件 | 属性 | 值 |
|---|---|---|
root | data-disabled | ''(条件成立时才出现) |
root | data-drawing | ''(条件成立时才出现) |
root | data-empty | ''(条件成立时才出现) |
root | data-invalid | ''(条件成立时才出现) |
root | data-readonly | ''(条件成立时才出现) |
label | data-disabled | ''(条件成立时才出现) |
control | data-disabled | ''(条件成立时才出现) |
control | data-drawing | ''(条件成立时才出现) |
control | data-empty | ''(条件成立时才出现) |
control | data-invalid | ''(条件成立时才出现) |
control | data-readonly | ''(条件成立时才出现) |
guide | data-disabled | ''(条件成立时才出现) |
path | data-empty | ''(条件成立时才出现) |
undo-trigger | data-disabled | ''(条件成立时才出现) |
undo-trigger | data-pressed | ''(条件成立时才出现) |
undo-trigger | data-xh-action-control | '' |
undo-trigger | data-xh-action-display | 'always' |
undo-trigger | data-xh-action-profile | 'text' |
undo-trigger | data-xh-action-size | 'sm' |
undo-trigger | data-xh-action-variant | 'outline' |
redo-trigger | data-disabled | ''(条件成立时才出现) |
redo-trigger | data-pressed | ''(条件成立时才出现) |
redo-trigger | data-xh-action-control | '' |
redo-trigger | data-xh-action-display | 'always' |
redo-trigger | data-xh-action-profile | 'text' |
redo-trigger | data-xh-action-size | 'sm' |
redo-trigger | data-xh-action-variant | 'outline' |
clear-trigger | data-disabled | ''(条件成立时才出现) |
clear-trigger | data-empty | ''(条件成立时才出现) |
clear-trigger | data-pressed | ''(条件成立时才出现) |
clear-trigger | data-xh-action-control | '' |
clear-trigger | data-xh-action-display | 'always' |
clear-trigger | data-xh-action-profile | 'text' |
clear-trigger | data-xh-action-size | 'sm' |
clear-trigger | data-xh-action-variant | 'outline' |
status | data-empty | ''(条件成立时才出现) |
hidden-input | data-disabled | ''(条件成立时才出现) |
CSS 变量
本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。
| 变量 | 部件 | CSS 属性 | 状态 | 默认来源 | 说明 |
|---|---|---|---|---|---|
--xh-signature-pad-aspect-ratio | control | aspect-ratio | default | 5 / 2 | signature-pad 的 control 部件 aspect-ratio 覆盖槽。 |
--xh-signature-pad-bg | control | background | default | --xh-bg-field | signature-pad 的 control 部件 background 覆盖槽。 |
--xh-signature-pad-bg-disabled | control | background | disabled | --xh-bg-subtle | signature-pad 的 control 部件 background 覆盖槽。 |
--xh-signature-pad-bg-drawing | control | background | drawing | --xh-bg-surface | signature-pad 的 control 部件 background 覆盖槽。 |
--xh-signature-pad-bg-invalid | control | background | invalid | --xh-bg-field-invalid | signature-pad 的 control 部件 background 覆盖槽。 |
--xh-signature-pad-bg-readonly | control | background | disablednot([data-disabled])readonly | --xh-bg-subtle | signature-pad 的 control 部件 background 覆盖槽。 |
--xh-signature-pad-border | control | border | default | --xh-border-control | signature-pad 的 control 部件 border 覆盖槽。 |
--xh-signature-pad-border-disabled | control | border-color | disabled | --xh-border-default | signature-pad 的 control 部件 border-color 覆盖槽。 |
--xh-signature-pad-border-drawing | control | border-color | drawing | --xh-border-control-focus | signature-pad 的 control 部件 border-color 覆盖槽。 |
--xh-signature-pad-border-hover | control | border-color | disableddrawinghoverinvalidnot([data-disabled])not([data-drawing])not([data-invalid])not([data-readonly])readonly | --xh-border-strong | signature-pad 的 control 部件 border-color 覆盖槽。 |
--xh-signature-pad-clear-bg | clear-trigger | --xh-ink-surfacebackground-color | defaultfocus-visiblexh-ink-surface | --xh-_action-variant-bg-focus-visible--xh-_action-variant-bg-rest | signature-pad 的 clear-trigger 部件 --xh-ink-surface、background-color 覆盖槽。 |
--xh-signature-pad-clear-bg-active | clear-trigger | background-color | disabledis(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-_action-variant-bg-pressed | signature-pad 的 clear-trigger 部件 background-color 覆盖槽。 |
--xh-signature-pad-clear-bg-disabled | clear-trigger | --xh-ink-surfacebackground-color | disabledxh-ink-surface | --xh-_action-variant-bg-disabled | signature-pad 的 clear-trigger 部件 --xh-ink-surface、background-color 覆盖槽。 |
--xh-signature-pad-clear-bg-hover | clear-trigger | background-color | disabledhoverloadingnot([data-disabled])not([data-loading]) | --xh-_action-variant-bg-hover | signature-pad 的 clear-trigger 部件 background-color 覆盖槽。 |
--xh-signature-pad-clear-border | clear-trigger | borderborder-color | defaultfocus-visible | --xh-_action-variant-border-focus-visible--xh-_action-variant-border-rest | signature-pad 的 clear-trigger 部件 border、border-color 覆盖槽。 |
--xh-signature-pad-clear-border-hover | clear-trigger | border-color | disabledhoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-_action-variant-border-hover--xh-_action-variant-border-pressed | signature-pad 的 clear-trigger 部件 border-color 覆盖槽。 |
--xh-signature-pad-clear-fg | clear-trigger | color | defaultdisabledfocus-visiblehoveris(:active, [data-pressed])loadingnot([data-disabled])not([data-loading])pressed | --xh-_action-variant-fg-focus-visible--xh-_action-variant-fg-hover--xh-_action-variant-fg-pressed--xh-_action-variant-fg-rest | signature-pad 的 clear-trigger 部件 color 覆盖槽。 |
--xh-signature-pad-clear-fg-empty | clear-trigger | color | empty | --xh-fg-muted | signature-pad 的 clear-trigger 部件 color 覆盖槽。 |
--xh-signature-pad-clear-font-size | clear-trigger | font-size | default | --xh-_action-profile-font-size | signature-pad 的 clear-trigger 部件 font-size 覆盖槽。 |
--xh-signature-pad-clear-gap | clear-trigger | gap | default | --xh-_action-profile-gap | signature-pad 的 clear-trigger 部件 gap 覆盖槽。 |
--xh-signature-pad-clear-h | clear-trigger | block-size | default | --xh-_action-profile-visual-size | signature-pad 的 clear-trigger 部件 block-size 覆盖槽。 |
--xh-signature-pad-clear-icon-size | clear-trigger | --xh-icon-size | default | --xh-_action-profile-glyph-size | signature-pad 的 clear-trigger 部件 --xh-icon-size 覆盖槽。 |
--xh-signature-pad-clear-px | clear-trigger | padding-inline | default | --xh-_action-profile-padding-inline | signature-pad 的 clear-trigger 部件 padding-inline 覆盖槽。 |
--xh-signature-pad-clear-radius | clear-trigger | border-radius | default | --xh-shape-control | signature-pad 的 clear-trigger 部件 border-radius 覆盖槽。 |
--xh-signature-pad-clear-shadow-hover | clear-trigger | box-shadow | disabledhoverloadingnot([data-disabled])not([data-loading]) | none | signature-pad 的 clear-trigger 部件 box-shadow 覆盖槽。 |
--xh-signature-pad-control-border-invalid | control | border-color | invalid | --xh-border-invalid | signature-pad 的 control 部件 border-color 覆盖槽。 |
--xh-signature-pad-gap | labelroot | gapmargin-block-end | default | --xh-space-2 | signature-pad 的 label、root 部件 gap、margin-block-end 覆盖槽。 |
--xh-signature-pad-guide-stroke | guide | stroke | default | --xh-border-control | signature-pad 的 guide 部件 stroke 覆盖槽。 |
--xh-signature-pad-ink | path | fill | default | --xh-fg-default | signature-pad 的 path 部件 fill 覆盖槽。 |
--xh-signature-pad-label-fg | label | color | default | --xh-fg-muted | signature-pad 的 label 部件 color 覆盖槽。 |
--xh-signature-pad-label-fg-disabled | label | color | disabled | --xh-fg-muted | signature-pad 的 label 部件 color 覆盖槽。 |
--xh-signature-pad-label-font-size | label | font-size | default | --xh-text-label-size | signature-pad 的 label 部件 font-size 覆盖槽。 |
--xh-signature-pad-label-font-weight | label | font-weight | default | --xh-text-label-weight | signature-pad 的 label 部件 font-weight 覆盖槽。 |
--xh-signature-pad-label-gap | label | margin-block-end | default | --xh-space-2 | signature-pad 的 label 部件 margin-block-end 覆盖槽。 |
--xh-signature-pad-radius | control | border-radius | default | --xh-shape-control | signature-pad 的 control 部件 border-radius 覆盖槽。 |
--xh-signature-pad-status-fg | status | color | default | --xh-fg-muted | signature-pad 的 status 部件 color 覆盖槽。 |
--xh-signature-pad-status-font-size | status | font-size | default | --xh-text-secondary-size | signature-pad 的 status 部件 font-size 覆盖槽。 |
动效
动效角色:按压 · 状态(见动效规范)。
background-color · border-color 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。
系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。
响应式
- 画布宽度铺满外层容器,高度由宽高比(
--xh-signature-pad-aspect-ratio,默认 5 / 2)决定,窄屏上自动变矮。 - 签名过程中转屏、拖动面板改变宽度时,已有笔迹按
viewBox整体缩放,后续新笔与它落在同一套坐标。 - 触摸设备上画布关闭浏览器的滚动与缩放手势,避免手指划动时页面滚动。
RTL
皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。
- 画布与基准线不区分左右:笔迹按落笔坐标记录,方向由书写者决定。
- 标题与清空按钮的排布跟随文档方向,皮肤全部使用逻辑属性。
