@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
package/dist/react.mjs CHANGED
@@ -166,6 +166,7 @@ var ICEN_LOCALE_ZH_CN = {
166
166
  "aiChat.roleTool": "\u5DE5",
167
167
  "aiChat.roleUser": "\u6211",
168
168
  "aiChat.thinking": "\u601D\u8003 {p0}",
169
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
169
170
  /* ── aiComposer ── */
170
171
  "aiComposer.attachAgent": "\u4EE3\u7406",
171
172
  "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
@@ -348,6 +349,19 @@ var ICEN_LOCALE_ZH_CN = {
348
349
  "charts.noData": "\u6682\u65E0\u6570\u636E",
349
350
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
350
351
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
352
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
353
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
354
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
355
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
356
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
357
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
358
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
359
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
360
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
361
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
362
+ "charts.a11y.trendDown": "\u4E0B\u964D",
363
+ "charts.a11y.trendFlat": "\u6301\u5E73",
364
+ "charts.a11y.trendUp": "\u4E0A\u5347",
351
365
  "charts.type.area": "\u9762\u79EF\u56FE",
352
366
  "charts.type.donut": "\u73AF\u5F62\u56FE",
353
367
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -1213,7 +1227,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
1213
1227
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
1214
1228
  });
1215
1229
  syncEye();
1216
- head.append(title, eye);
1230
+ if (hasLegend) head.append(title, eye);
1231
+ else head.append(title);
1217
1232
  el.append(head, body);
1218
1233
  paint(body);
1219
1234
  }
@@ -1314,7 +1329,7 @@ function renderVBar(el, opts) {
1314
1329
  wrap.appendChild(track);
1315
1330
  }
1316
1331
  body.append(wrap, labelsRow(labelsUsed));
1317
- 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));
1332
+ 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));
1318
1333
  });
1319
1334
  attachChartInteraction(el, "vbar");
1320
1335
  return el;
@@ -1409,8 +1424,10 @@ function renderDonut(el, opts) {
1409
1424
  "stroke-width": "14"
1410
1425
  }));
1411
1426
  let offset = 0;
1427
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
1412
1428
  opts.segments.forEach((seg, segIndex) => {
1413
- const dash = seg.value / total * circumference;
1429
+ const arcLength = Math.max(0, seg.value / total * circumference);
1430
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
1414
1431
  const arc = svgEl("circle", {
1415
1432
  cx: "60",
1416
1433
  cy: "60",
@@ -1424,7 +1441,7 @@ function renderDonut(el, opts) {
1424
1441
  });
1425
1442
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
1426
1443
  svg.appendChild(arc);
1427
- offset += dash;
1444
+ offset += arcLength;
1428
1445
  });
1429
1446
  const legend = document.createElement("div");
1430
1447
  legend.className = "icen-chart-legend";
@@ -1459,8 +1476,9 @@ function renderLine(el, opts) {
1459
1476
  const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
1460
1477
  const defs = svgEl("defs", {});
1461
1478
  for (let i = 0; i < 4; i++) {
1462
- const y = pad + i * (height - pad * 2) / 3;
1479
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1463
1480
  svg.appendChild(svgEl("line", {
1481
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1464
1482
  x1: String(pad),
1465
1483
  x2: String(width - pad),
1466
1484
  y1: String(y),
@@ -1544,7 +1562,7 @@ function renderLine(el, opts) {
1544
1562
  if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1545
1563
  wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
1546
1564
  body.appendChild(wrap);
1547
- 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));
1565
+ 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));
1548
1566
  });
1549
1567
  if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
1550
1568
  attachChartInteraction(el, "line");
@@ -1651,7 +1669,7 @@ function renderRadar(el, opts) {
1651
1669
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
1652
1670
  svg.appendChild(dot);
1653
1671
  }
1654
- legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 }), label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
1672
+ 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 });
1655
1673
  });
1656
1674
  wrap.appendChild(svg);
1657
1675
  body.appendChild(wrap);
@@ -1673,6 +1691,11 @@ function niceCeil(v) {
1673
1691
  else nice = 10;
1674
1692
  return nice * base;
1675
1693
  }
