跳转到内容

ColorSwatchPicker 颜色色块选择器

从一组固定颜色中选择一个:主题色、标签色、高亮色。每格是一个 role=radio 的色块,整组是一个 radiogroup,即把选项绘制为颜色的单选组。需要自由调出任意颜色时使用颜色选择器,它内嵌的预设色板使用的就是本组件。

用法

提供一组颜色数据即自动铺开;每格是一个 radio,方向键在格子间移动并选中

主题色
当前:#3b82f6

组件结构

加粗的是必需部件。

data-scope="color-swatch-picker"root · label · item · swatch · indicator · hidden-input

示例

手写格子

不提供数据也可以:每格自行声明 value,名字与禁用写在格子上;半透明颜色铺在棋盘格上

高亮色
当前:rgb(225, 29, 72)

状态

禁用整组置灰、只读只阻止落值不阻止焦点、无效把描边转为警示色

禁用
只读
必填未选

尺寸与语气

格子边长跟随控件行高分三档;tone 决定选中描边与选中徽标使用哪族颜色

sm
md
lg
brand
neutral
success
warning
danger
info

设计指引

何时使用

  • 可选颜色是有限的一组,且每个颜色都有含义(品牌色、状态色、日历分类色)。
  • 需要一次看到全部选项再挑选,不打开浮层。
  • 表单需要提交一个颜色串,且不需要自由调色。

何时不用

  • 需要自由调出任意颜色时,使用颜色选择器,它把色板与取色面组合在一起。
  • 只展示一个颜色、不接受选择时,使用颜色色块
  • 需要手动输入颜色串时,使用颜色字段
  • 选项不是颜色而是文字时,使用单选组

特性

  • 选中按颜色比较而不按字符串比较:rgb(255, 0, 0)#ff0000 是同一格,受控 value 使用任一写法都能匹配。
  • 与单选组同一套 roving tabindex:整组只占一个 Tab 位,四个方向键在格子间移动焦点并选中,到末端回绕,禁用格跳过;Space 选中当前格。
  • 焦点从组外进入时落在已选中的格子,没有选中时落在第一格。
  • swatches 提供数据:可访问名称与禁用从数据中读取,格子部件只需报告 value;不写默认内容时按数据自动铺开。
  • 每格的色块面由 Swatch 家族绘制:无法解析的串只显示棋盘格,半透明颜色铺在棋盘格上。
  • readOnly 时方向键照常移动焦点但不取值;disabled 整组置灰,格子仍可聚焦。
  • 尺寸 sm / md / lg 三档:格子边长跟随控件行高,与旁边的按钮、字段等高。
  • 选中徽标与色块的品牌描边随 data-tone 变化;徽标自带一圈画布色描边,落在任何颜色上都可见。
  • 高对比模式下色块保留原色,选中描边与徽标换用系统高亮色;打印时徽标改为实边。

组合

  • 内嵌在颜色选择器的浮层中作为预设色板。
  • 颜色字段并排:色板选择常用色,字段输入精确值。
  • 放入表单字段承接标题、说明与错误信息,disabled / readOnly / invalid / required 随字段下发。

最佳实践

  • 每格提供名称(swatches[].label 或部件的 label),读屏用户听到的应是“品牌红”而不是 #e11d48
  • 色板的颜色数量控制在一眼可扫完的范围,更多时改用颜色选择器
  • 有初始值时使用 defaultValue,焦点进组时直接落在该格。

反模式

  • 用它做多选:一格只能选中一个;需要多选颜色时使用复选框组配合颜色色块
  • 把颜色写成 red 等关键字:不在支持的写法内,该格只显示棋盘格。
  • 同一组内放同一颜色的不同写法:它们会同时算作选中。

API 参考

产物

自定义元素<xh-color-swatch-picker>
Vue 组件XhColorSwatchPickerItem XhColorSwatchPickerLabel XhColorSwatchPickerRoot
组合式函数useColorSwatchPicker
状态机colorSwatchPickerMachine
皮肤@xihan-ui/styles/color-swatch-picker.css

Props

属性类型必填说明
swatchesColorSwatchPickerNode[]格子数据,可及名与禁用的事实源。提供后格子部件只需声明 value。 未提供时回到名字与禁用都写在格子部件上的方式。
valuestring | null选中的颜色串。提供即受控:写入只发 onValueChange 不落内部值。写法不同的同一颜色也视为选中。
defaultValuestring | null
disabledboolean
readOnlyboolean只读:不可选择,但仍可聚焦、方向键照常移动焦点,对比度不降低。
invalidboolean校验失败:只改变呈现,不阻止交互。
requiredboolean必填:随表单校验一起使用,只发无障碍属性,不自行拦截提交。
dirDirection文字方向,默认 'ltr';只改写左右两键的语义。
namestring表单字段名。
sizeSize尺寸:sm / md / lg,影响格子的边长与间距。
toneTone语气:决定选中环与选中标记使用哪族颜色。
translationsPartial<ColorSwatchPickerTranslations>
onValueChange(details: ColorSwatchPickerValueChangeDetails) => voidvalue 变化回调。

