90 lines
5.2 KiB
JSON
90 lines
5.2 KiB
JSON
{
|
||
"slug": "themeswitcher",
|
||
"end": "react",
|
||
"curated": true,
|
||
"summary": "React 端的 ThemeSwitcher:模式与品牌色两组单选,各自支持点击与键盘 Enter/空格,分别经两个回调回传。",
|
||
"usage": [
|
||
"两组控件都用 role=\"radio\" + aria-checked 自建:模式项外层是 role=\"radiogroup\" 容器,色块各自也是 role=\"radio\"(frameworks/ThemeSwitcher.jsx:13,18,19,34,36)。",
|
||
"键盘可达是显式补的:每项 tabIndex={0},并监听 `e.key === 'Enter' || e.key === ' '` 触发同一个回调(frameworks/ThemeSwitcher.jsx:20,21,37,38)。",
|
||
"点击与键盘走同一出口:模式项 click / keydown 都调 onModeChange(m.value),色块都调 onBrandChange(c),载荷是值本身(frameworks/ThemeSwitcher.jsx:21,22,38,39)。",
|
||
"选中态由受控值比对:`mode === m.value` / `brand === c` 决定 is-active 与 aria-checked(frameworks/ThemeSwitcher.jsx:17,19,32,36)。",
|
||
"两组可选项都是组件内常量:模式固定日间 / 夜间 / 自动,品牌色固定六个十六进制值(frameworks/ThemeSwitcher.jsx:4-9)。",
|
||
"底部标签实时显示当前品牌色:`品牌色:{brand}(应用于 Kole 品牌令牌实时预览)`,是纯文本反馈(frameworks/ThemeSwitcher.jsx:43)。"
|
||
],
|
||
"bestPractices": [
|
||
"选项集合不能通过 props 替换,示例里同名常量只是演示数据(frameworks/ThemeSwitcher.jsx:4-9)。",
|
||
"色块只有颜色与 aria-label,没有可见色名,视觉外要表达颜色含义需靠周边文案(frameworks/ThemeSwitcher.jsx:30-40)。",
|
||
"受控值不匹配任何选项时所有项都不会带 is-active,界面表现为「未选中」(frameworks/ThemeSwitcher.jsx:17,32)。",
|
||
"两个回调都没有判空保护,不传时点击会抛错(frameworks/ThemeSwitcher.jsx:21,22,38,39)。"
|
||
],
|
||
"a11y": [
|
||
"模式容器带 aria-label=\"主题模式\",读屏器能说出这组的用途(frameworks/ThemeSwitcher.jsx:13)。",
|
||
"每个单选项目都带 aria-checked 与 tabIndex=0,并且 Enter / 空格可切换,键盘可用(frameworks/ThemeSwitcher.jsx:19-21,36-38)。",
|
||
"品牌色块用 aria-label={`品牌色 ${c}`} 给出可访问名,读屏器能读出色值(frameworks/ThemeSwitcher.jsx:35)。",
|
||
"用 div / span 加 role=\"radio\" 自建而不是原生 input:方向键在同一组内切换的浏览器默认行为不存在(frameworks/ThemeSwitcher.jsx:14-27)。"
|
||
],
|
||
"apiCarrier": {
|
||
"kind": "props",
|
||
"note": "React 端的 API 载体是 4 个 props 与两个回调:mode / brand 为受控值,切换分别经 onModeChange / onBrandChange 回传;选项集合是组件内常量,没有 v-model。",
|
||
"table": [
|
||
{
|
||
"name": "brand",
|
||
"type": "String",
|
||
"desc": "受控品牌色,比对决定 is-active 与 aria-checked(frameworks/ThemeSwitcher.jsx:32,36)"
|
||
},
|
||
{
|
||
"name": "mode",
|
||
"type": "String",
|
||
"desc": "受控模式值,比对决定 is-active 与 aria-checked(frameworks/ThemeSwitcher.jsx:17,19)"
|
||
},
|
||
{
|
||
"name": "onBrandChange",
|
||
"type": "属性",
|
||
"desc": "色块切换回调,点击与 Enter / 空格都调它,载荷是色值(frameworks/ThemeSwitcher.jsx:38,39)"
|
||
},
|
||
{
|
||
"name": "onModeChange",
|
||
"type": "属性",
|
||
"desc": "模式切换回调,点击与 Enter / 空格都调它,载荷是模式值(frameworks/ThemeSwitcher.jsx:21,22)"
|
||
},
|
||
{
|
||
"name": "onBrandChange",
|
||
"type": "事件",
|
||
"desc": "对外回调名,色块以 onBrandChange(c) 调用(frameworks/ThemeSwitcher.jsx:38,39)"
|
||
},
|
||
{
|
||
"name": "onClick",
|
||
"type": "事件",
|
||
"desc": "模式项与色块上的原生点击名(frameworks/ThemeSwitcher.jsx:22,39)"
|
||
},
|
||
{
|
||
"name": "onKeyDown",
|
||
"type": "事件",
|
||
"desc": "键盘按键处理:Enter 与空格触发与点击相同的回调(frameworks/ThemeSwitcher.jsx:21,38)"
|
||
}
|
||
]
|
||
},
|
||
"resources": [
|
||
{
|
||
"file": "frameworks/ThemeSwitcher.jsx",
|
||
"kind": "React",
|
||
"desc": "该端实现(本页 API 与用法的唯一权威来源)。"
|
||
},
|
||
{
|
||
"file": "frameworks/ThemeSwitcher.css",
|
||
"kind": "样式",
|
||
"desc": "该组件的样式文件,类名口径以它为准。"
|
||
}
|
||
],
|
||
"exampleIds": [
|
||
"themeswitcher-ex-1"
|
||
],
|
||
"notes": [
|
||
"props 解构见 frameworks/ThemeSwitcher.jsx:11,共 4 个(mode / brand / onModeChange / onBrandChange);两组常量见 4-9 行。",
|
||
"键盘处理见 frameworks/ThemeSwitcher.jsx:21 与 38(Enter / 空格),点击处理见 22 与 39;aria 属性见 13、18-19、34-36 行。",
|
||
"实现缺口:选项集合不可配、回调未判空、自建 radio 无方向键组内切换(frameworks/ThemeSwitcher.jsx:14-27,38);按实现写,未补。",
|
||
"a11y 依据:aria-label=\"主题模式\" 见 frameworks/ThemeSwitcher.jsx:13,色块 aria-label 见第 35 行,tabIndex 见 20 与 37 行。",
|
||
"apiCarrier.table 保留了自动生成时的「属性 + 事件」两套同名行(onBrandChange 出现两次),本次只改 desc 文案,未调整行结构。"
|
||
]
|
||
}
|