1694
+ function tickPrecision(min, max, steps) {
1695
+ const span = Math.abs(max - min);
1696
+ if (!Number.isFinite(span) || span <= 0) return 0;
1697
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
1698
+ }
1676
1699
  function isoDate(d) {
1677
1700
  const m = String(d.getMonth() + 1).padStart(2, "0");
1678
1701
  const day = String(d.getDate()).padStart(2, "0");
@@ -1768,7 +1791,8 @@ function renderSparkline(el, opts) {
1768
1791
  const tone = toneVar(opts.tone);
1769
1792
  const points = values.map((value, i) => ({
1770
1793
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
1771
- y: height - pad - value / max * (height - pad * 2),
1794
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
1795
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
1772
1796
  value
1773
1797
  }));
1774
1798
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -1893,6 +1917,7 @@ function renderCalendar(el, opts) {
1893
1917
  weekdayRow.appendChild(s);
1894
1918
  });
1895
1919
  const max = maxOf(entries.map((e) => e.value));
1920
+ entries.sort((a, b) => a.date.localeCompare(b.date));
1896
1921
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
1897
1922
  let lastMonth = -1;
1898
1923
  entries.forEach((entry, i) => {
@@ -1951,8 +1976,9 @@ function renderScatter(el, opts) {
1951
1976
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
1952
1977
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
1953
1978
  for (let i = 0; i <= 3; i++) {
1954
- const y = pad + i * (height - pad * 2) / 3;
1979
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1955
1980
  svg.appendChild(svgEl("line", {
1981
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1956
1982
  x1: String(pad),
1957
1983
  x2: String(width - pad),
1958
1984
  y1: String(y),
@@ -1968,12 +1994,13 @@ function renderScatter(el, opts) {
1968
1994
  "font-size": "8",
1969
1995
  fill: "var(--icen-token-text-faint)"
1970
1996
  });
1971
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1997
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
1972
1998
  svg.appendChild(txt);
1973
1999
  }
1974
2000
  for (let i = 0; i <= 4; i++) {
1975
- const x = pad + i * (width - pad * 2) / 4;
2001
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
1976
2002
  svg.appendChild(svgEl("line", {
2003
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
1977
2004
  x1: String(x),
1978
2005
  x2: String(x),
1979
2006
  y1: String(pad),
@@ -1990,7 +2017,7 @@ function renderScatter(el, opts) {
1990
2017
  "font-size": "8",
1991
2018
  fill: "var(--icen-token-text-faint)"
1992
2019
  });
1993
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2020
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
1994
2021
  svg.appendChild(txt);
1995
2022
  }
1996
2023
  if (opts.yLabel) {
@@ -2227,6 +2254,14 @@ function normalizeChartSpec(raw) {
2227
2254
  }
2228
2255
  if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2229
2256
  if (typeof s.loading === "boolean") spec.loading = s.loading;
2257
+ if (s.a11y && typeof s.a11y === "object") {
2258
+ const a = s.a11y;
2259
+ const a11y = {};
2260
+ if (typeof a.summary === "boolean") a11y.summary = a.summary;
2261
+ if (typeof a.table === "boolean") a11y.table = a.table;
2262
+ if (typeof a.keyboard === "boolean") a11y.keyboard = a.keyboard;
2263
+ if (Object.keys(a11y).length > 0) spec.a11y = a11y;
2264
+ }
2230
2265
  if (Array.isArray(s.marks)) {
2231
2266
  const marks = [];
2232
2267
  for (const raw2 of s.marks) {
@@ -2354,6 +2389,7 @@ function renderChartSkeleton(body) {
2354
2389
  body.appendChild(box);
2355
2390
  }
2356
2391
  var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2392
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2357
2393
  function markToneVar(tone) {
2358
2394
  switch (tone) {
2359
2395
  case "success":
@@ -2489,7 +2525,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2489
2525
  y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2490
2526
  "text-anchor": "middle",
2491
2527
  "font-size": "8",
2492
- fill: CHART_MARK_ACCENT
2528
+ fill: CHART_MARK_ACCENT_TEXT
2493
2529
  });
2494
2530
  label.textContent = mark.text ?? mark.label;
2495
2531
  g.appendChild(label);
@@ -2581,6 +2617,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2581
2617
  function chartAriaLabel(title, typeName) {
2582
2618
  return title ? `${typeName}\uFF1A${title}` : typeName;
2583
2619
  }
2620
+ function summarizeChart(view, type, fmt2) {
2621
+ const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
2622
+ const parts = [];
2623
+ if (series.length > 1) parts.push(t("charts.a11y.seriesCount", { p0: series.length }));
2624
+ if (type === "scatter") {
2625
+ const pts = view.points ?? [];
2626
+ if (pts.length > 0) {
2627
+ const xs = pts.map((p) => p.x);
2628
+ const ys = pts.map((p) => p.y);
2629
+ 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)) }));
2630
+ }
2631
+ return parts.join("\uFF1B");
2632
+ }
2633
+ const labels = view.labels ?? [];
2634
+ if (labels.length > 1) parts.push(t("charts.a11y.range", { p0: labels[0], p1: labels[labels.length - 1] }));
2635
+ let min = Infinity;
2636
+ let max = -Infinity;
2637
+ let minAt = "";
2638
+ let maxAt = "";
2639
+ for (const s of series) {
2640
+ s.values.forEach((v, i) => {
2641
+ if (v < min) {
2642
+ min = v;
2643
+ minAt = labels[i] ?? String(i + 1);
2644
+ }
2645
+ if (v > max) {
2646
+ max = v;
2647
+ maxAt = labels[i] ?? String(i + 1);
2648
+ }
2649
+ });
2650
+ }
2651
+ if (Number.isFinite(min) && Number.isFinite(max)) {
2652
+ parts.push(t("charts.a11y.min", { p0: fmt2(min), p1: minAt }));
2653
+ parts.push(t("charts.a11y.max", { p0: fmt2(max), p1: maxAt }));
2654
+ }
2655
+ const first = series[0]?.values ?? [];
2656
+ if (first.length > 1) {
2657
+ const d = first[first.length - 1] - first[0];
2658
+ const key = Math.abs(d) < 1e-9 ? "charts.a11y.trendFlat" : d > 0 ? "charts.a11y.trendUp" : "charts.a11y.trendDown";
2659
+ parts.push(t("charts.a11y.trend", { p0: t(key) }));
2660
+ }
2661
+ return parts.join("\uFF1B");
2662
+ }
2663
+ function buildChartTable(view, spec, type, fmt2) {
2664
+ const table = document.createElement("table");
2665
+ table.className = "icen-chart-table";
2666
+ const caption = document.createElement("caption");
2667
+ caption.textContent = t("charts.a11y.tableCaption", { p0: spec.title ?? String(type) });
2668
+ table.appendChild(caption);
2669
+ const addRow = (target, cells, head) => {
2670
+ const tr = document.createElement("tr");
2671
+ for (const c of cells) {
2672
+ const cell = document.createElement(head ? "th" : "td");
2673
+ if (head) cell.scope = target.tagName === "THEAD" ? "col" : "row";
2674
+ cell.textContent = c;
2675
+ tr.appendChild(cell);
2676
+ }
2677
+ target.appendChild(tr);
2678
+ };
2679
+ const thead = table.createTHead();
2680
+ const tbody = table.createTBody();
2681
+ if (type === "scatter") {
2682
+ addRow(thead, ["x", "y"], true);
2683
+ for (const p of view.points ?? []) addRow(tbody, [fmt2(p.x), fmt2(p.y)], false);
2684
+ return table;
2685
+ }
2686
+ const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
2687
+ const labels = view.labels ?? [];
2688
+ addRow(thead, ["", ...series.map((s, i) => s.name || String(i + 1))], true);
2689
+ const n = Math.max(labels.length, ...series.map((s) => s.values.length));
2690
+ for (let i = 0; i < n; i++) {
2691
+ addRow(tbody, [labels[i] ?? String(i + 1), ...series.map((s) => fmt2(s.values[i] ?? 0))], false);
2692
+ }
2693
+ return table;
2694
+ }
2584
2695
  function svgDimsOf(svg) {
2585
2696
  const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2586
2697
  const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
@@ -2921,6 +3032,7 @@ function renderChart(el, raw) {
2921
3032
  if (!isZoomableType(t2) || fullLength() < 2) return;
2922
3033
  const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
2923
3034
  if (!plot) return;
3035
+ plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
2924
3036
  const on = (type, fn) => {
2925
3037
  plot.addEventListener(type, fn);
2926
3038
  };
@@ -2976,6 +3088,149 @@ function renderChart(el, raw) {
2976
3088
  render();
2977
3089
  });
2978
3090
  };
3091
+ const KB_TYPES = /* @__PURE__ */ new Set(["line", "area", "vbar", "hbar", "scatter"]);
3092
+ const kbCursor = { si: 0, i: 0, active: false };
3093
+ let liveRegion = null;
3094
+ let a11ySeq = 0;
3095
+ const a11yOf = () => ({
3096
+ summary: current2.a11y?.summary !== false,
3097
+ table: current2.a11y?.table === true,
3098
+ keyboard: current2.a11y?.keyboard !== false
3099
+ });
3100
+ const seriesViewOf = (view) => view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
3101
+ const kbPointCount = (view) => typeOf() === "scatter" ? view.points?.length ?? 0 : Math.max(0, ...seriesViewOf(view).map((s) => s.values.length), view.labels?.length ?? 0);
3102
+ const kbCursorEl = () => {
3103
+ const t2 = typeOf();
3104
+ const view = viewOf();
3105
+ const series = seriesViewOf(view);
3106
+ const n = kbPointCount(view);
3107
+ if (n < 1) return null;
3108
+ const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
3109
+ const i = clampNum(kbCursor.i, 0, n - 1);
3110
+ if (t2 === "line" || t2 === "area") {
3111
+ const svg = root.querySelector(".icen-chart-line svg");
3112
+ if (!svg) return null;
3113
+ const dots = svg.querySelectorAll("circle");
3114
+ let base = 0;
3115
+ for (let k = 0; k < si; k++) base += Math.min(series[k].values.length, n);
3116
+ return dots.item(base + i) ?? null;
3117
+ }
3118
+ if (t2 === "scatter") return root.querySelector(".icen-chart-scatter svg")?.querySelectorAll("circle").item(i) ?? null;
3119
+ if (t2 === "vbar") return root.querySelectorAll(".icen-chart-vbar-bar").item(series.length > 1 ? i * series.length + si : i) ?? null;
3120
+ if (t2 === "hbar") return root.querySelectorAll(".icen-chart-hbar-bar").item(i) ?? null;
3121
+ return null;
3122
+ };
3123
+ const announceKb = (text) => {
3124
+ if (!liveRegion || !liveRegion.isConnected) {
3125
+ liveRegion = document.createElement("div");
3126
+ liveRegion.className = "icen-chart-live";
3127
+ liveRegion.setAttribute("aria-live", "polite");
3128
+ root.appendChild(liveRegion);
3129
+ }
3130
+ liveRegion.textContent = "";
3131
+ liveRegion.textContent = text;
3132
+ };
3133
+ const applyKbCursor = () => {
3134
+ for (const el2 of root.querySelectorAll(".icen-chart-kb-focus")) el2.classList.remove("icen-chart-kb-focus");
3135
+ if (!kbCursor.active) return;
3136
+ kbCursorEl()?.classList.add("icen-chart-kb-focus");
3137
+ };
3138
+ const announceCursor = () => {
3139
+ const view = viewOf();
3140
+ const series = seriesViewOf(view);
3141
+ const n = kbPointCount(view);
3142
+ if (n < 1) return;
3143
+ const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
3144
+ const i = clampNum(kbCursor.i, 0, Math.max(0, n - 1));
3145
+ const fmt2 = chartFormatValue(current2.format);
3146
+ if (typeOf() === "scatter") {
3147
+ const p = view.points?.[i];
3148
+ if (!p) return;
3149
+ announceKb(t("charts.a11y.point", { p0: `x ${fmt2(p.x)}`, p1: `y ${fmt2(p.y)}`, p2: i + 1, p3: n }));
3150
+ return;
3151
+ }
3152
+ const label = view.labels?.[i] ?? String(i + 1);
3153
+ const value = series[si]?.values[i] ?? 0;
3154
+ 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 }));
3155
+ else announceKb(t("charts.a11y.point", { p0: label, p1: fmt2(value), p2: i + 1, p3: n }));
3156
+ };
3157
+ const onKbKeydown = (e) => {
3158
+ const conf = a11yOf();
3159
+ if (!conf.keyboard || !KB_TYPES.has(typeOf())) return;
3160
+ const g = root.querySelector("[data-icen-chart-kb]");
3161
+ if (!g || e.target !== g) return;
3162
+ if (e.key === "Escape") {
3163
+ if (zoomWindow) {
3164
+ zoomWindow = null;
3165
+ kbCursor.active = false;
3166
+ render();
3167
+ }
3168
+ return;
3169
+ }
3170
+ const view = viewOf();
3171
+ const series = seriesViewOf(view);
3172
+ const n = kbPointCount(view);
3173
+ if (n < 1) return;
3174
+ const siMax = Math.max(0, series.length - 1);
3175
+ let moved = true;
3176
+ switch (e.key) {
3177
+ case "ArrowRight":
3178
+ kbCursor.i = clampNum(kbCursor.i + 1, 0, n - 1);
3179
+ break;
3180
+ case "ArrowLeft":
3181
+ kbCursor.i = clampNum(kbCursor.i - 1, 0, n - 1);
3182
+ break;
3183
+ case "ArrowDown":
3184
+ kbCursor.si = clampNum(kbCursor.si + 1, 0, siMax);
3185
+ break;
3186
+ case "ArrowUp":
3187
+ kbCursor.si = clampNum(kbCursor.si - 1, 0, siMax);
3188
+ break;
3189
+ case "Home":
3190
+ kbCursor.i = 0;
3191
+ break;
3192
+ case "End":
3193
+ kbCursor.i = n - 1;
3194
+ break;
3195
+ default:
3196
+ moved = false;
3197
+ }
3198
+ if (!moved) return;
3199
+ e.preventDefault();
3200
+ kbCursor.active = true;
3201
+ applyKbCursor();
3202
+ announceCursor();
3203
+ };
3204
+ root.addEventListener("keydown", onKbKeydown);
3205
+ const applyChartA11yPlus = (view, spec, type, formatValue) => {
3206
+ const conf = a11yOf();
3207
+ const graphic = root.querySelector('[role="img"]');
3208
+ if (!graphic) return;
3209
+ const body = root.querySelector(".icen-chart-body") ?? graphic.parentElement ?? root;
3210
+ const summaryParts = [];
3211
+ if (conf.summary) summaryParts.push(summarizeChart(view, type, formatValue));
3212
+ if (conf.keyboard && KB_TYPES.has(type)) summaryParts.push(t("charts.a11y.keyboardHint"));
3213
+ const summaryText = summaryParts.filter(Boolean).join("\uFF1B");
3214
+ if (summaryText) {
3215
+ const p = document.createElement("p");
3216
+ p.className = "icen-chart-summary";
3217
+ p.id = `icen-chart-a11y-${++a11ySeq}`;
3218
+ p.textContent = summaryText;
3219
+ body.appendChild(p);
3220
+ graphic.setAttribute("aria-describedby", p.id);
3221
+ } else {
3222
+ graphic.removeAttribute("aria-describedby");
3223
+ }
3224
+ if (conf.keyboard && KB_TYPES.has(type)) {
3225
+ graphic.setAttribute("tabindex", "0");
3226
+ graphic.setAttribute("data-icen-chart-kb", "");
3227
+ } else {
3228
+ graphic.removeAttribute("tabindex");
3229
+ graphic.removeAttribute("data-icen-chart-kb");
3230
+ }
3231
+ if (conf.table) body.appendChild(buildChartTable(view, spec, type, formatValue));
3232
+ applyKbCursor();
3233
+ };
2979
3234
  const render = () => {
2980
3235
  if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
2981
3236
  const spec = current2;
@@ -3047,9 +3302,16 @@ function renderChart(el, raw) {
3047
3302
  const graphic = root.querySelector('[role="img"]');
3048
3303
  if (graphic && !graphic.getAttribute("aria-label")) {
3049
3304
  graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3305
+ } else if (!graphic) {
3306
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3307
+ if (dom) {
3308
+ dom.setAttribute("role", "img");
3309
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3310
+ }
3050
3311
  }
3051
3312
  }
3052
3313
  if (loading) return;
3314
+ applyChartA11yPlus(view, spec, type, formatValue);
3053
3315
  paintChartMarks(root, view, spec, formatValue, warnedMarks);
3054
3316
  bindZoomGesture();
3055
3317
  };
@@ -3131,6 +3393,7 @@ function renderChart(el, raw) {
3131
3393
  releaseFluidWidth(root);
3132
3394
  hiddenLegendKeys.delete(root);
3133
3395
  zoomDragCleanup?.();
3396
+ root.removeEventListener("keydown", onKbKeydown);
3134
3397
  root.textContent = "";
3135
3398
  root.classList.remove("is-loading");
3136
3399
  unbindEvents();
@@ -3759,7 +4022,13 @@ function onKeyDown2(e) {
3759
4022
 
3760
4023
  // src/behaviors/datatable.ts
3761
4024
  function defaultCompare(a, b) {
3762
- if (typeof a === "number" && typeof b === "number") return a - b;
4025
+ if (typeof a === "number" && typeof b === "number") {
4026
+ if (Number.isNaN(a) || Number.isNaN(b)) {
4027
+ if (Number.isNaN(a) && Number.isNaN(b)) return 0;
4028
+ return Number.isNaN(a) ? 1 : -1;
4029
+ }
4030
+ return a - b;
4031
+ }
3763
4032
  return String(a ?? "").localeCompare(String(b ?? ""), "zh-CN", { numeric: true });
3764
4033
  }
3765
4034
  function toNum2(v) {
@@ -4048,11 +4317,13 @@ function createTable(el, opts) {
4048
4317
  const body = document.createElement("div");
4049
4318
  body.className = "icen-dt-body";
4050
4319
  body.setAttribute("role", "rowgroup");
4051
- const summaryEl = document.createElement("div");
4052
- summaryEl.className = "icen-dt-row icen-dt-row--summary";
4053
- summaryEl.setAttribute("role", "row");
4054
- summaryEl.hidden = true;
4055
- canvas.append(head, body, summaryEl);
4320
+ const summaryEl = opts.summaryRow ? document.createElement("div") : null;
4321
+ if (summaryEl) {
4322
+ summaryEl.className = "icen-dt-row icen-dt-row--summary";
4323
+ summaryEl.setAttribute("role", "row");
4324
+ summaryEl.hidden = true;
4325
+ }
4326
+ canvas.append(head, body, ...summaryEl ? [summaryEl] : []);
4056
4327
  scroll.appendChild(canvas);
4057
4328
  root.appendChild(scroll);
4058
4329
  const foot = document.createElement("div");
@@ -4866,6 +5137,7 @@ function createTable(el, opts) {
4866
5137
  return wrap;
4867
5138
  }
4868
5139
  function renderSummary() {
5140
+ if (!summaryEl) return;
4869
5141
  summaryEl.textContent = "";
4870
5142
  summaryEl.hidden = true;
4871
5143
  const cfg = opts.summaryRow;
@@ -5062,9 +5334,9 @@ function createTable(el, opts) {
5062
5334
  }
5063
5335
  }
5064
5336
  let currentTotal = 0;
5065
- function visibleRange(total) {
5337
+ function visibleRange(total, avail) {
5066
5338
  if (!virtual) {
5067
- if (opts.remote || opts.pagination === false) return [0, total];
5339
+ if (opts.remote || opts.pagination === false) return [0, Math.min(total, avail)];
5068
5340
  const start2 = (page - 1) * pageSize;
5069
5341
  return [start2, Math.min(total, start2 + pageSize)];
5070
5342
  }
@@ -5079,6 +5351,10 @@ function createTable(el, opts) {
5079
5351
  const rows = pipeline();
5080
5352
  const entries = groupFn ? flatEntries() : null;
5081
5353
  const total = entries ? entries.length : opts.remote ? opts.totalCount ?? data.length : rows.length;
5354
+ if (!opts.remote && opts.pagination !== false) {
5355
+ const pages = Math.max(1, Math.ceil(total / pageSize));
5356
+ if (page > pages) page = pages;
5357
+ }
5082
5358
  navTotal = entries ? entries.length : rows.length;
5083
5359
  currentTotal = total;
5084
5360
  const keepTop = virtual ? scroll.scrollTop : 0;
@@ -5107,7 +5383,7 @@ function createTable(el, opts) {
5107
5383
  renderSummary();
5108
5384
  return;
5109
5385
  }
5110
- const [start, end] = visibleRange(total);
5386
+ const [start, end] = visibleRange(total, rows.length);
5111
5387
  const frag = document.createDocumentFragment();
5112
5388
  const offsets = frozenOffsets();
5113
5389
  if (virtual && start > 0) {
@@ -5170,11 +5446,21 @@ function createTable(el, opts) {
5170
5446
  const pages = Math.ceil(total / pageSize);
5171
5447
  const pager = document.createElement("nav");
5172
5448
  pager.className = "icen-dt-pager";
5173
- pager.setAttribute("aria-label", t("datatable.paginationAria"));
5449
+ {
5450
+ const base = t("datatable.paginationAria");
5451
+ const used = /* @__PURE__ */ new Set();
5452
+ for (const el2 of document.querySelectorAll(".icen-dt-pager[aria-label]")) {
5453
+ if (!root.contains(el2)) used.add(el2.getAttribute("aria-label") ?? "");
5454
+ }
5455
+ let label = base, n = 2;
5456
+ while (used.has(label)) label = `${base} ${n++}`;
5457
+ pager.setAttribute("aria-label", label);
5458
+ }
5174
5459
  const sizeSel = document.createElement("select");
5175
5460
  sizeSel.className = "icen-dt-page-size";
5176
5461
  sizeSel.setAttribute("aria-label", t("datatable.pageSizeAria"));
5177
- for (const s of pageSizes) {
5462
+ const sizeOptions = pageSizes.includes(pageSize) ? pageSizes : [...pageSizes, pageSize].sort((a, b) => a - b);
5463
+ for (const s of sizeOptions) {
5178
5464
  const o = document.createElement("option");
5179
5465
  o.value = String(s);
5180
5466
  o.textContent = t("pagination.pageSize", { p0: s });
@@ -5266,6 +5552,7 @@ function createTable(el, opts) {
5266
5552
  if (destroyed) return;
5267
5553
  renderHead();
5268
5554
  renderBody();
5555
+ syncFrozenWidths();
5269
5556
  }
5270
5557
  rekey();
5271
5558
  renderAll();
@@ -5286,12 +5573,52 @@ function createTable(el, opts) {
5286
5573
  opts.onPageChange?.(page, pageSize);
5287
5574
  renderAll();
5288
5575
  }
5576
+ function hasFluidFrozen() {
5577
+ return cols().some((c) => frozenSide(c) != null && !/^(\d+(?:\.\d+)?)px/.test(colWidths.get(c.key) ?? c.width ?? ""));
5578
+ }
5579
+ function syncFrozenWidths() {
5580
+ if (!hasFluidFrozen()) return;
5581
+ const visible = cols();
5582
+ const headCells = Array.from(headRow.children);
5583
+ const lead = headCells.length - visible.length;
5584
+ const left = /* @__PURE__ */ new Map();
5585
+ const right = /* @__PURE__ */ new Map();
5586
+ let acc = headCells.slice(0, lead).reduce((s, c) => s + c.offsetWidth, 0);
5587
+ for (let i = 0; i < visible.length; i++) {
5588
+ const c = visible[i];
5589
+ if (frozenSide(c) === "left") left.set(c.key, acc);
5590
+ acc += headCells[lead + i]?.offsetWidth ?? 0;
5591
+ }
5592
+ let accR = 0;
5593
+ for (let i = visible.length - 1; i >= 0; i--) {
5594
+ const c = visible[i];
5595
+ if (frozenSide(c) === "right") right.set(c.key, accR);
5596
+ accR += headCells[lead + i]?.offsetWidth ?? 0;
5597
+ }
5598
+ const rows = [headRow, ...summaryEl ? [summaryEl] : [], ...Array.from(body.querySelectorAll(".icen-dt-row"))];
5599
+ for (const row of rows) {
5600
+ const cells = Array.from(row.children);
5601
+ if (cells.length !== headCells.length) continue;
5602
+ cells.forEach((cell, i) => {
5603
+ const col = i >= lead ? visible[i - lead] : void 0;
5604
+ if (!col) return;
5605
+ const l = left.get(col.key);
5606
+ if (l != null && cell.classList.contains("icen-dt-cell--frozen")) cell.style.left = `${l}px`;
5607
+ const r = right.get(col.key);
5608
+ if (r != null && cell.classList.contains("icen-dt-cell--frozen-right")) cell.style.right = `${r}px`;
5609
+ });
5610
+ }
5611
+ }
5289
5612
  return {
5290
5613
  setPage,
5291
5614
  setPageSize,
5292
5615
  setData(next) {
5293
5616
  if (editing) cancelEdit(true);
5294
5617
  data = next;
5618
+ if (typeof opts.rowKey !== "function" && typeof opts.rowKey !== "string" && selected.size > 0) {
5619
+ selected.clear();
5620
+ emitSelection();
5621
+ }
5295
5622
  rekey();
5296
5623
  invalidate();
5297
5624
  page = 1;
@@ -5662,6 +5989,15 @@ function svgIcon(svg) {
5662
5989
  return parseSvg(svg);
5663
5990
  }
5664
5991
 
5992
+ // src/behaviors/url-safety.ts
5993
+ function safeUrl(uri) {
5994
+ const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
5995
+ if (!s) return void 0;
5996
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
5997
+ if (/^data:\s*text\/html/.test(s)) return void 0;
5998
+ return uri;
5999
+ }
6000
+
5665
6001
  // src/behaviors/ai-chat.ts
5666
6002
  var ICON_COPY = iconHTML("copy");
5667
6003
  var ICON_RETRY = iconHTML("refresh");
@@ -5689,6 +6025,8 @@ function createAiStream(el) {
5689
6025
  el.setAttribute("aria-busy", "true");
5690
6026
  if (reasoning) {
5691
6027
  reasoning.classList.add("is-streaming");
6028
+ const timeEl = reasoning.querySelector(".icen-ai-reasoning-time");
6029
+ if (timeEl) timeEl.textContent = t("aiChat.thinkingNow");
5692
6030
  setReasoningOpen(reasoning, true);
5693
6031
  const head = reasoning.querySelector(".icen-ai-reasoning-head");
5694
6032
  if (head && head.dataset.icenReasoningStart == null) head.dataset.icenReasoningStart = String(startedAt);
@@ -5776,10 +6114,9 @@ var ROLE_AVATAR = {
5776
6114
  system: t("aiChat.roleSystem"),
5777
6115
  tool: t("aiChat.roleTool")
5778
6116
  };
5779
- function safeHref(uri) {
5780
- const s = uri.trim().toLowerCase();
5781
- if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
5782
- return uri;
6117
+ function safeContentUrl(part) {
6118
+ const src = aiContentUrl(part);
6119
+ return src ? safeUrl(src) : void 0;
5783
6120
  }
5784
6121
  function renderAiContentPart(part) {
5785
6122
  if (part.type === "text") {
@@ -5789,7 +6126,7 @@ function renderAiContentPart(part) {
5789
6126
  return span;
5790
6127
  }
5791
6128
  if (part.type === "image") {
5792
- const src = aiContentUrl(part);
6129
+ const src = safeContentUrl(part);
5793
6130
  if (!src) return void 0;
5794
6131
  const img = document.createElement("img");
5795
6132
  img.className = "icen-ai-msg-media icen-ai-msg-media--image";
@@ -5799,7 +6136,7 @@ function renderAiContentPart(part) {
5799
6136
  return img;
5800
6137
  }
5801
6138
  if (part.type === "audio") {
5802
- const src = aiContentUrl(part);
6139
+ const src = safeContentUrl(part);
5803
6140
  if (!src) return void 0;
5804
6141
  const audio = document.createElement("audio");
5805
6142
  audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
@@ -5808,7 +6145,7 @@ function renderAiContentPart(part) {
5808
6145
  return audio;
5809
6146
  }
5810
6147
  if (part.type === "video") {
5811
- const src = aiContentUrl(part);
6148
+ const src = safeContentUrl(part);
5812
6149
  if (!src) return void 0;
5813
6150
  const video = document.createElement("video");
5814
6151
  video.className = "icen-ai-msg-media icen-ai-msg-media--video";
@@ -5820,7 +6157,7 @@ function renderAiContentPart(part) {
5820
6157
  if (part.type === "file") {
5821
6158
  const chip = h("span", "icen-ai-msg-file");
5822
6159
  chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
5823
- const href2 = part.url ? safeHref(part.url) : void 0;
6160
+ const href2 = part.url ? safeUrl(part.url) : void 0;
5824
6161
  if (href2 && /^(https?:|data:)/i.test(href2)) {
5825
6162
  const a2 = document.createElement("a");
5826
6163
  a2.className = "icen-ai-msg-file-link";
@@ -5833,7 +6170,7 @@ function renderAiContentPart(part) {
5833
6170
  }
5834
6171
  const a = document.createElement("a");
5835
6172
  a.className = "icen-ai-msg-link";
5836
- const href = safeHref(part.uri);
6173
+ const href = safeUrl(part.uri);
5837
6174
  if (href) a.href = href;
5838
6175
  a.textContent = part.name ?? part.uri;
5839
6176
  a.title = part.uri;
@@ -5895,7 +6232,7 @@ function renderAiMessage(scrollEl, model) {
5895
6232
  errEl.textContent = message;
5896
6233
  },
5897
6234
  stream() {
5898
- const span = h("span", "ai-msg-stream-text");
6235
+ const span = h("span", "icen-ai-msg-text ai-msg-stream-text");
5899
6236
  body.appendChild(span);
5900
6237
  return createAiStream(span);
5901
6238
  }
@@ -6035,8 +6372,12 @@ function buildApproval() {
6035
6372
  }
6036
6373
  function applyTint(item, model) {
6037
6374
  const tint = getAiKind(model.kind).tint;
6038
- if (tint) item.style.setProperty("--ai-item-tint", `var(--icen-token-${tint})`);
6039
- else item.style.removeProperty("--ai-item-tint");
6375
+ if (tint) {
6376
+ const slot = tint === "muted" ? "text-muted" : tint;
6377
+ item.style.setProperty("--ai-item-tint", `var(--icen-token-${slot})`);
6378
+ } else {
6379
+ item.style.removeProperty("--ai-item-tint");
6380
+ }
6040
6381
  }
6041
6382
  function applyKindVisual(parts, model) {
6042
6383
  const kind = getAiKind(model.kind);