@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/vue.mjs CHANGED
@@ -168,6 +168,7 @@ var ICEN_LOCALE_ZH_CN = {
168
168
  "aiChat.roleTool": "\u5DE5",
169
169
  "aiChat.roleUser": "\u6211",
170
170
  "aiChat.thinking": "\u601D\u8003 {p0}",
171
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
171
172
  /* ── aiComposer ── */
172
173
  "aiComposer.attachAgent": "\u4EE3\u7406",
173
174
  "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
@@ -350,6 +351,19 @@ var ICEN_LOCALE_ZH_CN = {
350
351
  "charts.noData": "\u6682\u65E0\u6570\u636E",
351
352
  "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
352
353
  "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
354
+ "charts.a11y.keyboardHint": "\u65B9\u5411\u952E\u9010\u70B9\u6D4F\u89C8\uFF0CHome/End \u8DF3\u9996\u5C3E\uFF0CEsc \u91CD\u7F6E\u7F29\u653E",
355
+ "charts.a11y.max": "\u6700\u5927 {p0}\uFF08{p1}\uFF09",
356
+ "charts.a11y.min": "\u6700\u5C0F {p0}\uFF08{p1}\uFF09",
357
+ "charts.a11y.point": "{p0}\uFF1A{p1}\uFF0C\u7B2C {p2}/{p3} \u70B9",
358
+ "charts.a11y.pointSeries": "{p0} \xB7 {p1}\uFF1A{p2}\uFF0C\u7B2C {p3}/{p4} \u70B9",
359
+ "charts.a11y.range": "\u7C7B\u76EE {p0} \u81F3 {p1}",
360
+ "charts.a11y.scatterRange": "x \u8303\u56F4 {p0}\u2013{p1}\uFF0Cy \u8303\u56F4 {p2}\u2013{p3}",
361
+ "charts.a11y.seriesCount": "{p0} \u4E2A\u7CFB\u5217",
362
+ "charts.a11y.tableCaption": "{p0} \u6570\u636E\u8868",
363
+ "charts.a11y.trend": "\u9996\u7CFB\u5217\u8D8B\u52BF{p0}",
364
+ "charts.a11y.trendDown": "\u4E0B\u964D",
365
+ "charts.a11y.trendFlat": "\u6301\u5E73",
366
+ "charts.a11y.trendUp": "\u4E0A\u5347",
353
367
  "charts.type.area": "\u9762\u79EF\u56FE",
354
368
  "charts.type.donut": "\u73AF\u5F62\u56FE",
355
369
  "charts.type.gauge": "\u4EEA\u8868\u76D8",
@@ -1215,7 +1229,8 @@ function withChrome(el, opts, hasLegend, paint, state, extras) {
1215
1229
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
1216
1230
  });
1217
1231
  syncEye();
1218
- head.append(title, eye);
1232
+ if (hasLegend) head.append(title, eye);
1233
+ else head.append(title);
1219
1234
  el.append(head, body);
1220
1235
  paint(body);
1221
1236
  }
@@ -1316,7 +1331,7 @@ function renderVBar(el, opts) {
1316
1331
  wrap.appendChild(track);
1317
1332
  }
1318
1333
  body.append(wrap, labelsRow(labelsUsed));
1319
- 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));
1334
+ 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));
1320
1335
  });
1321
1336
  attachChartInteraction(el, "vbar");
1322
1337
  return el;
@@ -1411,8 +1426,10 @@ function renderDonut(el, opts) {
1411
1426
  "stroke-width": "14"
1412
1427
  }));
1413
1428
  let offset = 0;
1429
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
1414
1430
  opts.segments.forEach((seg, segIndex) => {
1415
- const dash = seg.value / total * circumference;
1431
+ const arcLength = Math.max(0, seg.value / total * circumference);
1432
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
1416
1433
  const arc = svgEl("circle", {
1417
1434
  cx: "60",
1418
1435
  cy: "60",
@@ -1426,7 +1443,7 @@ function renderDonut(el, opts) {
1426
1443
  });
1427
1444
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
1428
1445
  svg.appendChild(arc);
1429
- offset += dash;
1446
+ offset += arcLength;
1430
1447
  });
1431
1448
  const legend = document.createElement("div");
1432
1449
  legend.className = "icen-chart-legend";
@@ -1461,8 +1478,9 @@ function renderLine(el, opts) {
1461
1478
  const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
1462
1479
  const defs = svgEl("defs", {});
1463
1480
  for (let i = 0; i < 4; i++) {
1464
- const y = pad + i * (height - pad * 2) / 3;
1481
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1465
1482
  svg.appendChild(svgEl("line", {
1483
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1466
1484
  x1: String(pad),
1467
1485
  x2: String(width - pad),
1468
1486
  y1: String(y),
@@ -1546,7 +1564,7 @@ function renderLine(el, opts) {
1546
1564
  if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1547
1565
  wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
1548
1566
  body.appendChild(wrap);
1549
- 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));
1567
+ 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));
1550
1568
  });
1551
1569
  if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
1552
1570
  attachChartInteraction(el, "line");
@@ -1653,7 +1671,7 @@ function renderRadar(el, opts) {
1653
1671
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
1654
1672
  svg.appendChild(dot);
1655
1673
  }
1656
- legendItems.push({ key: s.name || t("charts.seriesName", { p0: si + 1 }), label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
1674
+ 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 });
1657
1675
  });