事件

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeColorSwatchPickerValueChangeDetails选中值变化;detail 为 { value: string | null }

插槽

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhColorSwatchPickerRootdefaultColorSwatchPickerRootSlotProps
XhColorSwatchPickerRootlabel

状态

公开状态写入 data-state

部件取值
item'checked' | 'unchecked'
swatch'checked' | 'unchecked'
indicator'checked' | 'unchecked'
hidden-input'checked' | 'unchecked'

以下名称仅用于内部状态机。

状态idle

事件VALUE.SET · ITEM.SELECT · ITEM.FOCUS · GROUP.BLUR · FORM.RESET · PRESS.START · PRESS.END

判据canPress

connect API

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valuestring | null
swatchesreadonly ColorSwatchPickerNodeMeta[]由 swatches 推导的格子元信息,按数据顺序排列;未提供 swatches 时为空数组。
focusedValuestring | null焦点在组外时为 null。
isSelected(value: string) => boolean某个颜色串是否为当前选中的格:写法不同(#f00rgb(255,0,0))也视为同一颜色。
setValue(next: string | null) => void
getRootProps() => T['element']
getLabelProps() => T['element']
getItemProps(props: ColorSwatchPickerItemProps) => T['element']一格:role=radio,颜色串是它的身份。
getSwatchProps(props: ColorSwatchPickerItemProps) => T['element']格内的色块面:使用 Swatch 家族绘制颜色,纯装饰。
getIndicatorProps(props: ColorSwatchPickerItemProps) => T['element']选中标记(对号),纯装饰。
getHiddenInputProps(props: ColorSwatchPickerItemProps) => T['input']格子对应的隐藏原生 radio 输入,用于表单提交。

无障碍

键盘

规格出处:W3C APG

按键生效条件行为
Tab / Shift+Tabfocus outside the group整组只占一个 Tab 位:焦点进入锚点格子(即选中的那格);落到容器上时由容器转投锚点格子,锚点缺席或被禁用才落首个可停留格
ArrowDown / ArrowRightfocus in group, group not disabled焦点移到下一个可停留格并选中,末格回绕到首格;dir=rtl 时改由 ArrowLeft 承担
ArrowUp / ArrowLeftfocus in group, group not disabled焦点移到上一个可停留格并选中,首格回绕到末格;dir=rtl 时改由 ArrowRight 承担
Spacefocus on item, item not disabled选中当前格
Spaceheld on item, 格子未禁用且组未禁用、非只读按住期间该格投影 data-pressed,与指针 :active 同一副按压面(换描边并缩放);抬起或失焦撤下,按住途中整组转入禁用或只读也撤下。Enter 不是 radio 的激活键,按住它没有按压面

ARIA

以下属性由 connect 生成。

部件属性
rootaria-invalid'true' | 'false'
rootaria-labellabel.group
rootaria-labelledbylabel 部件的 id
rootaria-readonly'true' | 'false'
rootaria-required'true' | 'false'
rootrole'radiogroup'
itemaria-checked'true' | 'false'
itemaria-disabled'true' | 'false'
itemaria-labelitemLabel(item)
itemrole'radio'
swatcharia-hidden'true'
indicatoraria-hidden'true'
hidden-inputaria-hidden'true'
  • 根是 role=radiogroup,名称取 label 部件,未提供时读 translations.group
  • 每格是 role=radio 并显式输出 aria-checked;名称依次取 labelswatches 中的 labeltranslations.swatch(value),颜色串无法表达含义时务必提供名称。
  • 禁用格用 aria-disabled 表达,仍可聚焦,仍是方向键的起点。
  • 每格内有一个 inert 的隐藏原生 radio 承接表单提交,不进入焦点序列与可访问树。

样式参考

皮肤

@xihan-ui/styles/color-swatch-picker.css 使用 [data-scope="color-swatch-picker"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性

connect 生成;条件不成立时不输出无值属性。

部件属性
rootdata-disabled''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-readonly''(条件成立时才出现)
rootdata-required''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-toneprops.tone
labeldata-disabled''(条件成立时才出现)
itemdata-disabled''(条件成立时才出现)
itemdata-invalid''(条件成立时才出现)
itemdata-pressed''(条件成立时才出现)
itemdata-readonly''(条件成立时才出现)
itemdata-state'checked' | 'unchecked'
swatchdata-disabled''(条件成立时才出现)
swatchdata-invalid''(条件成立时才出现)
swatchdata-readonly''(条件成立时才出现)
swatchdata-state'checked' | 'unchecked'
swatchdata-xh-swatch''
swatchdata-xh-swatch-sizeprops.size
indicatordata-disabled''(条件成立时才出现)
indicatordata-invalid''(条件成立时才出现)
indicatordata-readonly''(条件成立时才出现)
indicatordata-state'checked' | 'unchecked'
hidden-inputdata-disabled''(条件成立时才出现)
hidden-inputdata-invalid''(条件成立时才出现)
hidden-inputdata-readonly''(条件成立时才出现)
hidden-inputdata-state'checked' | 'unchecked'

CSS 变量

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-color-swatch-picker-gaplabel
root
gap
margin-block-end
default--xh-_color-swatch-picker-gapcolor-swatch-picker 的 label、root 部件 gap、margin-block-end 覆盖槽。
--xh-color-swatch-picker-icon-sizeroot--xh-icon-sizedefault--xh-_color-swatch-picker-markcolor-swatch-picker 的 root 部件 --xh-icon-size 覆盖槽。
--xh-color-swatch-picker-indicator-bgindicatorbackgrounddefault--xh-_color-swatch-picker-accentcolor-swatch-picker 的 indicator 部件 background 覆盖槽。
--xh-color-swatch-picker-indicator-borderindicatorborderdefault--xh-bg-canvascolor-swatch-picker 的 indicator 部件 border 覆盖槽。
--xh-color-swatch-picker-indicator-fgindicatorbackground-color
color
default
empty
--xh-_tone-oncolor-swatch-picker 的 indicator 部件 background-color、color 覆盖槽。
--xh-color-swatch-picker-indicator-sizeindicatorblock-size
inline-size
default--xh-_color-swatch-picker-indicatorcolor-swatch-picker 的 indicator 部件 block-size、inline-size 覆盖槽。
--xh-color-swatch-picker-item-radiusitem
swatch
--xh-swatch-radius
border-radius
default--xh-shape-insetcolor-swatch-picker 的 item、swatch 部件 --xh-swatch-radius、border-radius 覆盖槽。
--xh-color-swatch-picker-item-sizeitemblock-size
inline-size
default--xh-_color-swatch-picker-cellcolor-swatch-picker 的 item 部件 block-size、inline-size 覆盖槽。
--xh-color-swatch-picker-label-fglabelcolordefault--xh-fg-defaultcolor-swatch-picker 的 label 部件 color 覆盖槽。
--xh-color-swatch-picker-label-fg-disabledlabelcolordisabled--xh-fg-subtlecolor-swatch-picker 的 label 部件 color 覆盖槽。
--xh-color-swatch-picker-label-font-sizelabelfont-sizedefault--xh-text-label-sizecolor-swatch-picker 的 label 部件 font-size 覆盖槽。
--xh-color-swatch-picker-label-font-weightlabelfont-weightdefault--xh-text-label-weightcolor-swatch-picker 的 label 部件 font-weight 覆盖槽。
--xh-color-swatch-picker-label-gaplabelmargin-block-enddefault--xh-space-1color-swatch-picker 的 label 部件 margin-block-end 覆盖槽。
--xh-color-swatch-picker-ringitem
swatch
--xh-swatch-borderstate=checked--xh-_tonecolor-swatch-picker 的 item、swatch 部件 --xh-swatch-border 覆盖槽。
--xh-color-swatch-picker-swatch-borderitem
swatch
--xh-swatch-borderdefault--xh-border-defaultcolor-swatch-picker 的 item、swatch 部件 --xh-swatch-border 覆盖槽。
--xh-color-swatch-picker-swatch-border-hoveritem
swatch
--xh-swatch-borderdisabled
hover
not([data-disabled], [data-readonly], [data-state='checked'])
readonly
state=checked
--xh-border-control-hovercolor-swatch-picker 的 item、swatch 部件 --xh-swatch-border 覆盖槽。
--xh-color-swatch-picker-swatch-border-invalidswatch--xh-swatch-borderinvalid--xh-border-invalidcolor-swatch-picker 的 swatch 部件 --xh-swatch-border 覆盖槽。
--xh-color-swatch-picker-swatch-border-presseditem
swatch
--xh-swatch-borderdisabled
is(:active, [data-pressed])
not([data-disabled], [data-readonly])
pressed
readonly
--xh-_tonecolor-swatch-picker 的 item、swatch 部件 --xh-swatch-border 覆盖槽。

动效

border-color · opacity · scaletransition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

响应式

  • 格子排成可换行的网格,一行放不下时换行;粗指针下命中区是整格。

RTL

  • dir="rtl" 只对调左右方向键的语义,上下键不受影响;格子的排列顺序由文档方向决定。

Released under The MIT License