@icen.ai/ui 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +2 -2
  2. package/dist/base.css +11 -6
  3. package/dist/behaviors/ai-branch.mjs +13 -0
  4. package/dist/behaviors/ai-chat.mjs +13 -0
  5. package/dist/behaviors/ai-composer.mjs +13 -0
  6. package/dist/behaviors/ai-core.mjs +13 -0
  7. package/dist/behaviors/ai-diff.mjs +13 -0
  8. package/dist/behaviors/ai-feedback.mjs +13 -0
  9. package/dist/behaviors/ai-panel.mjs +13 -0
  10. package/dist/behaviors/ai-provider.mjs +13 -0
  11. package/dist/behaviors/ai-threads.mjs +13 -0
  12. package/dist/behaviors/ai-tool.mjs +242 -0
  13. package/dist/behaviors/ai-tools.mjs +242 -0
  14. package/dist/behaviors/autocomplete.mjs +13 -0
  15. package/dist/behaviors/back-top.mjs +13 -0
  16. package/dist/behaviors/carousel.mjs +13 -0
  17. package/dist/behaviors/cascader.mjs +13 -0
  18. package/dist/behaviors/charts.d.mts +12 -1
  19. package/dist/behaviors/charts.mjs +242 -0
  20. package/dist/behaviors/code-block.mjs +13 -0
  21. package/dist/behaviors/context-menu.mjs +13 -0
  22. package/dist/behaviors/controls.mjs +13 -0
  23. package/dist/behaviors/copy.mjs +13 -0
  24. package/dist/behaviors/datatable.mjs +13 -0
  25. package/dist/behaviors/date-picker.mjs +13 -0
  26. package/dist/behaviors/form-validate.mjs +13 -0
  27. package/dist/behaviors/i18n.d.mts +13 -0
  28. package/dist/behaviors/i18n.mjs +26 -0
  29. package/dist/behaviors/input.mjs +13 -0
  30. package/dist/behaviors/kb-access.mjs +13 -0
  31. package/dist/behaviors/kb-acl.mjs +13 -0
  32. package/dist/behaviors/kb-answer.mjs +242 -0
  33. package/dist/behaviors/kb-audit.mjs +13 -0
  34. package/dist/behaviors/kb-canvas.mjs +13 -0
  35. package/dist/behaviors/kb-chain.mjs +13 -0
  36. package/dist/behaviors/kb-checkpoint.mjs +13 -0
  37. package/dist/behaviors/kb-chunks.mjs +13 -0
  38. package/dist/behaviors/kb-citation.mjs +13 -0
  39. package/dist/behaviors/kb-clarify.mjs +13 -0
  40. package/dist/behaviors/kb-conflict.mjs +13 -0
  41. package/dist/behaviors/kb-connector.mjs +13 -0
  42. package/dist/behaviors/kb-core.mjs +13 -0
  43. package/dist/behaviors/kb-eval.mjs +13 -0
  44. package/dist/behaviors/kb-explain.mjs +13 -0
  45. package/dist/behaviors/kb-filter.mjs +13 -0
  46. package/dist/behaviors/kb-gap.mjs +13 -0
  47. package/dist/behaviors/kb-hittest.mjs +13 -0
  48. package/dist/behaviors/kb-metadata.mjs +13 -0
  49. package/dist/behaviors/kb-passage.mjs +13 -0
  50. package/dist/behaviors/kb-pipeline.mjs +13 -0
  51. package/dist/behaviors/kb-qa.mjs +13 -0
  52. package/dist/behaviors/kb-rerank.mjs +13 -0
  53. package/dist/behaviors/kb-retrieval.mjs +13 -0
  54. package/dist/behaviors/kb-review.mjs +13 -0
  55. package/dist/behaviors/kb-sandbox.mjs +13 -0
  56. package/dist/behaviors/kb-segment.mjs +13 -0
  57. package/dist/behaviors/kb-select.mjs +13 -0
  58. package/dist/behaviors/kb-sources.mjs +13 -0
  59. package/dist/behaviors/kb-sql.mjs +13 -0
  60. package/dist/behaviors/kb-trace.mjs +13 -0
  61. package/dist/behaviors/kb-visibility.mjs +13 -0
  62. package/dist/behaviors/kb-who-can.mjs +13 -0
  63. package/dist/behaviors/mentions.mjs +13 -0
  64. package/dist/behaviors/modal.mjs +13 -0
  65. package/dist/behaviors/motion.d.mts +16 -0
  66. package/dist/behaviors/motion.mjs +39 -0
  67. package/dist/behaviors/notification.mjs +13 -0
  68. package/dist/behaviors/panel.mjs +13 -0
  69. package/dist/behaviors/select.mjs +13 -0
  70. package/dist/behaviors/suggestions.mjs +13 -0
  71. package/dist/behaviors/tag-input.mjs +13 -0
  72. package/dist/behaviors/theme-switcher.mjs +13 -0
  73. package/dist/behaviors/toast.mjs +13 -0
  74. package/dist/behaviors/tree-select.mjs +13 -0
  75. package/dist/behaviors/upload.mjs +13 -0
  76. package/dist/components/charts.css +29 -0
  77. package/dist/components/material.css +1 -1
  78. package/dist/index.d.mts +1 -1
  79. package/dist/index.mjs +257 -1
  80. package/dist/react.mjs +242 -0
  81. package/dist/registry.json +3 -1
  82. package/dist/tokens/design.css +15 -9
  83. package/dist/tokens/dtcg.json +3594 -738
  84. package/dist/tokens/figma.variables.json +1705 -157
  85. package/dist/tokens/motion.css +51 -0
  86. package/dist/tokens/pixel.css +7 -0
  87. package/dist/tokens/tokens-studio.json +3007 -679
  88. package/dist/tokens/typography.css +33 -0
  89. package/dist/tokens.css +107 -10
  90. package/dist/ui.css +147 -16
  91. package/dist/vue.mjs +242 -0
  92. package/docs/spec/charts-scale-a11y.md +115 -0
  93. package/docs/spec/motion-typography.md +105 -0
  94. package/package.json +2 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![CI](https://github.com/icen-ai/ui/actions/workflows/ci.yml/badge.svg)](https://github.com/icen-ai/ui/actions/workflows/ci.yml)
5
5
  [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
6
6
 
7
- icen.ai 的设计系统。组件、图表和 AI 界面共用一套设计令牌——换肤不改代码,UI 可直接交给模型调用。无框架,零运行时依赖,MIT。
7
+ icen.ai 的设计系统:<!-- meta:components -->122<!-- /meta:components --> 个组件入口、<!-- meta:charts.total -->14<!-- /meta:charts.total --> 种图表与 AI 原生组件族共用一套设计令牌——换肤不改代码,UI 可直接交给模型调用。无框架、零运行时依赖(`dependencies` 为空,可验证)、SSR 安全,MIT。
8
8
 
9
9
  - 文档与实时演示:<https://ui.icen.ai>
10
10
  - 安装:`bun add @icen.ai/ui`(或 `npm i`)
@@ -39,7 +39,7 @@ renderLine(el, { labels, series }); // 函数式组件:无 init,直接渲染
39
39
  ## 里面有什么
40
40
 
41
41
  - **组件**:无框架组件库(表单 / 浮层 / 导航 / 数据展示 / 反馈),纯 CSS 契约 + 按需行为 JS。类名 `icen-*`、钩子 `data-icen-*`、变量 `--icen-*`,产物全部进 cascade layers,与任何第三方 CSS 共存零冲突。
42
- - **图表**:一份 JSON 十三种图,悬停/点击/图例开关内建,不依赖图表库。
42
+ - **图表**:一份 JSON <!-- meta:charts.total -->14<!-- /meta:charts.total --> 种图,悬停/点击/图例开关内建,不依赖图表库。
43
43
  - **AI 界面**:对话 / 推理 / 工具调用 / 审批 / 输入台 / 用量审计;兼容 OpenAI / Anthropic / MCP / AI SDK 协议;UI 能力可注册成模型直接调用的工具。
44
44
  - **知识库**:覆盖 RAG 全链路的组件族(摄取 / 检索 / 问数 / 治理 / 权限),权限域 fail-closed。
45
45
  - **主题**:色彩预设 × 设计原语 × 明暗,全部挂在 `<html>` data 属性上;自建品牌只需在自家 CSS 写一块 token 面。
package/dist/base.css CHANGED
@@ -493,15 +493,20 @@ p { margin: 0 0 1em; }
493
493
  动效与无障碍兜底
494
494
  ══════════════════════════════════════════════════════════════ */
495
495
 
496
- /* reduced-motion:所有动画/过渡压缩到 ~0ms(保留可访问性最小可视信号) */
496
+ /* reduced-motion 与手动覆盖的行为压制(变量开关在 design.css 自持):
497
+ 循环/环境动画单次瞬时 + 平滑滚动关闭;过渡时长经 --icen-design-motion 归零瞬时完成(状态反馈保留)。 */
497
498
  @media (prefers-reduced-motion: reduce) {
498
- *, *::before, *::after {
499
- animation-duration: 0.01ms !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
500
- animation-iteration-count: 1 !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
501
- transition-duration: 0.01ms !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
502
- scroll-behavior: auto !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
499
+ :root:not([data-icen-motion="full"]) *, :root:not([data-icen-motion="full"]) *::before, :root:not([data-icen-motion="full"]) *::after {
500
+ animation-duration: 0.01ms !important; /* guard:allow-important 动效守卫:降级需压制组件循环动画 */
501
+ animation-iteration-count: 1 !important; /* guard:allow-important 动效守卫:降级需压制组件循环动画 */
502
+ scroll-behavior: auto !important; /* guard:allow-important 动效守卫:降级需关闭平滑滚动 */
503
503
  }
504
504
  }
505
+ :root[data-icen-motion="reduce"] *, :root[data-icen-motion="reduce"] *::before, :root[data-icen-motion="reduce"] *::after {
506
+ animation-duration: 0.01ms !important; /* guard:allow-important 手动降级:与系统降级同口径 */
507
+ animation-iteration-count: 1 !important; /* guard:allow-important 手动降级:与系统降级同口径 */
508
+ scroll-behavior: auto !important; /* guard:allow-important 手动降级:与系统降级同口径 */
509
+ }
505
510
 
506
511
  /* 触屏设备(无精细指针):压低 pressable 按下形变(hover 抬升已由 hover 守卫关闭) */
507
512
  @media (pointer: coarse) {
@@ -305,6 +305,19 @@ var ICEN_LOCALE_ZH_CN = {
305
305
  "charts.noData": "\u6682\u65E0\u6570\u636E",
306
306
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
307
307
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
308
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
309
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
310
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
311
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
312
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
313
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
314
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
315
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
316
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
317
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
318
+ "charts.a11y.trendDown": "\u4E0B\u964D",
319
+ "charts.a11y.trendFlat": "\u6301\u5E73",
320
+ "charts.a11y.trendUp": "\u4E0A\u5347",
308
321
  "charts.type.area": "\u9762\u79EF\u56FE",
309
322
  "charts.type.donut": "\u73AF\u5F62\u56FE",
310
323
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -204,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
204
204
  "charts.noData": "\u6682\u65E0\u6570\u636E",
205
205
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
206
206
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
207
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
208
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
209
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
210
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
211
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
212
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
213
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
214
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
215
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
216
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
217
+ "charts.a11y.trendDown": "\u4E0B\u964D",
218
+ "charts.a11y.trendFlat": "\u6301\u5E73",
219
+ "charts.a11y.trendUp": "\u4E0A\u5347",
207
220
  "charts.type.area": "\u9762\u79EF\u56FE",
208
221
  "charts.type.donut": "\u73AF\u5F62\u56FE",
209
222
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -305,6 +305,19 @@ var ICEN_LOCALE_ZH_CN = {
305
305
  "charts.noData": "\u6682\u65E0\u6570\u636E",
306
306
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
307
307
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
308
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
309
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
310
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
311
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
312
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
313
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
314
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
315
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
316
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
317
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
318
+ "charts.a11y.trendDown": "\u4E0B\u964D",
319
+ "charts.a11y.trendFlat": "\u6301\u5E73",
320
+ "charts.a11y.trendUp": "\u4E0A\u5347",
308
321
  "charts.type.area": "\u9762\u79EF\u56FE",
309
322
  "charts.type.donut": "\u73AF\u5F62\u56FE",
310
323
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -197,6 +197,19 @@ var ICEN_LOCALE_ZH_CN = {
197
197
  "charts.noData": "\u6682\u65E0\u6570\u636E",
198
198
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
199
199
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
200
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
201
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
202
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
203
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
204
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
205
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
206
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
207
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
208
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
209
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
210
+ "charts.a11y.trendDown": "\u4E0B\u964D",
211
+ "charts.a11y.trendFlat": "\u6301\u5E73",
212
+ "charts.a11y.trendUp": "\u4E0A\u5347",
200
213
  "charts.type.area": "\u9762\u79EF\u56FE",
201
214
  "charts.type.donut": "\u73AF\u5F62\u56FE",
202
215
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -204,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
204
204
  "charts.noData": "\u6682\u65E0\u6570\u636E",
205
205
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
206
206
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
207
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
208
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
209
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
210
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
211
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
212
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
213
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
214
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
215
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
216
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
217
+ "charts.a11y.trendDown": "\u4E0B\u964D",
218
+ "charts.a11y.trendFlat": "\u6301\u5E73",
219
+ "charts.a11y.trendUp": "\u4E0A\u5347",
207
220
  "charts.type.area": "\u9762\u79EF\u56FE",
208
221
  "charts.type.donut": "\u73AF\u5F62\u56FE",
209
222
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -204,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
204
204
  "charts.noData": "\u6682\u65E0\u6570\u636E",
205
205
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
206
206
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
207
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
208
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
209
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
210
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
211
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
212
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
213
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
214
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
215
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
216
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
217
+ "charts.a11y.trendDown": "\u4E0B\u964D",
218
+ "charts.a11y.trendFlat": "\u6301\u5E73",
219
+ "charts.a11y.trendUp": "\u4E0A\u5347",
207
220
  "charts.type.area": "\u9762\u79EF\u56FE",
208
221
  "charts.type.donut": "\u73AF\u5F62\u56FE",
209
222
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -305,6 +305,19 @@ var ICEN_LOCALE_ZH_CN = {
305
305
  "charts.noData": "\u6682\u65E0\u6570\u636E",
306
306
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
307
307
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
308
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
309
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
310
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
311
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
312
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
313
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
314
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
315
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
316
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
317
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
318
+ "charts.a11y.trendDown": "\u4E0B\u964D",
319
+ "charts.a11y.trendFlat": "\u6301\u5E73",
320
+ "charts.a11y.trendUp": "\u4E0A\u5347",
308
321
  "charts.type.area": "\u9762\u79EF\u56FE",
309
322
  "charts.type.donut": "\u73AF\u5F62\u56FE",
310
323
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -204,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
204
204
  "charts.noData": "\u6682\u65E0\u6570\u636E",
205
205
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
206
206
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
207
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
208
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
209
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
210
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
211
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
212
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
213
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
214
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
215
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
216
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
217
+ "charts.a11y.trendDown": "\u4E0B\u964D",
218
+ "charts.a11y.trendFlat": "\u6301\u5E73",
219
+ "charts.a11y.trendUp": "\u4E0A\u5347",
207
220
  "charts.type.area": "\u9762\u79EF\u56FE",
208
221
  "charts.type.donut": "\u73AF\u5F62\u56FE",
209
222
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -305,6 +305,19 @@ var ICEN_LOCALE_ZH_CN = {
305
305
  "charts.noData": "\u6682\u65E0\u6570\u636E",
306
306
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
307
307
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
308
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
309
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
310
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
311
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
312
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
313
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
314
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
315
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
316
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
317
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
318
+ "charts.a11y.trendDown": "\u4E0B\u964D",
319
+ "charts.a11y.trendFlat": "\u6301\u5E73",
320
+ "charts.a11y.trendUp": "\u4E0A\u5347",
308
321
  "charts.type.area": "\u9762\u79EF\u56FE",
309
322
  "charts.type.donut": "\u73AF\u5F62\u56FE",
310
323
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -204,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
204
204
  "charts.noData": "\u6682\u65E0\u6570\u636E",
205
205
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
206
206
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
207
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
208
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
209
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
210
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
211
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
212
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
213
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
214
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
215
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
216
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
217
+ "charts.a11y.trendDown": "\u4E0B\u964D",
218
+ "charts.a11y.trendFlat": "\u6301\u5E73",
219
+ "charts.a11y.trendUp": "\u4E0A\u5347",
207
220
  "charts.type.area": "\u9762\u79EF\u56FE",
208
221
  "charts.type.donut": "\u73AF\u5F62\u56FE",
209
222
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -2570,6 +2583,14 @@ function normalizeChartSpec(raw) {
2570
2583
  }
2571
2584
  if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2572
2585
  if (typeof s.loading === "boolean") spec.loading = s.loading;
2586
+ if (s.a11y && typeof s.a11y === "object") {
2587
+ const a = s.a11y;
2588
+ const a11y = {};
2589
+ if (typeof a.summary === "boolean") a11y.summary = a.summary;
2590
+ if (typeof a.table === "boolean") a11y.table = a.table;
2591
+ if (typeof a.keyboard === "boolean") a11y.keyboard = a.keyboard;
2592
+ if (Object.keys(a11y).length > 0) spec.a11y = a11y;
2593
+ }
2573
2594
  if (Array.isArray(s.marks)) {
2574
2595
  const marks = [];
2575
2596
  for (const raw2 of s.marks) {
@@ -2925,6 +2946,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2925
2946
  function chartAriaLabel(title, typeName) {
2926
2947
  return title ? `${typeName}\uFF1A${title}` : typeName;
2927
2948
  }
2949
+ function summarizeChart(view, type, fmt2) {
2950
+ const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
2951
+ const parts = [];
2952
+ if (series.length > 1) parts.push(t("charts.a11y.seriesCount", { p0: series.length }));
2953
+ if (type === "scatter") {
2954
+ const pts = view.points ?? [];
2955
+ if (pts.length > 0) {
2956
+ const xs = pts.map((p) => p.x);
2957
+ const ys = pts.map((p) => p.y);
2958
+ parts.push(t("charts.a11y.scatterRange", { p0: fmt2(Math.min(...xs)), p1: fmt2(Math.max(...xs)), p2: fmt2(Math.min(...ys)), p3: fmt2(Math.max(...ys)) }));
2959
+ }
2960
+ return parts.join("\uFF1B");
2961
+ }
2962
+ const labels = view.labels ?? [];
2963
+ if (labels.length > 1) parts.push(t("charts.a11y.range", { p0: labels[0], p1: labels[labels.length - 1] }));
2964
+ let min = Infinity;
2965
+ let max = -Infinity;
2966
+ let minAt = "";
2967
+ let maxAt = "";
2968
+ for (const s of series) {
2969
+ s.values.forEach((v, i) => {
2970
+ if (v < min) {
2971
+ min = v;
2972
+ minAt = labels[i] ?? String(i + 1);
2973
+ }
2974
+ if (v > max) {
2975
+ max = v;
2976
+ maxAt = labels[i] ?? String(i + 1);
2977
+ }
2978
+ });
2979
+ }
2980
+ if (Number.isFinite(min) && Number.isFinite(max)) {
2981
+ parts.push(t("charts.a11y.min", { p0: fmt2(min), p1: minAt }));
2982
+ parts.push(t("charts.a11y.max", { p0: fmt2(max), p1: maxAt }));
2983
+ }
2984
+ const first = series[0]?.values ?? [];
2985
+ if (first.length > 1) {
2986
+ const d = first[first.length - 1] - first[0];
2987
+ const key = Math.abs(d) < 1e-9 ? "charts.a11y.trendFlat" : d > 0 ? "charts.a11y.trendUp" : "charts.a11y.trendDown";
2988
+ parts.push(t("charts.a11y.trend", { p0: t(key) }));
2989
+ }
2990
+ return parts.join("\uFF1B");
2991
+ }
2992
+ function buildChartTable(view, spec, type, fmt2) {
2993
+ const table = document.createElement("table");
2994
+ table.className = "icen-chart-table";
2995
+ const caption = document.createElement("caption");
2996
+ caption.textContent = t("charts.a11y.tableCaption", { p0: spec.title ?? String(type) });
2997
+ table.appendChild(caption);
2998
+ const addRow = (target, cells, head) => {
2999
+ const tr = document.createElement("tr");
3000
+ for (const c of cells) {
3001
+ const cell = document.createElement(head ? "th" : "td");
3002
+ if (head) cell.scope = target.tagName === "THEAD" ? "col" : "row";
3003
+ cell.textContent = c;
3004
+ tr.appendChild(cell);
3005
+ }
3006
+ target.appendChild(tr);
3007
+ };
3008
+ const thead = table.createTHead();
3009
+ const tbody = table.createTBody();
3010
+ if (type === "scatter") {
3011
+ addRow(thead, ["x", "y"], true);
3012
+ for (const p of view.points ?? []) addRow(tbody, [fmt2(p.x), fmt2(p.y)], false);
3013
+ return table;
3014
+ }
3015
+ const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
3016
+ const labels = view.labels ?? [];
3017
+ addRow(thead, ["", ...series.map((s, i) => s.name || String(i + 1))], true);
3018
+ const n = Math.max(labels.length, ...series.map((s) => s.values.length));
3019
+ for (let i = 0; i < n; i++) {
3020
+ addRow(tbody, [labels[i] ?? String(i + 1), ...series.map((s) => fmt2(s.values[i] ?? 0))], false);
3021
+ }
3022
+ return table;
3023
+ }
2928
3024
  function svgDimsOf(svg) {
2929
3025
  const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2930
3026
  const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
@@ -3265,6 +3361,7 @@ function renderChart(el, raw) {
3265
3361
  if (!isZoomableType(t2) || fullLength() < 2) return;
3266
3362
  const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
3267
3363
  if (!plot) return;
3364
+ plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
3268
3365
  const on = (type, fn) => {
3269
3366
  plot.addEventListener(type, fn);
3270
3367
  };
@@ -3320,6 +3417,149 @@ function renderChart(el, raw) {
3320
3417
  render();
3321
3418
  });
3322
3419
  };
3420
+ const KB_TYPES = /* @__PURE__ */ new Set(["line", "area", "vbar", "hbar", "scatter"]);
3421
+ const kbCursor = { si: 0, i: 0, active: false };
3422
+ let liveRegion = null;
3423
+ let a11ySeq = 0;
3424
+ const a11yOf = () => ({
3425
+ summary: current2.a11y?.summary !== false,
3426
+ table: current2.a11y?.table === true,
3427
+ keyboard: current2.a11y?.keyboard !== false
3428
+ });
3429
+ const seriesViewOf = (view) => view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
3430
+ const kbPointCount = (view) => typeOf() === "scatter" ? view.points?.length ?? 0 : Math.max(0, ...seriesViewOf(view).map((s) => s.values.length), view.labels?.length ?? 0);
3431
+ const kbCursorEl = () => {
3432
+ const t2 = typeOf();
3433
+ const view = viewOf();
3434
+ const series = seriesViewOf(view);
3435
+ const n = kbPointCount(view);
3436
+ if (n < 1) return null;
3437
+ const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
3438
+ const i = clampNum(kbCursor.i, 0, n - 1);
3439
+ if (t2 === "line" || t2 === "area") {
3440
+ const svg = root.querySelector(".icen-chart-line svg");
3441
+ if (!svg) return null;
3442
+ const dots = svg.querySelectorAll("circle");
3443
+ let base = 0;
3444
+ for (let k = 0; k < si; k++) base += Math.min(series[k].values.length, n);
3445
+ return dots.item(base + i) ?? null;
3446
+ }
3447
+ if (t2 === "scatter") return root.querySelector(".icen-chart-scatter svg")?.querySelectorAll("circle").item(i) ?? null;
3448
+ if (t2 === "vbar") return root.querySelectorAll(".icen-chart-vbar-bar").item(series.length > 1 ? i * series.length + si : i) ?? null;
3449
+ if (t2 === "hbar") return root.querySelectorAll(".icen-chart-hbar-bar").item(i) ?? null;
3450
+ return null;
3451
+ };
3452
+ const announceKb = (text) => {
3453
+ if (!liveRegion || !liveRegion.isConnected) {
3454
+ liveRegion = document.createElement("div");
3455
+ liveRegion.className = "icen-chart-live";
3456
+ liveRegion.setAttribute("aria-live", "polite");
3457
+ root.appendChild(liveRegion);
3458
+ }
3459
+ liveRegion.textContent = "";
3460
+ liveRegion.textContent = text;
3461
+ };
3462
+ const applyKbCursor = () => {
3463
+ for (const el2 of root.querySelectorAll(".icen-chart-kb-focus")) el2.classList.remove("icen-chart-kb-focus");
3464
+ if (!kbCursor.active) return;
3465
+ kbCursorEl()?.classList.add("icen-chart-kb-focus");
3466
+ };
3467
+ const announceCursor = () => {
3468
+ const view = viewOf();
3469
+ const series = seriesViewOf(view);
3470
+ const n = kbPointCount(view);
3471
+ if (n < 1) return;
3472
+ const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
3473
+ const i = clampNum(kbCursor.i, 0, Math.max(0, n - 1));
3474
+ const fmt2 = chartFormatValue(current2.format);
3475
+ if (typeOf() === "scatter") {
3476
+ const p = view.points?.[i];
3477
+ if (!p) return;
3478
+ announceKb(t("charts.a11y.point", { p0: `x ${fmt2(p.x)}`, p1: `y ${fmt2(p.y)}`, p2: i + 1, p3: n }));
3479
+ return;
3480
+ }
3481
+ const label = view.labels?.[i] ?? String(i + 1);
3482
+ const value = series[si]?.values[i] ?? 0;
3483
+ if (series.length > 1) announceKb(t("charts.a11y.pointSeries", { p0: series[si].name || String(si + 1), p1: label, p2: fmt2(value), p3: i + 1, p4: n }));
3484
+ else announceKb(t("charts.a11y.point", { p0: label, p1: fmt2(value), p2: i + 1, p3: n }));
3485
+ };
3486
+ const onKbKeydown = (e) => {
3487
+ const conf = a11yOf();
3488
+ if (!conf.keyboard || !KB_TYPES.has(typeOf())) return;
3489
+ const g = root.querySelector("[data-icen-chart-kb]");
3490
+ if (!g || e.target !== g) return;
3491
+ if (e.key === "Escape") {
3492
+ if (zoomWindow) {
3493
+ zoomWindow = null;
3494
+ kbCursor.active = false;
3495
+ render();
3496
+ }
3497
+ return;
3498
+ }
3499
+ const view = viewOf();
3500
+ const series = seriesViewOf(view);
3501
+ const n = kbPointCount(view);
3502
+ if (n < 1) return;
3503
+ const siMax = Math.max(0, series.length - 1);
3504
+ let moved = true;
3505
+ switch (e.key) {
3506
+ case "ArrowRight":
3507
+ kbCursor.i = clampNum(kbCursor.i + 1, 0, n - 1);
3508
+ break;
3509
+ case "ArrowLeft":
3510
+ kbCursor.i = clampNum(kbCursor.i - 1, 0, n - 1);
3511
+ break;
3512
+ case "ArrowDown":
3513
+ kbCursor.si = clampNum(kbCursor.si + 1, 0, siMax);
3514
+ break;
3515
+ case "ArrowUp":
3516
+ kbCursor.si = clampNum(kbCursor.si - 1, 0, siMax);
3517
+ break;
3518
+ case "Home":
3519
+ kbCursor.i = 0;
3520
+ break;
3521
+ case "End":
3522
+ kbCursor.i = n - 1;
3523
+ break;
3524
+ default:
3525
+ moved = false;
3526
+ }
3527
+ if (!moved) return;
3528
+ e.preventDefault();
3529
+ kbCursor.active = true;
3530
+ applyKbCursor();
3531
+ announceCursor();
3532
+ };
3533
+ root.addEventListener("keydown", onKbKeydown);
3534
+ const applyChartA11yPlus = (view, spec, type, formatValue) => {
3535
+ const conf = a11yOf();
3536
+ const graphic = root.querySelector('[role="img"]');
3537
+ if (!graphic) return;
3538
+ const body = root.querySelector(".icen-chart-body") ?? graphic.parentElement ?? root;
3539
+ const summaryParts = [];
3540
+ if (conf.summary) summaryParts.push(summarizeChart(view, type, formatValue));
3541
+ if (conf.keyboard && KB_TYPES.has(type)) summaryParts.push(t("charts.a11y.keyboardHint"));
3542
+ const summaryText = summaryParts.filter(Boolean).join("\uFF1B");
3543
+ if (summaryText) {
3544
+ const p = document.createElement("p");
3545
+ p.className = "icen-chart-summary";
3546
+ p.id = `icen-chart-a11y-${++a11ySeq}`;
3547
+ p.textContent = summaryText;
3548
+ body.appendChild(p);
3549
+ graphic.setAttribute("aria-describedby", p.id);
3550
+ } else {
3551
+ graphic.removeAttribute("aria-describedby");
3552
+ }
3553
+ if (conf.keyboard && KB_TYPES.has(type)) {
3554
+ graphic.setAttribute("tabindex", "0");
3555
+ graphic.setAttribute("data-icen-chart-kb", "");
3556
+ } else {
3557
+ graphic.removeAttribute("tabindex");
3558
+ graphic.removeAttribute("data-icen-chart-kb");
3559
+ }
3560
+ if (conf.table) body.appendChild(buildChartTable(view, spec, type, formatValue));
3561
+ applyKbCursor();
3562
+ };
3323
3563
  const render = () => {
3324
3564
  if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
3325
3565
  const spec = current2;
@@ -3400,6 +3640,7 @@ function renderChart(el, raw) {
3400
3640
  }
3401
3641
  }
3402
3642
  if (loading) return;
3643
+ applyChartA11yPlus(view, spec, type, formatValue);
3403
3644
  paintChartMarks(root, view, spec, formatValue, warnedMarks);
3404
3645
  bindZoomGesture();
3405
3646
  };
@@ -3481,6 +3722,7 @@ function renderChart(el, raw) {
3481
3722
  releaseFluidWidth(root);
3482
3723
  hiddenLegendKeys.delete(root);
3483
3724
  zoomDragCleanup?.();
3725
+ root.removeEventListener("keydown", onKbKeydown);
3484
3726
  root.textContent = "";
3485
3727
  root.classList.remove("is-loading");
3486
3728
  unbindEvents();