@icen.ai/ui 0.10.0 → 0.11.1

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 (362) hide show
  1. package/AGENTS.md +79 -309
  2. package/LICENSE +21 -0
  3. package/README.md +43 -54
  4. package/dist/base.css +68 -22
  5. package/dist/behaviors/accordion.mjs +1 -1
  6. package/dist/behaviors/ai-branch.mjs +14 -0
  7. package/dist/behaviors/ai-chat.d.mts +2 -2
  8. package/dist/behaviors/ai-chat.mjs +66 -10
  9. package/dist/behaviors/ai-composer.d.mts +5 -5
  10. package/dist/behaviors/ai-composer.mjs +34 -10
  11. package/dist/behaviors/ai-core.mjs +14 -0
  12. package/dist/behaviors/ai-diff.mjs +14 -0
  13. package/dist/behaviors/ai-feedback.mjs +14 -0
  14. package/dist/behaviors/ai-panel.d.mts +2 -2
  15. package/dist/behaviors/ai-panel.mjs +14 -0
  16. package/dist/behaviors/ai-provider.d.mts +1 -1
  17. package/dist/behaviors/ai-provider.mjs +14 -0
  18. package/dist/behaviors/ai-threads.mjs +14 -0
  19. package/dist/behaviors/ai-tool.d.mts +1 -1
  20. package/dist/behaviors/ai-tool.mjs +299 -24
  21. package/dist/behaviors/ai-tools.mjs +1179 -28
  22. package/dist/behaviors/autocomplete.d.mts +1 -1
  23. package/dist/behaviors/autocomplete.mjs +14 -0
  24. package/dist/behaviors/back-top.mjs +14 -0
  25. package/dist/behaviors/carousel.mjs +21 -1
  26. package/dist/behaviors/cascader.mjs +27 -0
  27. package/dist/behaviors/charts.d.mts +12 -1
  28. package/dist/behaviors/charts.mjs +298 -20
  29. package/dist/behaviors/code-block.mjs +22 -1
  30. package/dist/behaviors/command-palette.mjs +3 -3
  31. package/dist/behaviors/context-menu.d.mts +2 -2
  32. package/dist/behaviors/context-menu.mjs +14 -0
  33. package/dist/behaviors/controls.d.mts +8 -8
  34. package/dist/behaviors/controls.mjs +50 -6
  35. package/dist/behaviors/copy.mjs +14 -0
  36. package/dist/behaviors/datatable.d.mts +3 -3
  37. package/dist/behaviors/datatable.mjs +89 -11
  38. package/dist/behaviors/date-picker.mjs +14 -0
  39. package/dist/behaviors/events.d.mts +10 -10
  40. package/dist/behaviors/events.mjs +11 -1
  41. package/dist/behaviors/form-validate.d.mts +10 -1
  42. package/dist/behaviors/form-validate.mjs +279 -4611
  43. package/dist/behaviors/i18n.d.mts +14 -0
  44. package/dist/behaviors/i18n.mjs +28 -0
  45. package/dist/behaviors/input.mjs +16 -0
  46. package/dist/behaviors/kb-access.d.mts +2 -2
  47. package/dist/behaviors/kb-access.mjs +21 -2
  48. package/dist/behaviors/kb-acl.d.mts +2 -2
  49. package/dist/behaviors/kb-acl.mjs +14 -0
  50. package/dist/behaviors/kb-answer.d.mts +2 -2
  51. package/dist/behaviors/kb-answer.mjs +298 -23
  52. package/dist/behaviors/kb-audit.d.mts +2 -2
  53. package/dist/behaviors/kb-audit.mjs +14 -0
  54. package/dist/behaviors/kb-canvas.d.mts +3 -3
  55. package/dist/behaviors/kb-canvas.mjs +14 -0
  56. package/dist/behaviors/kb-chain.d.mts +2 -2
  57. package/dist/behaviors/kb-chain.mjs +14 -0
  58. package/dist/behaviors/kb-checkpoint.d.mts +2 -2
  59. package/dist/behaviors/kb-checkpoint.mjs +14 -0
  60. package/dist/behaviors/kb-chunks.d.mts +2 -2
  61. package/dist/behaviors/kb-chunks.mjs +14 -0
  62. package/dist/behaviors/kb-citation.d.mts +2 -2
  63. package/dist/behaviors/kb-citation.mjs +33 -6
  64. package/dist/behaviors/kb-clarify.d.mts +2 -2
  65. package/dist/behaviors/kb-clarify.mjs +14 -0
  66. package/dist/behaviors/kb-conflict.d.mts +2 -2
  67. package/dist/behaviors/kb-conflict.mjs +14 -0
  68. package/dist/behaviors/kb-connector.d.mts +2 -2
  69. package/dist/behaviors/kb-connector.mjs +14 -0
  70. package/dist/behaviors/kb-core.d.mts +1 -1
  71. package/dist/behaviors/kb-core.mjs +14 -0
  72. package/dist/behaviors/kb-eval.d.mts +2 -2
  73. package/dist/behaviors/kb-eval.mjs +21 -2
  74. package/dist/behaviors/kb-explain.d.mts +2 -2
  75. package/dist/behaviors/kb-explain.mjs +26 -2
  76. package/dist/behaviors/kb-filter.d.mts +2 -2
  77. package/dist/behaviors/kb-filter.mjs +21 -2
  78. package/dist/behaviors/kb-gap.d.mts +2 -2
  79. package/dist/behaviors/kb-gap.mjs +14 -0
  80. package/dist/behaviors/kb-hittest.d.mts +2 -2
  81. package/dist/behaviors/kb-hittest.mjs +15 -1
  82. package/dist/behaviors/kb-metadata.mjs +19 -0
  83. package/dist/behaviors/kb-passage.d.mts +2 -2
  84. package/dist/behaviors/kb-passage.mjs +14 -0
  85. package/dist/behaviors/kb-pipeline.d.mts +2 -2
  86. package/dist/behaviors/kb-pipeline.mjs +14 -0
  87. package/dist/behaviors/kb-qa.mjs +14 -0
  88. package/dist/behaviors/kb-rerank.d.mts +2 -2
  89. package/dist/behaviors/kb-rerank.mjs +14 -0
  90. package/dist/behaviors/kb-retrieval.d.mts +2 -2
  91. package/dist/behaviors/kb-retrieval.mjs +31 -4
  92. package/dist/behaviors/kb-review.d.mts +2 -2
  93. package/dist/behaviors/kb-review.mjs +21 -2
  94. package/dist/behaviors/kb-sandbox.d.mts +2 -2
  95. package/dist/behaviors/kb-sandbox.mjs +20 -1
  96. package/dist/behaviors/kb-segment.d.mts +2 -2
  97. package/dist/behaviors/kb-segment.mjs +15 -1
  98. package/dist/behaviors/kb-select.mjs +21 -2
  99. package/dist/behaviors/kb-sources.d.mts +2 -2
  100. package/dist/behaviors/kb-sources.mjs +14 -0
  101. package/dist/behaviors/kb-sql.d.mts +2 -2
  102. package/dist/behaviors/kb-sql.mjs +14 -0
  103. package/dist/behaviors/kb-trace.d.mts +2 -2
  104. package/dist/behaviors/kb-trace.mjs +22 -3
  105. package/dist/behaviors/kb-visibility.d.mts +2 -2
  106. package/dist/behaviors/kb-visibility.mjs +14 -0
  107. package/dist/behaviors/kb-who-can.d.mts +2 -2
  108. package/dist/behaviors/kb-who-can.mjs +21 -2
  109. package/dist/behaviors/mentions.d.mts +1 -1
  110. package/dist/behaviors/mentions.mjs +14 -0
  111. package/dist/behaviors/modal.d.mts +1 -1
  112. package/dist/behaviors/modal.mjs +14 -0
  113. package/dist/behaviors/motion.d.mts +16 -0
  114. package/dist/behaviors/motion.mjs +39 -0
  115. package/dist/behaviors/notification.d.mts +2 -2
  116. package/dist/behaviors/notification.mjs +27 -3
  117. package/dist/behaviors/panel.mjs +14 -0
  118. package/dist/behaviors/scroll-area.d.mts +17 -0
  119. package/dist/behaviors/scroll-area.mjs +59 -0
  120. package/dist/behaviors/select.mjs +21 -2
  121. package/dist/behaviors/slider.mjs +3 -3
  122. package/dist/behaviors/split-pane.mjs +2 -0
  123. package/dist/behaviors/suggestions.mjs +14 -0
  124. package/dist/behaviors/tabs.mjs +10 -0
  125. package/dist/behaviors/tag-input.mjs +14 -0
  126. package/dist/behaviors/theme-switcher.d.mts +2 -2
  127. package/dist/behaviors/theme-switcher.mjs +30 -2
  128. package/dist/behaviors/theme.mjs +16 -2
  129. package/dist/behaviors/toast.d.mts +2 -2
  130. package/dist/behaviors/toast.mjs +14 -0
  131. package/dist/behaviors/tree-select.mjs +27 -0
  132. package/dist/behaviors/tree.mjs +4 -4
  133. package/dist/behaviors/upload.mjs +14 -0
  134. package/dist/behaviors/url-safety.d.mts +8 -0
  135. package/dist/behaviors/url-safety.mjs +11 -0
  136. package/dist/components/accordion.d.mts +2 -0
  137. package/dist/components/ai-branch.d.mts +2 -0
  138. package/dist/components/ai-chat.css +40 -33
  139. package/dist/components/ai-chat.d.mts +2 -0
  140. package/dist/components/ai-composer.d.mts +2 -0
  141. package/dist/components/ai-context.d.mts +2 -0
  142. package/dist/components/ai-context.mjs +1 -0
  143. package/dist/components/ai-diff.css +6 -6
  144. package/dist/components/ai-diff.d.mts +2 -0
  145. package/dist/components/ai-feedback.d.mts +2 -0
  146. package/dist/components/ai-files.d.mts +2 -0
  147. package/dist/components/ai-message.d.mts +2 -0
  148. package/dist/components/ai-panel.css +12 -10
  149. package/dist/components/ai-reasoning.d.mts +2 -0
  150. package/dist/components/ai-subagent.d.mts +2 -0
  151. package/dist/components/ai-subagent.mjs +1 -0
  152. package/dist/components/ai-threads.d.mts +2 -0
  153. package/dist/components/ai-todo.d.mts +2 -0
  154. package/dist/components/ai-todo.mjs +1 -0
  155. package/dist/components/ai-tool-call.d.mts +2 -0
  156. package/dist/components/ai-tool-call.mjs +1 -0
  157. package/dist/components/ai-tool.css +16 -16
  158. package/dist/components/ai-usage.d.mts +2 -0
  159. package/dist/components/alert.d.mts +2 -0
  160. package/dist/components/autocomplete.css +12 -12
  161. package/dist/components/autocomplete.d.mts +2 -0
  162. package/dist/components/avatar.d.mts +2 -0
  163. package/dist/components/back-top.css +47 -16
  164. package/dist/components/back-top.d.mts +2 -0
  165. package/dist/components/badge.css +1 -1
  166. package/dist/components/badge.d.mts +2 -0
  167. package/dist/components/breadcrumb.css +26 -8
  168. package/dist/components/breadcrumb.d.mts +2 -0
  169. package/dist/components/btn.css +67 -62
  170. package/dist/components/btn.d.mts +2 -0
  171. package/dist/components/card.css +22 -22
  172. package/dist/components/card.d.mts +2 -0
  173. package/dist/components/carousel.d.mts +2 -0
  174. package/dist/components/cascader.css +56 -35
  175. package/dist/components/cascader.d.mts +2 -0
  176. package/dist/components/chart-area.css +46 -0
  177. package/dist/components/chart-area.d.mts +2 -0
  178. package/dist/components/chart-bar.css +66 -19
  179. package/dist/components/chart-bar.d.mts +2 -0
  180. package/dist/components/chart-calendar.d.mts +2 -0
  181. package/dist/components/chart-gauge.css +23 -3
  182. package/dist/components/chart-gauge.d.mts +2 -0
  183. package/dist/components/chart-graph.css +15 -3
  184. package/dist/components/chart-graph.d.mts +2 -0
  185. package/dist/components/chart-heatmap.css +117 -95
  186. package/dist/components/chart-heatmap.d.mts +2 -0
  187. package/dist/components/chart-line.css +54 -0
  188. package/dist/components/chart-line.d.mts +2 -0
  189. package/dist/components/chart-map.d.mts +2 -0
  190. package/dist/components/chart-pie.css +29 -0
  191. package/dist/components/chart-pie.d.mts +2 -0
  192. package/dist/components/chart-radar.css +50 -1
  193. package/dist/components/chart-radar.d.mts +2 -0
  194. package/dist/components/chart-scatter.css +39 -2
  195. package/dist/components/chart-scatter.d.mts +2 -0
  196. package/dist/components/chart-sparkline.css +20 -0
  197. package/dist/components/chart-sparkline.d.mts +2 -0
  198. package/dist/components/chart-stack.css +16 -5
  199. package/dist/components/chart-stack.d.mts +2 -0
  200. package/dist/components/charts.css +109 -35
  201. package/dist/components/charts.d.mts +2 -0
  202. package/dist/components/code-block.css +10 -8
  203. package/dist/components/code-block.d.mts +2 -0
  204. package/dist/components/command-palette.css +45 -38
  205. package/dist/components/command-palette.d.mts +2 -0
  206. package/dist/components/content.css +62 -57
  207. package/dist/components/context-menu.d.mts +2 -0
  208. package/dist/components/copy.css +10 -10
  209. package/dist/components/copy.d.mts +2 -0
  210. package/dist/components/datatable.css +72 -59
  211. package/dist/components/datatable.d.mts +2 -0
  212. package/dist/components/date-picker.css +26 -26
  213. package/dist/components/date-picker.d.mts +2 -0
  214. package/dist/components/desc.d.mts +2 -0
  215. package/dist/components/dropdown.d.mts +2 -0
  216. package/dist/components/empty.css +16 -16
  217. package/dist/components/empty.d.mts +2 -0
  218. package/dist/components/feedback.css +31 -29
  219. package/dist/components/form-validate.css +20 -6
  220. package/dist/components/form-validate.d.mts +2 -0
  221. package/dist/components/form.css +17 -14
  222. package/dist/components/form.d.mts +2 -0
  223. package/dist/components/icon.css +21 -10
  224. package/dist/components/icon.d.mts +2 -0
  225. package/dist/components/input.css +22 -22
  226. package/dist/components/input.d.mts +2 -0
  227. package/dist/components/kb-access.d.mts +2 -0
  228. package/dist/components/kb-acl.d.mts +2 -0
  229. package/dist/components/kb-agent.css +134 -55
  230. package/dist/components/kb-answer.d.mts +2 -0
  231. package/dist/components/kb-audit.d.mts +2 -0
  232. package/dist/components/kb-canvas.d.mts +2 -0
  233. package/dist/components/kb-chain.d.mts +2 -0
  234. package/dist/components/kb-checkpoint.d.mts +2 -0
  235. package/dist/components/kb-chunks.d.mts +2 -0
  236. package/dist/components/kb-citation.d.mts +2 -0
  237. package/dist/components/kb-clarify.d.mts +2 -0
  238. package/dist/components/kb-conflict.d.mts +2 -0
  239. package/dist/components/kb-connector.d.mts +2 -0
  240. package/dist/components/kb-data.css +192 -80
  241. package/dist/components/kb-eval.d.mts +2 -0
  242. package/dist/components/kb-explain.d.mts +2 -0
  243. package/dist/components/kb-filter.d.mts +2 -0
  244. package/dist/components/kb-gap.d.mts +2 -0
  245. package/dist/components/kb-ground.css +165 -73
  246. package/dist/components/kb-hittest.d.mts +2 -0
  247. package/dist/components/kb-ingest.css +308 -113
  248. package/dist/components/kb-metadata.d.mts +2 -0
  249. package/dist/components/kb-ops.css +189 -75
  250. package/dist/components/kb-passage.d.mts +2 -0
  251. package/dist/components/kb-perm.css +158 -87
  252. package/dist/components/kb-pipeline.d.mts +2 -0
  253. package/dist/components/kb-qa.d.mts +2 -0
  254. package/dist/components/kb-rerank.d.mts +2 -0
  255. package/dist/components/kb-retrieval.d.mts +2 -0
  256. package/dist/components/kb-review.d.mts +2 -0
  257. package/dist/components/kb-sandbox.d.mts +2 -0
  258. package/dist/components/kb-search.css +353 -116
  259. package/dist/components/kb-segment.d.mts +2 -0
  260. package/dist/components/kb-sources.d.mts +2 -0
  261. package/dist/components/kb-sql.d.mts +2 -0
  262. package/dist/components/kb-trace.d.mts +2 -0
  263. package/dist/components/kb-visibility.d.mts +2 -0
  264. package/dist/components/kb-who-can.d.mts +2 -0
  265. package/dist/components/kb.css +60 -36
  266. package/dist/components/kb.d.mts +2 -0
  267. package/dist/components/kbd.d.mts +2 -0
  268. package/dist/components/layout.css +10 -10
  269. package/dist/components/layout.d.mts +2 -0
  270. package/dist/components/list.d.mts +2 -0
  271. package/dist/components/material-chinese.css +10 -0
  272. package/dist/components/material-soviet.css +10 -0
  273. package/dist/components/material.css +61 -18
  274. package/dist/components/media-card.d.mts +2 -0
  275. package/dist/components/media.css +22 -27
  276. package/dist/components/mentions.css +18 -17
  277. package/dist/components/mentions.d.mts +2 -0
  278. package/dist/components/menu.css +32 -28
  279. package/dist/components/modal.css +30 -27
  280. package/dist/components/modal.d.mts +2 -0
  281. package/dist/components/nav.css +48 -44
  282. package/dist/components/nav.d.mts +2 -0
  283. package/dist/components/notification.css +31 -25
  284. package/dist/components/notification.d.mts +2 -0
  285. package/dist/components/pagination.css +15 -13
  286. package/dist/components/pagination.d.mts +2 -0
  287. package/dist/components/panel.css +19 -20
  288. package/dist/components/panel.d.mts +2 -0
  289. package/dist/components/pill.css +8 -7
  290. package/dist/components/pill.d.mts +2 -0
  291. package/dist/components/popover.css +32 -23
  292. package/dist/components/popover.d.mts +2 -0
  293. package/dist/components/progress.d.mts +2 -0
  294. package/dist/components/rating.d.mts +2 -0
  295. package/dist/components/result.d.mts +2 -0
  296. package/dist/components/scroll-area.css +84 -112
  297. package/dist/components/scroll-area.d.mts +2 -0
  298. package/dist/components/scroll-area.mjs +1 -0
  299. package/dist/components/segmented.css +47 -29
  300. package/dist/components/segmented.d.mts +2 -0
  301. package/dist/components/select.css +80 -41
  302. package/dist/components/select.d.mts +2 -0
  303. package/dist/components/sidebar.css +42 -38
  304. package/dist/components/sidebar.d.mts +2 -0
  305. package/dist/components/skeleton.d.mts +2 -0
  306. package/dist/components/slider.css +26 -22
  307. package/dist/components/slider.d.mts +2 -0
  308. package/dist/components/spinner.d.mts +2 -0
  309. package/dist/components/split-pane.css +16 -7
  310. package/dist/components/split-pane.d.mts +2 -0
  311. package/dist/components/stat.css +17 -16
  312. package/dist/components/stat.d.mts +2 -0
  313. package/dist/components/steps.css +26 -26
  314. package/dist/components/steps.d.mts +2 -0
  315. package/dist/components/switch.css +78 -39
  316. package/dist/components/switch.d.mts +2 -0
  317. package/dist/components/table.css +54 -32
  318. package/dist/components/table.d.mts +2 -0
  319. package/dist/components/tabs.css +53 -32
  320. package/dist/components/tabs.d.mts +2 -0
  321. package/dist/components/tag-input.css +12 -8
  322. package/dist/components/tag-input.d.mts +2 -0
  323. package/dist/components/tag.css +20 -12
  324. package/dist/components/tag.d.mts +2 -0
  325. package/dist/components/theme-switcher.css +7 -7
  326. package/dist/components/theme-switcher.d.mts +2 -0
  327. package/dist/components/timeline.d.mts +2 -0
  328. package/dist/components/toast.css +34 -30
  329. package/dist/components/toast.d.mts +2 -0
  330. package/dist/components/toolbar.css +19 -18
  331. package/dist/components/toolbar.d.mts +2 -0
  332. package/dist/components/tooltip.css +9 -8
  333. package/dist/components/tooltip.d.mts +2 -0
  334. package/dist/components/tree-select.css +63 -40
  335. package/dist/components/tree-select.d.mts +2 -0
  336. package/dist/components/tree.d.mts +2 -0
  337. package/dist/components/upload.css +9 -11
  338. package/dist/components/upload.d.mts +2 -0
  339. package/dist/index.d.mts +85 -84
  340. package/dist/index.mjs +14644 -13935
  341. package/dist/react.d.mts +18 -18
  342. package/dist/react.mjs +377 -36
  343. package/dist/registry.json +797 -64
  344. package/dist/tokens/colors.css +6 -0
  345. package/dist/tokens/design.css +137 -31
  346. package/dist/tokens/dtcg.json +9592 -2008
  347. package/dist/tokens/figma.variables.json +7451 -2141
  348. package/dist/tokens/motion.css +51 -0
  349. package/dist/tokens/pixel.css +10 -0
  350. package/dist/tokens/scrollbars.css +40 -0
  351. package/dist/tokens/tokens-studio.json +8390 -1142
  352. package/dist/tokens/typography.css +33 -0
  353. package/dist/tokens.css +402 -82
  354. package/dist/ui.css +4196 -2163
  355. package/dist/vue.d.mts +17 -17
  356. package/dist/vue.mjs +371 -34
  357. package/docs/spec/charts-scale-a11y.md +115 -0
  358. package/docs/spec/design-philosophy.md +5 -5
  359. package/docs/spec/design-primitives.md +10 -10
  360. package/docs/spec/motion-typography.md +105 -0
  361. package/docs/spec/scrollbars.md +46 -0
  362. package/package.json +17 -3