1658
1676
  wrap.appendChild(svg);
1659
1677
  body.appendChild(wrap);
@@ -1675,6 +1693,11 @@ function niceCeil(v) {
1675
1693
  else nice = 10;
1676
1694
  return nice * base;
1677
1695
  }
1696
+ function tickPrecision(min, max, steps) {
1697
+ const span = Math.abs(max - min);
1698
+ if (!Number.isFinite(span) || span <= 0) return 0;
1699
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
1700
+ }
1678
1701
  function isoDate(d) {
1679
1702
  const m = String(d.getMonth() + 1).padStart(2, "0");
1680
1703
  const day = String(d.getDate()).padStart(2, "0");
@@ -1770,7 +1793,8 @@ function renderSparkline(el, opts) {
1770
1793
  const tone = toneVar(opts.tone);
1771
1794
  const points = values.map((value, i) => ({
1772
1795
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
1773
- y: height - pad - value / max * (height - pad * 2),
1796
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
1797
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
1774
1798
  value
1775
1799
  }));
1776
1800
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -1895,6 +1919,7 @@ function renderCalendar(el, opts) {
1895
1919
  weekdayRow.appendChild(s);
1896
1920
  });
1897
1921
  const max = maxOf(entries.map((e) => e.value));
1922
+ entries.sort((a, b) => a.date.localeCompare(b.date));
1898
1923
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
1899
1924
  let lastMonth = -1;
1900
1925
  entries.forEach((entry, i) => {
@@ -1953,8 +1978,9 @@ function renderScatter(el, opts) {
1953
1978
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
1954
1979
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
1955
1980
  for (let i = 0; i <= 3; i++) {
1956
- const y = pad + i * (height - pad * 2) / 3;
1981
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1957
1982
  svg.appendChild(svgEl("line", {
1983
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1958
1984
  x1: String(pad),
1959
1985
  x2: String(width - pad),
1960
1986
  y1: String(y),
@@ -1970,12 +1996,13 @@ function renderScatter(el, opts) {
1970
1996
  "font-size": "8",
1971
1997
  fill: "var(--icen-token-text-faint)"
1972
1998
  });
1973
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1999
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
1974
2000
  svg.appendChild(txt);
1975
2001
  }
1976
2002
  for (let i = 0; i <= 4; i++) {
1977
- const x = pad + i * (width - pad * 2) / 4;
2003
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
1978
2004
  svg.appendChild(svgEl("line", {
2005
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
1979
2006
  x1: String(x),
1980
2007
  x2: String(x),
1981
2008
  y1: String(pad),
@@ -1992,7 +2019,7 @@ function renderScatter(el, opts) {
1992
2019
  "font-size": "8",
1993
2020
  fill: "var(--icen-token-text-faint)"
1994
2021
  });
1995
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
2022
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
1996
2023
  svg.appendChild(txt);
1997
2024
  }
1998
2025
  if (opts.yLabel) {
@@ -2229,6 +2256,14 @@ function normalizeChartSpec(raw) {
2229
2256
  }
2230
2257
  if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2231
2258
  if (typeof s.loading === "boolean") spec.loading = s.loading;
2259
+ if (s.a11y && typeof s.a11y === "object") {
2260
+ const a = s.a11y;
2261
+ const a11y = {};
2262
+ if (typeof a.summary === "boolean") a11y.summary = a.summary;
2263
+ if (typeof a.table === "boolean") a11y.table = a.table;
2264
+ if (typeof a.keyboard === "boolean") a11y.keyboard = a.keyboard;
2265
+ if (Object.keys(a11y).length > 0) spec.a11y = a11y;
2266
+ }
2232
2267
  if (Array.isArray(s.marks)) {
2233
2268
  const marks = [];
2234
2269
  for (const raw2 of s.marks) {
@@ -2356,6 +2391,7 @@ function renderChartSkeleton(body) {
2356
2391
  body.appendChild(box);
2357
2392
  }
2358
2393
  var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2394
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2359
2395
  function markToneVar(tone) {
2360
2396
  switch (tone) {
2361
2397
  case "success":
@@ -2491,7 +2527,7 @@ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2491
2527
  y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2492
2528
  "text-anchor": "middle",
2493
2529
  "font-size": "8",
2494
- fill: CHART_MARK_ACCENT
2530
+ fill: CHART_MARK_ACCENT_TEXT
2495
2531
  });
2496
2532
  label.textContent = mark.text ?? mark.label;
2497
2533
  g.appendChild(label);
@@ -2583,6 +2619,81 @@ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2583
2619
  function chartAriaLabel(title, typeName) {
2584
2620
  return title ? `${typeName}\uFF1A${title}` : typeName;
2585
2621
  }
2622
+ function summarizeChart(view, type, fmt2) {
2623
+ const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
2624
+ const parts = [];
2625
+ if (series.length > 1) parts.push(t("charts.a11y.seriesCount", { p0: series.length }));
2626
+ if (type === "scatter") {
2627
+ const pts = view.points ?? [];
2628
+ if (pts.length > 0) {
2629
+ const xs = pts.map((p) => p.x);
2630
+ const ys = pts.map((p) => p.y);
2631
+ 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)) }));
2632
+ }
2633
+ return parts.join("\uFF1B");
2634
+ }
2635
+ const labels = view.labels ?? [];
2636
+ if (labels.length > 1) parts.push(t("charts.a11y.range", { p0: labels[0], p1: labels[labels.length - 1] }));
2637
+ let min = Infinity;
2638
+ let max = -Infinity;
2639
+ let minAt = "";
2640
+ let maxAt = "";
2641
+ for (const s of series) {
2642
+ s.values.forEach((v, i) => {
2643
+ if (v < min) {
2644
+ min = v;
2645
+ minAt = labels[i] ?? String(i + 1);
2646
+ }
2647
+ if (v > max) {
2648
+ max = v;
2649
+ maxAt = labels[i] ?? String(i + 1);
2650
+ }
2651
+ });
2652
+ }
2653
+ if (Number.isFinite(min) && Number.isFinite(max)) {
2654
+ parts.push(t("charts.a11y.min", { p0: fmt2(min), p1: minAt }));
2655
+ parts.push(t("charts.a11y.max", { p0: fmt2(max), p1: maxAt }));
2656
+ }
2657
+ const first = series[0]?.values ?? [];
2658
+ if (first.length > 1) {
2659
+ const d = first[first.length - 1] - first[0];
2660
+ const key = Math.abs(d) < 1e-9 ? "charts.a11y.trendFlat" : d > 0 ? "charts.a11y.trendUp" : "charts.a11y.trendDown";
2661
+ parts.push(t("charts.a11y.trend", { p0: t(key) }));
2662
+ }
2663
+ return parts.join("\uFF1B");
2664
+ }
2665
+ function buildChartTable(view, spec, type, fmt2) {
2666
+ const table = document.createElement("table");
2667
+ table.className = "icen-chart-table";
2668
+ const caption = document.createElement("caption");
2669
+ caption.textContent = t("charts.a11y.tableCaption", { p0: spec.title ?? String(type) });
2670
+ table.appendChild(caption);
2671
+ const addRow = (target, cells, head) => {
2672
+ const tr = document.createElement("tr");
2673
+ for (const c of cells) {
2674
+ const cell = document.createElement(head ? "th" : "td");
2675
+ if (head) cell.scope = target.tagName === "THEAD" ? "col" : "row";
2676
+ cell.textContent = c;
2677
+ tr.appendChild(cell);
2678
+ }
2679
+ target.appendChild(tr);
2680
+ };
2681
+ const thead = table.createTHead();
2682
+ const tbody = table.createTBody();
2683
+ if (type === "scatter") {
2684
+ addRow(thead, ["x", "y"], true);
2685
+ for (const p of view.points ?? []) addRow(tbody, [fmt2(p.x), fmt2(p.y)], false);
2686
+ return table;
2687
+ }
2688
+ const series = view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
2689
+ const labels = view.labels ?? [];
2690
+ addRow(thead, ["", ...series.map((s, i) => s.name || String(i + 1))], true);
2691
+ const n = Math.max(labels.length, ...series.map((s) => s.values.length));
2692
+ for (let i = 0; i < n; i++) {
2693
+ addRow(tbody, [labels[i] ?? String(i + 1), ...series.map((s) => fmt2(s.values[i] ?? 0))], false);
2694
+ }
2695
+ return table;
2696
+ }
2586
2697
  function svgDimsOf(svg) {
2587
2698
  const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2588
2699
  const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
@@ -2923,6 +3034,7 @@ function renderChart(el, raw) {
2923
3034
  if (!isZoomableType(t2) || fullLength() < 2) return;
2924
3035
  const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
2925
3036
  if (!plot) return;
3037
+ plot.style.touchAction = current2.zoom === "x" ? "pan-y" : "none";
2926
3038
  const on = (type, fn) => {
2927
3039
  plot.addEventListener(type, fn);
2928
3040
  };
@@ -2978,6 +3090,149 @@ function renderChart(el, raw) {
2978
3090
  render();
2979
3091
  });
2980
3092
  };
3093
+ const KB_TYPES = /* @__PURE__ */ new Set(["line", "area", "vbar", "hbar", "scatter"]);
3094
+ const kbCursor = { si: 0, i: 0, active: false };
3095
+ let liveRegion = null;
3096
+ let a11ySeq = 0;
3097
+ const a11yOf = () => ({
3098
+ summary: current2.a11y?.summary !== false,
3099
+ table: current2.a11y?.table === true,
3100
+ keyboard: current2.a11y?.keyboard !== false
3101
+ });
3102
+ const seriesViewOf = (view) => view.series && view.series.length > 0 ? view.series : [{ name: "", values: view.values ?? [] }];
3103
+ const kbPointCount = (view) => typeOf() === "scatter" ? view.points?.length ?? 0 : Math.max(0, ...seriesViewOf(view).map((s) => s.values.length), view.labels?.length ?? 0);
3104
+ const kbCursorEl = () => {
3105
+ const t2 = typeOf();
3106
+ const view = viewOf();
3107
+ const series = seriesViewOf(view);
3108
+ const n = kbPointCount(view);
3109
+ if (n < 1) return null;
3110
+ const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
3111
+ const i = clampNum(kbCursor.i, 0, n - 1);
3112
+ if (t2 === "line" || t2 === "area") {
3113
+ const svg = root.querySelector(".icen-chart-line svg");
3114
+ if (!svg) return null;
3115
+ const dots = svg.querySelectorAll("circle");
3116
+ let base = 0;
3117
+ for (let k = 0; k < si; k++) base += Math.min(series[k].values.length, n);
3118
+ return dots.item(base + i) ?? null;
3119
+ }
3120
+ if (t2 === "scatter") return root.querySelector(".icen-chart-scatter svg")?.querySelectorAll("circle").item(i) ?? null;
3121
+ if (t2 === "vbar") return root.querySelectorAll(".icen-chart-vbar-bar").item(series.length > 1 ? i * series.length + si : i) ?? null;
3122
+ if (t2 === "hbar") return root.querySelectorAll(".icen-chart-hbar-bar").item(i) ?? null;
3123
+ return null;
3124
+ };
3125
+ const announceKb = (text) => {
3126
+ if (!liveRegion || !liveRegion.isConnected) {
3127
+ liveRegion = document.createElement("div");
3128
+ liveRegion.className = "icen-chart-live";
3129
+ liveRegion.setAttribute("aria-live", "polite");
3130
+ root.appendChild(liveRegion);
3131
+ }
3132
+ liveRegion.textContent = "";
3133
+ liveRegion.textContent = text;
3134
+ };
3135
+ const applyKbCursor = () => {
3136
+ for (const el2 of root.querySelectorAll(".icen-chart-kb-focus")) el2.classList.remove("icen-chart-kb-focus");
3137
+ if (!kbCursor.active) return;
3138
+ kbCursorEl()?.classList.add("icen-chart-kb-focus");
3139
+ };
3140
+ const announceCursor = () => {
3141
+ const view = viewOf();
3142
+ const series = seriesViewOf(view);
3143
+ const n = kbPointCount(view);
3144
+ if (n < 1) return;
3145
+ const si = clampNum(kbCursor.si, 0, Math.max(0, series.length - 1));
3146
+ const i = clampNum(kbCursor.i, 0, Math.max(0, n - 1));
3147
+ const fmt2 = chartFormatValue(current2.format);
3148
+ if (typeOf() === "scatter") {
3149
+ const p = view.points?.[i];
3150
+ if (!p) return;
3151
+ announceKb(t("charts.a11y.point", { p0: `x ${fmt2(p.x)}`, p1: `y ${fmt2(p.y)}`, p2: i + 1, p3: n }));
3152
+ return;
3153
+ }
3154
+ const label = view.labels?.[i] ?? String(i + 1);
3155
+ const value = series[si]?.values[i] ?? 0;
3156
+ 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 }));
3157
+ else announceKb(t("charts.a11y.point", { p0: label, p1: fmt2(value), p2: i + 1, p3: n }));
3158
+ };
3159
+ const onKbKeydown = (e) => {
3160
+ const conf = a11yOf();
3161
+ if (!conf.keyboard || !KB_TYPES.has(typeOf())) return;
3162
+ const g = root.querySelector("[data-icen-chart-kb]");
3163
+ if (!g || e.target !== g) return;
3164
+ if (e.key === "Escape") {
3165
+ if (zoomWindow) {
3166
+ zoomWindow = null;
3167
+ kbCursor.active = false;
3168
+ render();
3169
+ }
3170
+ return;
3171
+ }
3172
+ const view = viewOf();
3173
+ const series = seriesViewOf(view);
3174
+ const n = kbPointCount(view);
3175
+ if (n < 1) return;
3176
+ const siMax = Math.max(0, series.length - 1);
3177
+ let moved = true;
3178
+ switch (e.key) {
3179
+ case "ArrowRight":
3180
+ kbCursor.i = clampNum(kbCursor.i + 1, 0, n - 1);
3181
+ break;
3182
+ case "ArrowLeft":
3183
+ kbCursor.i = clampNum(kbCursor.i - 1, 0, n - 1);
3184
+ break;
3185
+ case "ArrowDown":
3186
+ kbCursor.si = clampNum(kbCursor.si + 1, 0, siMax);
3187
+ break;
3188
+ case "ArrowUp":
3189
+ kbCursor.si = clampNum(kbCursor.si - 1, 0, siMax);
3190
+ break;
3191
+ case "Home":
3192
+ kbCursor.i = 0;
3193
+ break;
3194
+ case "End":
3195
+ kbCursor.i = n - 1;
3196
+ break;
3197
+ default:
3198
+ moved = false;
3199
+ }
3200
+ if (!moved) return;
3201
+ e.preventDefault();
3202
+ kbCursor.active = true;
3203
+ applyKbCursor();
3204
+ announceCursor();
3205
+ };
3206
+ root.addEventListener("keydown", onKbKeydown);
3207
+ const applyChartA11yPlus = (view, spec, type, formatValue) => {
3208
+ const conf = a11yOf();
3209
+ const graphic = root.querySelector('[role="img"]');
3210
+ if (!graphic) return;
3211
+ const body = root.querySelector(".icen-chart-body") ?? graphic.parentElement ?? root;
3212
+ const summaryParts = [];
3213
+ if (conf.summary) summaryParts.push(summarizeChart(view, type, formatValue));
3214
+ if (conf.keyboard && KB_TYPES.has(type)) summaryParts.push(t("charts.a11y.keyboardHint"));
3215
+ const summaryText = summaryParts.filter(Boolean).join("\uFF1B");
3216
+ if (summaryText) {
3217
+ const p = document.createElement("p");
3218
+ p.className = "icen-chart-summary";
3219
+ p.id = `icen-chart-a11y-${++a11ySeq}`;
3220
+ p.textContent = summaryText;
3221
+ body.appendChild(p);
3222
+ graphic.setAttribute("aria-describedby", p.id);
3223
+ } else {
3224
+ graphic.removeAttribute("aria-describedby");
3225
+ }
3226
+ if (conf.keyboard && KB_TYPES.has(type)) {
3227
+ graphic.setAttribute("tabindex", "0");
3228
+ graphic.setAttribute("data-icen-chart-kb", "");
3229
+ } else {
3230
+ graphic.removeAttribute("tabindex");
3231
+ graphic.removeAttribute("data-icen-chart-kb");
3232
+ }
3233
+ if (conf.table) body.appendChild(buildChartTable(view, spec, type, formatValue));
3234
+ applyKbCursor();
3235
+ };
2981
3236
  const render = () => {
2982
3237
  if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
2983
3238
  const spec = current2;
@@ -3049,9 +3304,16 @@ function renderChart(el, raw) {
3049
3304
  const graphic = root.querySelector('[role="img"]');
3050
3305
  if (graphic && !graphic.getAttribute("aria-label")) {
3051
3306
  graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3307
+ } else if (!graphic) {
3308
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3309
+ if (dom) {
3310
+ dom.setAttribute("role", "img");
3311
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3312
+ }
3052
3313
  }
3053
3314
  }
3054
3315
  if (loading) return;
3316
+ applyChartA11yPlus(view, spec, type, formatValue);
3055
3317
  paintChartMarks(root, view, spec, formatValue, warnedMarks);
3056
3318
  bindZoomGesture();
3057
3319
  };
@@ -3133,6 +3395,7 @@ function renderChart(el, raw) {
3133
3395
  releaseFluidWidth(root);
3134
3396
  hiddenLegendKeys.delete(root);
3135
3397
  zoomDragCleanup?.();
3398
+ root.removeEventListener("keydown", onKbKeydown);
3136
3399
  root.textContent = "";
3137
3400
  root.classList.remove("is-loading");
3138
3401
  unbindEvents();
@@ -3761,7 +4024,13 @@ function onKeyDown2(e) {
3761
4024
 
3762
4025
  // src/behaviors/datatable.ts
3763
4026
  function defaultCompare(a, b) {
3764
- if (typeof a === "number" && typeof b === "number") return a - b;
4027
+ if (typeof a === "number" && typeof b === "number") {
4028
+ if (Number.isNaN(a) || Number.isNaN(b)) {
4029
+ if (Number.isNaN(a) && Number.isNaN(b)) return 0;
4030
+ return Number.isNaN(a) ? 1 : -1;
4031
+ }
4032
+ return a - b;
4033
+ }
3765
4034
  return String(a ?? "").localeCompare(String(b ?? ""), "zh-CN", { numeric: true });
3766
4035
  }
3767
4036
  function toNum2(v) {
@@ -4050,11 +4319,13 @@ function createTable(el, opts) {
4050
4319
  const body = document.createElement("div");
4051
4320
  body.className = "icen-dt-body";
4052
4321
  body.setAttribute("role", "rowgroup");
4053
- const summaryEl = document.createElement("div");
4054
- summaryEl.className = "icen-dt-row icen-dt-row--summary";
4055
- summaryEl.setAttribute("role", "row");
4056
- summaryEl.hidden = true;
4057
- canvas.append(head, body, summaryEl);
4322
+ const summaryEl = opts.summaryRow ? document.createElement("div") : null;
4323
+ if (summaryEl) {
4324
+ summaryEl.className = "icen-dt-row icen-dt-row--summary";
4325
+ summaryEl.setAttribute("role", "row");
4326
+ summaryEl.hidden = true;
4327
+ }
4328
+ canvas.append(head, body, ...summaryEl ? [summaryEl] : []);
4058
4329
  scroll.appendChild(canvas);
4059
4330
  root.appendChild(scroll);
4060
4331
  const foot = document.createElement("div");
@@ -4868,6 +5139,7 @@ function createTable(el, opts) {
4868
5139
  return wrap;
4869
5140
  }
4870
5141
  function renderSummary() {
5142
+ if (!summaryEl) return;
4871
5143
  summaryEl.textContent = "";
4872
5144
  summaryEl.hidden = true;
4873
5145
  const cfg = opts.summaryRow;
@@ -5064,9 +5336,9 @@ function createTable(el, opts) {
5064
5336
  }
5065
5337
  }
5066
5338
  let currentTotal = 0;
5067
- function visibleRange(total) {
5339
+ function visibleRange(total, avail) {
5068
5340
  if (!virtual) {
5069
- if (opts.remote || opts.pagination === false) return [0, total];
5341
+ if (opts.remote || opts.pagination === false) return [0, Math.min(total, avail)];
5070
5342
  const start2 = (page - 1) * pageSize;
5071
5343
  return [start2, Math.min(total, start2 + pageSize)];
5072
5344
  }
@@ -5081,6 +5353,10 @@ function createTable(el, opts) {
5081
5353
  const rows = pipeline();
5082
5354
  const entries = groupFn ? flatEntries() : null;
5083
5355
  const total = entries ? entries.length : opts.remote ? opts.totalCount ?? data.length : rows.length;
5356
+ if (!opts.remote && opts.pagination !== false) {
5357
+ const pages = Math.max(1, Math.ceil(total / pageSize));
5358
+ if (page > pages) page = pages;
5359
+ }
5084
5360
  navTotal = entries ? entries.length : rows.length;
5085
5361
  currentTotal = total;
5086
5362
  const keepTop = virtual ? scroll.scrollTop : 0;
@@ -5109,7 +5385,7 @@ function createTable(el, opts) {
5109
5385
  renderSummary();
5110
5386
  return;
5111
5387
  }
5112
- const [start, end] = visibleRange(total);
5388
+ const [start, end] = visibleRange(total, rows.length);
5113
5389
  const frag = document.createDocumentFragment();
5114
5390
  const offsets = frozenOffsets();
5115
5391
  if (virtual && start > 0) {
@@ -5172,11 +5448,21 @@ function createTable(el, opts) {
5172
5448
  const pages = Math.ceil(total / pageSize);
5173
5449
  const pager = document.createElement("nav");
5174
5450
  pager.className = "icen-dt-pager";
5175
- pager.setAttribute("aria-label", t("datatable.paginationAria"));
5451
+ {
5452
+ const base = t("datatable.paginationAria");
5453
+ const used = /* @__PURE__ */ new Set();
5454
+ for (const el2 of document.querySelectorAll(".icen-dt-pager[aria-label]")) {
5455
+ if (!root.contains(el2)) used.add(el2.getAttribute("aria-label") ?? "");
5456
+ }
5457
+ let label = base, n = 2;
5458
+ while (used.has(label)) label = `${base} ${n++}`;
5459
+ pager.setAttribute("aria-label", label);
5460
+ }
5176
5461
  const sizeSel = document.createElement("select");
5177
5462
  sizeSel.className = "icen-dt-page-size";
5178
5463
  sizeSel.setAttribute("aria-label", t("datatable.pageSizeAria"));
5179
- for (const s of pageSizes) {
5464
+ const sizeOptions = pageSizes.includes(pageSize) ? pageSizes : [...pageSizes, pageSize].sort((a, b) => a - b);
5465
+ for (const s of sizeOptions) {
5180
5466
  const o = document.createElement("option");
5181
5467
  o.value = String(s);
5182
5468
  o.textContent = t("pagination.pageSize", { p0: s });
@@ -5268,6 +5554,7 @@ function createTable(el, opts) {
5268
5554
  if (destroyed) return;
5269
5555
  renderHead();
5270
5556
  renderBody();
5557
+ syncFrozenWidths();
5271
5558
  }
5272
5559
  rekey();
5273
5560
  renderAll();
@@ -5288,12 +5575,52 @@ function createTable(el, opts) {
5288
5575
  opts.onPageChange?.(page, pageSize);
5289
5576
  renderAll();
5290
5577
  }
5578
+ function hasFluidFrozen() {
5579
+ return cols().some((c) => frozenSide(c) != null && !/^(\d+(?:\.\d+)?)px/.test(colWidths.get(c.key) ?? c.width ?? ""));
5580
+ }
5581
+ function syncFrozenWidths() {
5582
+ if (!hasFluidFrozen()) return;
5583
+ const visible = cols();
5584
+ const headCells = Array.from(headRow.children);
5585
+ const lead = headCells.length - visible.length;
5586
+ const left = /* @__PURE__ */ new Map();
5587
+ const right = /* @__PURE__ */ new Map();
5588
+ let acc = headCells.slice(0, lead).reduce((s, c) => s + c.offsetWidth, 0);
5589
+ for (let i = 0; i < visible.length; i++) {
5590
+ const c = visible[i];
5591
+ if (frozenSide(c) === "left") left.set(c.key, acc);
5592
+ acc += headCells[lead + i]?.offsetWidth ?? 0;
5593
+ }
5594
+ let accR = 0;
5595
+ for (let i = visible.length - 1; i >= 0; i--) {
5596
+ const c = visible[i];
5597
+ if (frozenSide(c) === "right") right.set(c.key, accR);
5598
+ accR += headCells[lead + i]?.offsetWidth ?? 0;
5599
+ }
5600
+ const rows = [headRow, ...summaryEl ? [summaryEl] : [], ...Array.from(body.querySelectorAll(".icen-dt-row"))];
5601
+ for (const row of rows) {
5602
+ const cells = Array.from(row.children);
5603
+ if (cells.length !== headCells.length) continue;
5604
+ cells.forEach((cell, i) => {
5605
+ const col = i >= lead ? visible[i - lead] : void 0;
5606
+ if (!col) return;
5607
+ const l = left.get(col.key);
5608
+ if (l != null && cell.classList.contains("icen-dt-cell--frozen")) cell.style.left = `${l}px`;
5609
+ const r = right.get(col.key);
5610
+ if (r != null && cell.classList.contains("icen-dt-cell--frozen-right")) cell.style.right = `${r}px`;
5611
+ });
5612
+ }
5613
+ }
5291
5614
  return {
5292
5615
  setPage,
5293
5616
  setPageSize,
5294
5617
  setData(next) {
5295
5618
  if (editing) cancelEdit(true);
5296
5619
  data = next;
5620
+ if (typeof opts.rowKey !== "function" && typeof opts.rowKey !== "string" && selected.size > 0) {
5621
+ selected.clear();
5622
+ emitSelection();
5623
+ }
5297
5624
  rekey();
5298
5625
  invalidate();
5299
5626
  page = 1;
@@ -5536,6 +5863,15 @@ function svgIcon(svg) {
5536
5863
  return parseSvg(svg);
5537
5864
  }
5538
5865
 
5866
+ // src/behaviors/url-safety.ts
5867
+ function safeUrl(uri) {
5868
+ const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
5869
+ if (!s) return void 0;
5870
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
5871
+ if (/^data:\s*text\/html/.test(s)) return void 0;
5872
+ return uri;
5873
+ }
5874
+
5539
5875
  // src/behaviors/ai-chat.ts
5540
5876
  var ICON_COPY = iconHTML("copy");
5541
5877
  var ICON_RETRY = iconHTML("refresh");
@@ -5563,6 +5899,8 @@ function createAiStream(el) {
5563
5899
  el.setAttribute("aria-busy", "true");
5564
5900
  if (reasoning) {
5565
5901
  reasoning.classList.add("is-streaming");
5902
+ const timeEl = reasoning.querySelector(".icen-ai-reasoning-time");
5903
+ if (timeEl) timeEl.textContent = t("aiChat.thinkingNow");
5566
5904
  setReasoningOpen(reasoning, true);
5567
5905
  const head = reasoning.querySelector(".icen-ai-reasoning-head");
5568
5906
  if (head && head.dataset.icenReasoningStart == null) head.dataset.icenReasoningStart = String(startedAt);
@@ -5650,10 +5988,9 @@ var ROLE_AVATAR = {
5650
5988
  system: t("aiChat.roleSystem"),
5651
5989
  tool: t("aiChat.roleTool")
5652
5990
  };
5653
- function safeHref(uri) {
5654
- const s = uri.trim().toLowerCase();
5655
- if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
5656
- return uri;
5991
+ function safeContentUrl(part) {
5992
+ const src = aiContentUrl(part);
5993
+ return src ? safeUrl(src) : void 0;
5657
5994
  }
5658
5995
  function renderAiContentPart(part) {
5659
5996
  if (part.type === "text") {
@@ -5663,7 +6000,7 @@ function renderAiContentPart(part) {
5663
6000
  return span;
5664
6001
  }
5665
6002
  if (part.type === "image") {
5666
- const src = aiContentUrl(part);
6003
+ const src = safeContentUrl(part);
5667
6004
  if (!src) return void 0;
5668
6005
  const img = document.createElement("img");
5669
6006
  img.className = "icen-ai-msg-media icen-ai-msg-media--image";
@@ -5673,7 +6010,7 @@ function renderAiContentPart(part) {
5673
6010
  return img;
5674
6011
  }
5675
6012
  if (part.type === "audio") {
5676
- const src = aiContentUrl(part);
6013
+ const src = safeContentUrl(part);
5677
6014
  if (!src) return void 0;
5678
6015
  const audio = document.createElement("audio");
5679
6016
  audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
@@ -5682,7 +6019,7 @@ function renderAiContentPart(part) {
5682
6019
  return audio;
5683
6020
  }
5684
6021
  if (part.type === "video") {
5685
- const src = aiContentUrl(part);
6022
+ const src = safeContentUrl(part);
5686
6023
  if (!src) return void 0;
5687
6024
  const video = document.createElement("video");
5688
6025
  video.className = "icen-ai-msg-media icen-ai-msg-media--video";
@@ -5694,7 +6031,7 @@ function renderAiContentPart(part) {
5694
6031
  if (part.type === "file") {
5695
6032
  const chip = h("span", "icen-ai-msg-file");
5696
6033
  chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
5697
- const href2 = part.url ? safeHref(part.url) : void 0;
6034
+ const href2 = part.url ? safeUrl(part.url) : void 0;
5698
6035
  if (href2 && /^(https?:|data:)/i.test(href2)) {
5699
6036
  const a2 = document.createElement("a");
5700
6037
  a2.className = "icen-ai-msg-file-link";
@@ -5707,7 +6044,7 @@ function renderAiContentPart(part) {
5707
6044
  }
5708
6045
  const a = document.createElement("a");
5709
6046
  a.className = "icen-ai-msg-link";
5710
- const href = safeHref(part.uri);
6047
+ const href = safeUrl(part.uri);
5711
6048
  if (href) a.href = href;
5712
6049
  a.textContent = part.name ?? part.uri;
5713
6050
  a.title = part.uri;
@@ -5769,7 +6106,7 @@ function renderAiMessage(scrollEl, model) {
5769
6106
  errEl.textContent = message;
5770
6107
  },
5771
6108
  stream() {
5772
- const span = h("span", "ai-msg-stream-text");
6109
+ const span = h("span", "icen-ai-msg-text ai-msg-stream-text");
5773
6110
  body.appendChild(span);
5774
6111
  return createAiStream(span);
5775
6112
  }