@@ -21,6 +21,7 @@ var ICEN_LOCALE_ZH_CN = {
21
21
  "aiChat.roleTool": "\u5DE5",
22
22
  "aiChat.roleUser": "\u6211",
23
23
  "aiChat.thinking": "\u601D\u8003 {p0}",
24
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
24
25
  /* ── aiComposer ── */
25
26
  "aiComposer.attachAgent": "\u4EE3\u7406",
26
27
  "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
@@ -203,6 +204,19 @@ var ICEN_LOCALE_ZH_CN = {
203
204
  "charts.noData": "\u6682\u65E0\u6570\u636E",
204
205
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
205
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",
206
220
  "charts.type.area": "\u9762\u79EF\u56FE",
207
221
  "charts.type.donut": "\u73AF\u5F62\u56FE",
208
222
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -1241,6 +1255,15 @@ function svgIcon(svg) {
1241
1255
  return parseSvg(svg);
1242
1256
  }
1243
1257
 
1258
+ // src/behaviors/url-safety.ts
1259
+ function safeUrl(uri) {
1260
+ const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
1261
+ if (!s) return void 0;
1262
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
1263
+ if (/^data:\s*text\/html/.test(s)) return void 0;
1264
+ return uri;
1265
+ }
1266
+
1244
1267
  // src/behaviors/ai-chat.ts
1245
1268
  var ICON_COPY = iconHTML("copy");
1246
1269
  var ICON_RETRY = iconHTML("refresh");
@@ -1250,10 +1273,9 @@ var ROLE_AVATAR = {
1250
1273
  system: t("aiChat.roleSystem"),
1251
1274
  tool: t("aiChat.roleTool")
1252
1275
  };
1253
- function safeHref(uri) {
1254
- const s = uri.trim().toLowerCase();
1255
- if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
1256
- return uri;
1276
+ function safeContentUrl(part) {
1277
+ const src = aiContentUrl(part);
1278
+ return src ? safeUrl(src) : void 0;
1257
1279
  }
1258
1280
  function renderAiContentPart(part) {
1259
1281
  if (part.type === "text") {
@@ -1263,7 +1285,7 @@ function renderAiContentPart(part) {
1263
1285
  return span;
1264
1286
  }
1265
1287
  if (part.type === "image") {
1266
- const src = aiContentUrl(part);
1288
+ const src = safeContentUrl(part);
1267
1289
  if (!src) return void 0;
1268
1290
  const img = document.createElement("img");
1269
1291
  img.className = "icen-ai-msg-media icen-ai-msg-media--image";
@@ -1273,7 +1295,7 @@ function renderAiContentPart(part) {
1273
1295
  return img;
1274
1296
  }
1275
1297
  if (part.type === "audio") {
1276
- const src = aiContentUrl(part);
1298
+ const src = safeContentUrl(part);
1277
1299
  if (!src) return void 0;
1278
1300
  const audio = document.createElement("audio");
1279
1301
  audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
@@ -1282,7 +1304,7 @@ function renderAiContentPart(part) {
1282
1304
  return audio;
1283
1305
  }
1284
1306
  if (part.type === "video") {
1285
- const src = aiContentUrl(part);
1307
+ const src = safeContentUrl(part);
1286
1308
  if (!src) return void 0;
1287
1309
  const video = document.createElement("video");
1288
1310
  video.className = "icen-ai-msg-media icen-ai-msg-media--video";
@@ -1294,7 +1316,7 @@ function renderAiContentPart(part) {
1294
1316
  if (part.type === "file") {
1295
1317
  const chip = h("span", "icen-ai-msg-file");
1296
1318
  chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
1297
- const href2 = part.url ? safeHref(part.url) : void 0;
1319
+ const href2 = part.url ? safeUrl(part.url) : void 0;
1298
1320
  if (href2 && /^(https?:|data:)/i.test(href2)) {
1299
1321
  const a2 = document.createElement("a");
1300
1322
  a2.className = "icen-ai-msg-file-link";
@@ -1307,7 +1329,7 @@ function renderAiContentPart(part) {
1307
1329
  }
1308
1330
  const a = document.createElement("a");
1309
1331
  a.className = "icen-ai-msg-link";
1310
- const href = safeHref(part.uri);
1332
+ const href = safeUrl(part.uri);
1311
1333
  if (href) a.href = href;
1312
1334
  a.textContent = part.name ?? part.uri;
1313
1335
  a.title = part.uri;
@@ -1534,7 +1556,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
1534
1556
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
1535
1557
  });
1536
1558
  syncEye();
1537
- head.append(title, eye);
1559
+ if (hasLegend) head.append(title, eye);
1560
+ else head.append(title);
1538
1561
  el.append(head, body);
1539
1562
  paint(body);
1540
1563
  }
@@ -1635,7 +1658,7 @@ function renderVBar(el, opts) {
1635
1658
  wrap.appendChild(track);
1636
1659
  }
1637
1660
  body.append(wrap, labelsRow(labelsUsed));
1638
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1661
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1639
1662
  });
1640
1663
  attachChartInteraction(el, "vbar");
1641
1664
  return el;
@@ -1730,8 +1753,10 @@ function renderDonut(el, opts) {
1730
1753
  "stroke-width": "14"
1731
1754
  }));
1732
1755
  let offset = 0;
1756
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
1733
1757
  opts.segments.forEach((seg, segIndex) => {
1734
- const dash = seg.value / total * circumference;
1758
+ const arcLength = Math.max(0, seg.value / total * circumference);
1759
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
1735
1760
  const arc = svgEl("circle", {
1736
1761
  cx: "60",
1737
1762
  cy: "60",
@@ -1745,7 +1770,7 @@ function renderDonut(el, opts) {
1745
1770
  });
1746
1771
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
1747
1772
  svg.appendChild(arc);
1748
- offset += dash;
1773
+ offset += arcLength;
1749
1774
  });
1750
1775
  const legend = document.createElement("div");
1751
1776
  legend.className = "icen-chart-legend";
@@ -1780,8 +1805,9 @@ function renderLine(el, opts) {
1780
1805
  const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
1781
1806
  const defs = svgEl("defs", {});
1782
1807
  for (let i = 0; i < 4; i++) {
1783
- const y = pad + i * (height - pad * 2) / 3;
1808
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1784
1809
  svg.appendChild(svgEl("line", {
1810
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1785
1811
  x1: String(pad),
1786
1812
  x2: String(width - pad),
1787
1813
  y1: String(y),
@@ -1865,7 +1891,7 @@ function renderLine(el, opts) {
1865
1891
  if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1866
1892
  wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
1867
1893
  body.appendChild(wrap);
1868
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1894
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
1869
1895
  });
1870
1896
  if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
1871
1897
  attachChartInteraction(el, "line");
@@ -1972,7 +1998,7 @@ function renderRadar(el, opts) {
1972
1998
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
1973
1999
  svg.appendChild(dot);
1974
2000
  }
1975
- legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 }), label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
2001
+ legendItems.push({ key: `${si}:${s.name || t("charts.seriesName", { p0: si + 1 })}`, label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
1976
2002
  });
1977
2003
  wrap.appendChild(svg);
1978
2004
  body.appendChild(wrap);
@@ -1994,6 +2020,11 @@ function niceCeil(v) {
1994
2020
  else nice = 10;
1995
2021
  return nice * base;
1996
2022
  }
2023
+ function tickPrecision(min, max, steps) {
2024
+ const span = Math.abs(max - min);
2025
+ if (!Number.isFinite(span) || span <= 0) return 0;
2026
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
2027
+ }
1997
2028
  function isoDate(d) {
1998
2029
  const m = String(d.getMonth() + 1).padStart(2, "0");
1999
2030
  const day = String(d.getDate()).padStart(2, "0");
@@ -2089,7 +2120,8 @@ function renderSparkline(el, opts) {
2089
2120
  const tone = toneVar(opts.tone);
2090
2121
  const points = values.map((value, i) => ({
2091
2122
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
2092
- y: height - pad - value / max * (height - pad * 2),
2123
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
2124
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
2093
2125
  value
2094
2126
  }));
2095
2127
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -2214,6 +2246,7 @@ function renderCalendar(el, opts) {
2214
2246
  weekdayRow.appendChild(s);
2215
2247
  });
2216
2248
  const max = maxOf(entries.map((e) => e.value));
2249
+ entries.sort((a, b) => a.date.localeCompare(b.date));
2217
2250
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
2218
2251
  let lastMonth = -1;
2219
2252
  entries.forEach((entry, i) => {
@@ -2272,8 +2305,9 @@ function renderScatter(el, opts) {
2272
2305
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
2273
2306
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
2274
2307
  for (let i = 0; i <= 3; i++) {
2275
- const y = pad + i * (height - pad * 2) / 3;
2308
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
2276
2309
  svg.appendChild(svgEl("line", {
2310
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
2277
2311
  x1: String(pad),
2278
2312
  x2: String(width - pad),
2279
2313
  y1: String(y),
@@ -2289,12 +2323,13 @@ function renderScatter(el, opts) {
2289
2323
  "font-size": "8",
2290
2324
  fill: "var(--icen-token-text-faint)"
2291
2325
  });
2292
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2326
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
2293
2327
  svg.appendChild(txt);
2294
2328
  }
2295
2329
  for (let i = 0; i <= 4; i++) {
2296
- const x = pad + i * (width - pad * 2) / 4;
2330
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
2297
2331
  svg.appendChild(svgEl("line", {
2332
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
2298
2333
  x1: String(x),
2299
2334
  x2: String(x),
2300
2335
  y1: String(pad),
@@ -2311,7 +2346,7 @@ function renderScatter(el, opts) {
2311
2346
  "font-size": "8",
2312
2347
  fill: "var(--icen-token-text-faint)"
2313
2348
  });
2314
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2349
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
2315
2350
  svg.appendChild(txt);
2316
2351
  }
2317
2352
  if (opts.yLabel) {
@@ -2548,6 +2583,14 @@ function normalizeChartSpec(raw) {
2548
2583
  }
2549
2584
  if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2550
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
+ }
2551
2594
  if (Array.isArray(s.marks)) {
2552
2595
  const marks = [];
2553
2596
  for (const raw2 of s.marks) {
@@ -2675,6 +2718,7 @@ function renderChartSkeleton(body) {
2675
2718
  body.appendChild(box);
2676
2719
  }
2677
2720
  var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2721
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2678
2722
  function markToneVar(tone) {
2679
2723
  switch (tone) {
2680
2724
  case "success":
@@ -2810,7 +2854,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2810
2854
  y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2811
2855
  "text-anchor": "middle",
2812
2856
  "font-size": "8",
2813
- fill: CHART_MARK_ACCENT
2857
+ fill: CHART_MARK_ACCENT_TEXT
2814
2858
  });
2815
2859
  label.textContent = mark.text ?? mark.label;
2816
2860
  g.appendChild(label);
@@ -2902,6 +2946,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2902
2946
  function chartAriaLabel(title, typeName) {
2903
2947
  return title ? `${typeName}\uFF1A${title}` : typeName;
2904
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
+ }
2905
3024
  function svgDimsOf(svg) {
2906
3025
  const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2907
3026
  const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
@@ -3242,6 +3361,7 @@ function renderChart(el, raw) {
3242
3361
  if (!isZoomableType(t2) || fullLength() < 2) return;
3243
3362
  const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
3244
3363
  if (!plot) return;
3364
+ plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
3245
3365
  const on = (type, fn) => {
3246
3366
  plot.addEventListener(type, fn);
3247
3367
  };
@@ -3297,6 +3417,149 @@ function renderChart(el, raw) {
3297
3417
  render();
3298
3418
  });
3299
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
+ };
3300
3563
  const render = () => {
3301
3564
  if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
3302
3565
  const spec = current2;
@@ -3368,9 +3631,16 @@ function renderChart(el, raw) {
3368
3631
  const graphic = root.querySelector('[role="img"]');
3369
3632
  if (graphic && !graphic.getAttribute("aria-label")) {
3370
3633
  graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3634
+ } else if (!graphic) {
3635
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3636
+ if (dom) {
3637
+ dom.setAttribute("role", "img");
3638
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3639
+ }
3371
3640
  }
3372
3641
  }
3373
3642
  if (loading) return;
3643
+ applyChartA11yPlus(view, spec, type, formatValue);
3374
3644
  paintChartMarks(root, view, spec, formatValue, warnedMarks);
3375
3645
  bindZoomGesture();
3376
3646
  };
@@ -3452,6 +3722,7 @@ function renderChart(el, raw) {
3452
3722
  releaseFluidWidth(root);
3453
3723
  hiddenLegendKeys.delete(root);
3454
3724
  zoomDragCleanup?.();
3725
+ root.removeEventListener("keydown", onKbKeydown);
3455
3726
  root.textContent = "";
3456
3727
  root.classList.remove("is-loading");
3457
3728
  unbindEvents();
@@ -3605,8 +3876,12 @@ function buildApproval() {
3605
3876
  }
3606
3877
  function applyTint(item, model) {
3607
3878
  const tint = getAiKind(model.kind).tint;
3608
- if (tint) item.style.setProperty("--ai-item-tint", `var(--icen-token-${tint})`);
3609
- else item.style.removeProperty("--ai-item-tint");
3879
+ if (tint) {
3880
+ const slot = tint === "muted" ? "text-muted" : tint;
3881
+ item.style.setProperty("--ai-item-tint", `var(--icen-token-${slot})`);
3882
+ } else {
3883
+ item.style.removeProperty("--ai-item-tint");
3884
+ }
3610
3885
  }
3611
3886
  function applyKindVisual(parts, model) {
3612
3887
  const kind = getAiKind(model.kind);