@icen.ai/ui 0.9.0 → 0.11.0

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 (431) hide show
  1. package/AGENTS.md +82 -254
  2. package/LICENSE +21 -0
  3. package/README.md +60 -96
  4. package/dist/base.css +258 -188
  5. package/dist/behaviors/accordion.mjs +8 -8
  6. package/dist/behaviors/ai-branch.d.mts +1 -1
  7. package/dist/behaviors/ai-branch.mjs +1011 -94
  8. package/dist/behaviors/ai-chat.d.mts +9 -9
  9. package/dist/behaviors/ai-chat.mjs +1122 -169
  10. package/dist/behaviors/ai-composer.d.mts +47 -15
  11. package/dist/behaviors/ai-composer.mjs +2018 -534
  12. package/dist/behaviors/ai-core.d.mts +1 -1
  13. package/dist/behaviors/ai-core.mjs +1017 -107
  14. package/dist/behaviors/ai-diff.mjs +1020 -127
  15. package/dist/behaviors/ai-feedback.d.mts +1 -1
  16. package/dist/behaviors/ai-feedback.mjs +1036 -126
  17. package/dist/behaviors/ai-panel.d.mts +10 -10
  18. package/dist/behaviors/ai-panel.mjs +1285 -266
  19. package/dist/behaviors/ai-provider.d.mts +1 -1
  20. package/dist/behaviors/ai-provider.mjs +1004 -101
  21. package/dist/behaviors/ai-threads.d.mts +1 -1
  22. package/dist/behaviors/ai-threads.mjs +1069 -154
  23. package/dist/behaviors/ai-tool.d.mts +3 -3
  24. package/dist/behaviors/ai-tool.mjs +2087 -413
  25. package/dist/behaviors/ai-tools.d.mts +89 -16
  26. package/dist/behaviors/ai-tools.mjs +5365 -380
  27. package/dist/behaviors/autocomplete.d.mts +53 -0
  28. package/dist/behaviors/autocomplete.mjs +1601 -0
  29. package/dist/behaviors/back-top.d.mts +1 -1
  30. package/dist/behaviors/back-top.mjs +952 -14
  31. package/dist/behaviors/carousel.d.mts +1 -1
  32. package/dist/behaviors/carousel.mjs +914 -12
  33. package/dist/behaviors/cascader.d.mts +48 -0
  34. package/dist/behaviors/cascader.mjs +1867 -0
  35. package/dist/behaviors/charts.d.mts +72 -8
  36. package/dist/behaviors/charts.mjs +1953 -272
  37. package/dist/behaviors/code-block.d.mts +36 -0
  38. package/dist/behaviors/code-block.mjs +1619 -0
  39. package/dist/behaviors/command-palette.d.mts +9 -6
  40. package/dist/behaviors/command-palette.mjs +164 -62
  41. package/dist/behaviors/context-menu.d.mts +10 -9
  42. package/dist/behaviors/context-menu.mjs +1113 -44
  43. package/dist/behaviors/controls.d.mts +21 -21
  44. package/dist/behaviors/controls.mjs +1024 -134
  45. package/dist/behaviors/copy.d.mts +21 -2
  46. package/dist/behaviors/copy.mjs +1207 -42
  47. package/dist/behaviors/datatable.d.mts +55 -5
  48. package/dist/behaviors/datatable.mjs +2033 -212
  49. package/dist/behaviors/date-picker.d.mts +0 -1
  50. package/dist/behaviors/date-picker.mjs +1341 -293
  51. package/dist/behaviors/design.d.mts +54 -0
  52. package/dist/behaviors/design.mjs +109 -0
  53. package/dist/behaviors/dropdown.d.mts +5 -6
  54. package/dist/behaviors/dropdown.mjs +262 -110
  55. package/dist/behaviors/events.d.mts +127 -10
  56. package/dist/behaviors/events.mjs +58 -3
  57. package/dist/behaviors/feedback.d.mts +30 -0
  58. package/dist/behaviors/feedback.mjs +296 -0
  59. package/dist/behaviors/focus.d.mts +8 -0
  60. package/dist/behaviors/focus.mjs +24 -0
  61. package/dist/behaviors/form-validate.d.mts +111 -0
  62. package/dist/behaviors/form-validate.mjs +1746 -0
  63. package/dist/behaviors/i18n.d.mts +790 -0
  64. package/dist/behaviors/i18n.mjs +1713 -0
  65. package/dist/behaviors/icons.d.mts +93 -0
  66. package/dist/behaviors/icons.mjs +113 -0
  67. package/dist/behaviors/input.d.mts +9 -1
  68. package/dist/behaviors/input.mjs +1059 -60
  69. package/dist/behaviors/kb-access.d.mts +3 -3
  70. package/dist/behaviors/kb-access.mjs +2135 -239
  71. package/dist/behaviors/kb-acl.d.mts +8 -8
  72. package/dist/behaviors/kb-acl.mjs +1120 -179
  73. package/dist/behaviors/kb-answer.d.mts +2 -2
  74. package/dist/behaviors/kb-answer.mjs +2120 -435
  75. package/dist/behaviors/kb-audit.d.mts +3 -3
  76. package/dist/behaviors/kb-audit.mjs +1077 -154
  77. package/dist/behaviors/kb-canvas.d.mts +3 -3
  78. package/dist/behaviors/kb-canvas.mjs +1101 -177
  79. package/dist/behaviors/kb-chain.d.mts +2 -2
  80. package/dist/behaviors/kb-chain.mjs +1023 -100
  81. package/dist/behaviors/kb-checkpoint.d.mts +3 -3
  82. package/dist/behaviors/kb-checkpoint.mjs +1320 -169
  83. package/dist/behaviors/kb-chunks.d.mts +2 -2
  84. package/dist/behaviors/kb-chunks.mjs +1153 -213
  85. package/dist/behaviors/kb-citation.d.mts +3 -3
  86. package/dist/behaviors/kb-citation.mjs +1221 -185
  87. package/dist/behaviors/kb-clarify.d.mts +2 -2
  88. package/dist/behaviors/kb-clarify.mjs +1059 -130
  89. package/dist/behaviors/kb-conflict.d.mts +2 -2
  90. package/dist/behaviors/kb-conflict.mjs +1042 -119
  91. package/dist/behaviors/kb-connector.d.mts +2 -2
  92. package/dist/behaviors/kb-connector.mjs +1105 -176
  93. package/dist/behaviors/kb-core.d.mts +7 -2
  94. package/dist/behaviors/kb-core.mjs +1078 -162
  95. package/dist/behaviors/kb-eval.d.mts +2 -2
  96. package/dist/behaviors/kb-eval.mjs +1977 -144
  97. package/dist/behaviors/kb-explain.d.mts +3 -3
  98. package/dist/behaviors/kb-explain.mjs +1037 -104
  99. package/dist/behaviors/kb-filter.d.mts +2 -2
  100. package/dist/behaviors/kb-filter.mjs +2014 -178
  101. package/dist/behaviors/kb-gap.d.mts +3 -3
  102. package/dist/behaviors/kb-gap.mjs +1044 -121
  103. package/dist/behaviors/kb-hittest.d.mts +3 -3
  104. package/dist/behaviors/kb-hittest.mjs +1095 -151
  105. package/dist/behaviors/kb-metadata.mjs +1058 -130
  106. package/dist/behaviors/kb-passage.d.mts +4 -4
  107. package/dist/behaviors/kb-passage.mjs +1102 -161
  108. package/dist/behaviors/kb-pipeline.d.mts +4 -4
  109. package/dist/behaviors/kb-pipeline.mjs +1083 -162
  110. package/dist/behaviors/kb-qa.mjs +1089 -160
  111. package/dist/behaviors/kb-rerank.d.mts +2 -2
  112. package/dist/behaviors/kb-rerank.mjs +1048 -114
  113. package/dist/behaviors/kb-retrieval.d.mts +2 -2
  114. package/dist/behaviors/kb-retrieval.mjs +2079 -226
  115. package/dist/behaviors/kb-review.d.mts +2 -2
  116. package/dist/behaviors/kb-review.mjs +1996 -159
  117. package/dist/behaviors/kb-sandbox.d.mts +3 -3
  118. package/dist/behaviors/kb-sandbox.mjs +1033 -105
  119. package/dist/behaviors/kb-segment.d.mts +2 -2
  120. package/dist/behaviors/kb-segment.mjs +1112 -179
  121. package/dist/behaviors/kb-select.d.mts +24 -0
  122. package/dist/behaviors/kb-select.mjs +1995 -0
  123. package/dist/behaviors/kb-sources.d.mts +3 -3
  124. package/dist/behaviors/kb-sources.mjs +1085 -170
  125. package/dist/behaviors/kb-sql.d.mts +3 -3
  126. package/dist/behaviors/kb-sql.mjs +1144 -226
  127. package/dist/behaviors/kb-trace.d.mts +3 -3
  128. package/dist/behaviors/kb-trace.mjs +1051 -131
  129. package/dist/behaviors/kb-visibility.d.mts +2 -2
  130. package/dist/behaviors/kb-visibility.mjs +1087 -158
  131. package/dist/behaviors/kb-who-can.d.mts +2 -2
  132. package/dist/behaviors/kb-who-can.mjs +1980 -137
  133. package/dist/behaviors/mentions.d.mts +93 -0
  134. package/dist/behaviors/mentions.mjs +2153 -0
  135. package/dist/behaviors/modal.d.mts +4 -3
  136. package/dist/behaviors/modal.mjs +1056 -33
  137. package/dist/behaviors/nav.d.mts +1 -1
  138. package/dist/behaviors/nav.mjs +6 -6
  139. package/dist/behaviors/notification.d.mts +16 -8
  140. package/dist/behaviors/notification.mjs +1629 -268
  141. package/dist/behaviors/panel.d.mts +4 -0
  142. package/dist/behaviors/panel.mjs +995 -0
  143. package/dist/behaviors/popover.d.mts +28 -5
  144. package/dist/behaviors/popover.mjs +225 -24
  145. package/dist/behaviors/scroll-area.d.mts +17 -0
  146. package/dist/behaviors/scroll-area.mjs +59 -0
  147. package/dist/behaviors/select.d.mts +5 -2
  148. package/dist/behaviors/select.mjs +1416 -117
  149. package/dist/behaviors/sidebar.d.mts +1 -1
  150. package/dist/behaviors/sidebar.mjs +13 -13
  151. package/dist/behaviors/slider.d.mts +1 -1
  152. package/dist/behaviors/slider.mjs +12 -12
  153. package/dist/behaviors/split-pane.d.mts +1 -1
  154. package/dist/behaviors/split-pane.mjs +9 -7
  155. package/dist/behaviors/suggestions.d.mts +27 -0
  156. package/dist/behaviors/suggestions.mjs +1090 -0
  157. package/dist/behaviors/svg-parse.d.mts +14 -0
  158. package/dist/behaviors/svg-parse.mjs +37 -0
  159. package/dist/behaviors/tabs.d.mts +2 -2
  160. package/dist/behaviors/tabs.mjs +35 -25
  161. package/dist/behaviors/tag-input.d.mts +23 -5
  162. package/dist/behaviors/tag-input.mjs +1360 -104
  163. package/dist/behaviors/theme-switcher.d.mts +24 -0
  164. package/dist/behaviors/theme-switcher.mjs +1996 -0
  165. package/dist/behaviors/theme.d.mts +15 -8
  166. package/dist/behaviors/theme.mjs +406 -30
  167. package/dist/behaviors/toast.d.mts +24 -25
  168. package/dist/behaviors/toast.mjs +1267 -88
  169. package/dist/behaviors/tooltip.d.mts +4 -0
  170. package/dist/behaviors/tooltip.mjs +378 -0
  171. package/dist/behaviors/tree-select.d.mts +69 -0
  172. package/dist/behaviors/tree-select.mjs +1921 -0
  173. package/dist/behaviors/tree.d.mts +1 -1
  174. package/dist/behaviors/tree.mjs +18 -18
  175. package/dist/behaviors/upload.d.mts +3 -2
  176. package/dist/behaviors/upload.mjs +1077 -66
  177. package/dist/behaviors/url-safety.d.mts +8 -0
  178. package/dist/behaviors/url-safety.mjs +11 -0
  179. package/dist/cli.mjs +5 -6
  180. package/dist/components/accordion.d.mts +2 -0
  181. package/dist/components/ai-branch.d.mts +2 -0
  182. package/dist/components/ai-chat.css +682 -582
  183. package/dist/components/ai-chat.d.mts +2 -0
  184. package/dist/components/ai-composer.d.mts +2 -0
  185. package/dist/components/ai-context.d.mts +2 -0
  186. package/dist/components/ai-context.mjs +1 -0
  187. package/dist/components/ai-diff.css +153 -132
  188. package/dist/components/ai-diff.d.mts +2 -0
  189. package/dist/components/ai-feedback.d.mts +2 -0
  190. package/dist/components/ai-files.d.mts +2 -0
  191. package/dist/components/ai-message.d.mts +2 -0
  192. package/dist/components/ai-panel.css +353 -343
  193. package/dist/components/ai-reasoning.d.mts +2 -0
  194. package/dist/components/ai-subagent.d.mts +2 -0
  195. package/dist/components/ai-subagent.mjs +1 -0
  196. package/dist/components/ai-threads.d.mts +2 -0
  197. package/dist/components/ai-todo.d.mts +2 -0
  198. package/dist/components/ai-todo.mjs +1 -0
  199. package/dist/components/ai-tool-call.d.mts +2 -0
  200. package/dist/components/ai-tool-call.mjs +1 -0
  201. package/dist/components/ai-tool.css +397 -242
  202. package/dist/components/ai-usage.d.mts +2 -0
  203. package/dist/components/alert.d.mts +2 -0
  204. package/dist/components/autocomplete.css +61 -0
  205. package/dist/components/autocomplete.d.mts +2 -0
  206. package/dist/components/autocomplete.mjs +3 -0
  207. package/dist/components/avatar.d.mts +2 -0
  208. package/dist/components/back-top.css +74 -40
  209. package/dist/components/back-top.d.mts +2 -0
  210. package/dist/components/badge.css +44 -41
  211. package/dist/components/badge.d.mts +2 -0
  212. package/dist/components/breadcrumb.css +85 -46
  213. package/dist/components/breadcrumb.d.mts +2 -0
  214. package/dist/components/btn.css +105 -94
  215. package/dist/components/btn.d.mts +2 -0
  216. package/dist/components/card.css +124 -113
  217. package/dist/components/card.d.mts +2 -0
  218. package/dist/components/carousel.d.mts +2 -0
  219. package/dist/components/cascader.css +332 -0
  220. package/dist/components/cascader.d.mts +2 -0
  221. package/dist/components/cascader.mjs +3 -0
  222. package/dist/components/chart-area.css +54 -2
  223. package/dist/components/chart-area.d.mts +2 -0
  224. package/dist/components/chart-bar.css +147 -38
  225. package/dist/components/chart-bar.d.mts +2 -0
  226. package/dist/components/chart-calendar.d.mts +2 -0
  227. package/dist/components/chart-gauge.css +36 -13
  228. package/dist/components/chart-gauge.d.mts +2 -0
  229. package/dist/components/chart-graph.css +35 -20
  230. package/dist/components/chart-graph.d.mts +2 -0
  231. package/dist/components/chart-heatmap.css +67 -39
  232. package/dist/components/chart-heatmap.d.mts +2 -0
  233. package/dist/components/chart-line.css +62 -3
  234. package/dist/components/chart-line.d.mts +2 -0
  235. package/dist/components/chart-map.d.mts +2 -0
  236. package/dist/components/chart-pie.css +38 -6
  237. package/dist/components/chart-pie.d.mts +2 -0
  238. package/dist/components/chart-radar.css +57 -5
  239. package/dist/components/chart-radar.d.mts +2 -0
  240. package/dist/components/chart-scatter.css +47 -7
  241. package/dist/components/chart-scatter.d.mts +2 -0
  242. package/dist/components/chart-sparkline.css +25 -2
  243. package/dist/components/chart-sparkline.d.mts +2 -0
  244. package/dist/components/chart-stack.css +27 -13
  245. package/dist/components/chart-stack.d.mts +2 -0
  246. package/dist/components/charts.css +220 -84
  247. package/dist/components/charts.d.mts +2 -0
  248. package/dist/components/code-block.css +420 -0
  249. package/dist/components/code-block.d.mts +2 -0
  250. package/dist/components/code-block.mjs +4 -0
  251. package/dist/components/command-palette.css +150 -122
  252. package/dist/components/command-palette.d.mts +2 -0
  253. package/dist/components/content.css +274 -263
  254. package/dist/components/context-menu.d.mts +2 -0
  255. package/dist/components/copy.css +73 -45
  256. package/dist/components/copy.d.mts +2 -0
  257. package/dist/components/datatable.css +457 -202
  258. package/dist/components/datatable.d.mts +2 -0
  259. package/dist/components/date-picker.css +136 -105
  260. package/dist/components/date-picker.d.mts +2 -0
  261. package/dist/components/desc.d.mts +2 -0
  262. package/dist/components/dropdown.d.mts +2 -0
  263. package/dist/components/empty.css +72 -69
  264. package/dist/components/empty.d.mts +2 -0
  265. package/dist/components/feedback.css +211 -191
  266. package/dist/components/form-validate.css +134 -0
  267. package/dist/components/form-validate.d.mts +2 -0
  268. package/dist/components/form-validate.mjs +3 -0
  269. package/dist/components/form.css +157 -131
  270. package/dist/components/form.d.mts +2 -0
  271. package/dist/components/icon.css +113 -0
  272. package/dist/components/icon.d.mts +2 -0
  273. package/dist/components/icon.mjs +3 -0
  274. package/dist/components/input.css +163 -108
  275. package/dist/components/input.d.mts +2 -0
  276. package/dist/components/kb-access.d.mts +2 -0
  277. package/dist/components/kb-acl.d.mts +2 -0
  278. package/dist/components/kb-agent.css +300 -206
  279. package/dist/components/kb-answer.d.mts +2 -0
  280. package/dist/components/kb-audit.d.mts +2 -0
  281. package/dist/components/kb-canvas.d.mts +2 -0
  282. package/dist/components/kb-chain.d.mts +2 -0
  283. package/dist/components/kb-checkpoint.d.mts +2 -0
  284. package/dist/components/kb-chunks.d.mts +2 -0
  285. package/dist/components/kb-citation.d.mts +2 -0
  286. package/dist/components/kb-clarify.d.mts +2 -0
  287. package/dist/components/kb-conflict.d.mts +2 -0
  288. package/dist/components/kb-connector.d.mts +2 -0
  289. package/dist/components/kb-data.css +431 -315
  290. package/dist/components/kb-eval.d.mts +2 -0
  291. package/dist/components/kb-explain.d.mts +2 -0
  292. package/dist/components/kb-filter.d.mts +2 -0
  293. package/dist/components/kb-gap.d.mts +2 -0
  294. package/dist/components/kb-ground.css +333 -229
  295. package/dist/components/kb-hittest.d.mts +2 -0
  296. package/dist/components/kb-ingest.css +613 -434
  297. package/dist/components/kb-metadata.d.mts +2 -0
  298. package/dist/components/kb-ops.css +422 -302
  299. package/dist/components/kb-passage.d.mts +2 -0
  300. package/dist/components/kb-perm.css +374 -314
  301. package/dist/components/kb-pipeline.d.mts +2 -0
  302. package/dist/components/kb-qa.d.mts +2 -0
  303. package/dist/components/kb-rerank.d.mts +2 -0
  304. package/dist/components/kb-retrieval.d.mts +2 -0
  305. package/dist/components/kb-review.d.mts +2 -0
  306. package/dist/components/kb-sandbox.d.mts +2 -0
  307. package/dist/components/kb-search.css +653 -459
  308. package/dist/components/kb-segment.d.mts +2 -0
  309. package/dist/components/kb-sources.d.mts +2 -0
  310. package/dist/components/kb-sql.d.mts +2 -0
  311. package/dist/components/kb-trace.d.mts +2 -0
  312. package/dist/components/kb-visibility.d.mts +2 -0
  313. package/dist/components/kb-who-can.d.mts +2 -0
  314. package/dist/components/kb.css +170 -135
  315. package/dist/components/kb.d.mts +2 -0
  316. package/dist/components/kbd.d.mts +2 -0
  317. package/dist/components/layout.css +86 -83
  318. package/dist/components/layout.d.mts +2 -0
  319. package/dist/components/list.d.mts +2 -0
  320. package/dist/components/material-chinese.css +83 -0
  321. package/dist/components/material-soviet.css +86 -0
  322. package/dist/components/material.css +318 -0
  323. package/dist/components/media-card.d.mts +2 -0
  324. package/dist/components/media.css +225 -176
  325. package/dist/components/mentions.css +190 -0
  326. package/dist/components/mentions.d.mts +2 -0
  327. package/dist/components/mentions.mjs +3 -0
  328. package/dist/components/menu.css +121 -109
  329. package/dist/components/modal.css +116 -118
  330. package/dist/components/modal.d.mts +2 -0
  331. package/dist/components/nav.css +136 -129
  332. package/dist/components/nav.d.mts +2 -0
  333. package/dist/components/notification.css +247 -177
  334. package/dist/components/notification.d.mts +2 -0
  335. package/dist/components/pagination.css +62 -57
  336. package/dist/components/pagination.d.mts +2 -0
  337. package/dist/components/panel.css +70 -68
  338. package/dist/components/panel.d.mts +2 -0
  339. package/dist/components/panel.mjs +1 -0
  340. package/dist/components/pill.css +83 -72
  341. package/dist/components/pill.d.mts +2 -0
  342. package/dist/components/popover.css +80 -57
  343. package/dist/components/popover.d.mts +2 -0
  344. package/dist/components/progress.d.mts +2 -0
  345. package/dist/components/rating.d.mts +2 -0
  346. package/dist/components/result.d.mts +2 -0
  347. package/dist/components/scroll-area.css +29 -54
  348. package/dist/components/scroll-area.d.mts +2 -0
  349. package/dist/components/scroll-area.mjs +1 -0
  350. package/dist/components/segmented.css +167 -146
  351. package/dist/components/segmented.d.mts +2 -0
  352. package/dist/components/select.css +250 -191
  353. package/dist/components/select.d.mts +2 -0
  354. package/dist/components/sidebar.css +157 -143
  355. package/dist/components/sidebar.d.mts +2 -0
  356. package/dist/components/skeleton.d.mts +2 -0
  357. package/dist/components/slider.css +135 -128
  358. package/dist/components/slider.d.mts +2 -0
  359. package/dist/components/spinner.d.mts +2 -0
  360. package/dist/components/split-pane.css +120 -108
  361. package/dist/components/split-pane.d.mts +2 -0
  362. package/dist/components/stat.css +116 -109
  363. package/dist/components/stat.d.mts +2 -0
  364. package/dist/components/steps.css +114 -108
  365. package/dist/components/steps.d.mts +2 -0
  366. package/dist/components/switch.css +192 -149
  367. package/dist/components/switch.d.mts +2 -0
  368. package/dist/components/table.css +158 -112
  369. package/dist/components/table.d.mts +2 -0
  370. package/dist/components/tabs.css +143 -116
  371. package/dist/components/tabs.d.mts +2 -0
  372. package/dist/components/tag-input.css +52 -133
  373. package/dist/components/tag-input.d.mts +2 -0
  374. package/dist/components/tag.css +90 -72
  375. package/dist/components/tag.d.mts +2 -0
  376. package/dist/components/theme-switcher.css +105 -0
  377. package/dist/components/theme-switcher.d.mts +2 -0
  378. package/dist/components/theme-switcher.mjs +3 -0
  379. package/dist/components/timeline.d.mts +2 -0
  380. package/dist/components/toast.css +115 -97
  381. package/dist/components/toast.d.mts +2 -0
  382. package/dist/components/toolbar.css +47 -43
  383. package/dist/components/toolbar.d.mts +2 -0
  384. package/dist/components/tooltip.css +103 -43
  385. package/dist/components/tooltip.d.mts +2 -0
  386. package/dist/components/tooltip.mjs +1 -0
  387. package/dist/components/tree-select.css +439 -0
  388. package/dist/components/tree-select.d.mts +2 -0
  389. package/dist/components/tree-select.mjs +3 -0
  390. package/dist/components/tree.d.mts +2 -0
  391. package/dist/components/upload.css +138 -97
  392. package/dist/components/upload.d.mts +2 -0
  393. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  394. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  395. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  396. package/dist/fonts/OFL.txt +96 -0
  397. package/dist/fonts/README.md +14 -0
  398. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  399. package/dist/index.d.mts +85 -70
  400. package/dist/index.mjs +17330 -5773
  401. package/dist/react.d.mts +91 -0
  402. package/dist/react.mjs +8307 -0
  403. package/dist/registry.json +918 -70
  404. package/dist/tokens/chinese.css +44 -0
  405. package/dist/tokens/colors.css +371 -1222
  406. package/dist/tokens/design.css +209 -0
  407. package/dist/tokens/dtcg.json +15926 -0
  408. package/dist/tokens/figma.variables.json +10779 -0
  409. package/dist/tokens/icon-masks.css +78 -0
  410. package/dist/tokens/pixel.css +53 -0
  411. package/dist/tokens/scrollbars.css +40 -0
  412. package/dist/tokens/soviet.css +44 -0
  413. package/dist/tokens/style-profiles.css +36 -547
  414. package/dist/tokens/themes.json +308 -0
  415. package/dist/tokens/tokens-studio.json +11648 -0
  416. package/dist/tokens/typography.css +21 -18
  417. package/dist/tokens.css +1783 -1806
  418. package/dist/ui.css +14796 -10750
  419. package/dist/vue.d.mts +344 -0
  420. package/dist/vue.mjs +7876 -0
  421. package/docs/spec/ai-input-experience.md +75 -0
  422. package/docs/spec/ai-native.md +238 -147
  423. package/docs/spec/design-philosophy.md +189 -0
  424. package/docs/spec/design-primitives.md +196 -0
  425. package/docs/spec/kb-family.md +147 -115
  426. package/docs/spec/scrollbars.md +46 -0
  427. package/package.json +56 -8
  428. package/dist/retro-effects.css +0 -255
  429. package/dist/tokens/retro-effects.css +0 -255
  430. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  431. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -1,10 +1,127 @@
1
+ // src/behaviors/icons.ts
2
+ var ICON_PATHS = {
3
+ file: "M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16",
4
+ folder: "M3 5a1.5 1.5 0 0 1 1.5-1.5H8l2 2h5.5A1.5 1.5 0 0 1 17 7v8a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 3 15Z",
5
+ globe: "M17.5 10a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0ZM2.5 10h15M10 2.5c-4 4-4 11 0 15 4-4 4-11 0-15Z",
6
+ document: "M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16M7 10.5h6M7 13.5h6",
7
+ agent: "M10 6V3M8 3h2M5 6h10a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2ZM1.5 10h1.5M17 10h1.5M7 10v2M13 10v2M8 14h4",
8
+ paperclip: "M14 7 8.3 12.7a1.6 1.6 0 0 1-2.3-2.3l6.3-6.3a3.2 3.2 0 0 1 4.5 4.5l-7 7a4.7 4.7 0 0 1-6.7-6.7l7-7",
9
+ stop: "M6.5 5h7A1.5 1.5 0 0 1 15 6.5v7a1.5 1.5 0 0 1-1.5 1.5h-7A1.5 1.5 0 0 1 5 13.5v-7A1.5 1.5 0 0 1 6.5 5Z",
10
+ terminal: "M5 3.5h10a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2ZM6 7l3 3-3 3M11 13h3",
11
+ branch: "M6 6v8M14 6v2a4 4 0 0 1-4 4H6M8 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM8 16a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM16 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z",
12
+ "line-numbers": "M3 5h2M3 10h2M3 15h2M8 5h9M8 10h9M8 15h9",
13
+ wrap: "M3 5h14M3 10h10a3 3 0 0 1 0 6h-3M12.5 13.5 10 16l2.5 2.5",
14
+ calendar: "M5.5 4h9A2.5 2.5 0 0 1 17 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 3 14.5v-8A2.5 2.5 0 0 1 5.5 4ZM6.5 2.5v3M13.5 2.5v3M3 8h14M6.5 11h.1M10 11h.1M13.5 11h.1M6.5 14h.1M10 14h.1",
15
+ close: "M6 6l8 8M14 6l-8 8",
16
+ check: "M4.5 10.2l3.6 3.6 7.4-7.6",
17
+ "chevron-down": "M5.5 7.75 10 12.25l4.5-4.5",
18
+ "chevron-up": "M5.5 12.25 10 7.75l4.5 4.5",
19
+ "chevron-right": "M7.75 5.5 12.25 10l-4.5 4.5",
20
+ "chevron-left": "M12.25 5.5 7.75 10l4.5 4.5",
21
+ "arrow-right": "M3.5 10h13M11 4.5l5.5 5.5-5.5 5.5",
22
+ "arrow-left": "M16.5 10h-13M9 4.5 3.5 10 9 15.5",
23
+ "arrow-up": "M10 16.5v-13M4.5 9 10 3.5 15.5 9",
24
+ "arrow-down": "M10 3.5v13M4.5 11l5.5 5.5 5.5-5.5",
25
+ plus: "M10 4v12M4 10h12",
26
+ minus: "M4 10h12",
27
+ sort: "M6 15V4M3 7l3-3 3 3M14 5v11M11 13l3 3 3-3",
28
+ search: "M13.3 13.3 17 17M14.5 8.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0",
29
+ sun: "M13.5 10a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0M10 1.75v1.5M10 16.75v1.5M1.75 10h1.5M16.75 10h1.5M4.17 4.17l1.06 1.06M14.77 14.77l1.06 1.06M4.17 15.83l1.06-1.06M14.77 5.23l1.06-1.06",
30
+ moon: "M17.25 11.15A7.5 7.5 0 0 1 8.85 2.75a7.5 7.5 0 1 0 8.4 8.4Z",
31
+ modern: "M6.5 3h7A3.5 3.5 0 0 1 17 6.5v7a3.5 3.5 0 0 1-3.5 3.5h-7A3.5 3.5 0 0 1 3 13.5v-7A3.5 3.5 0 0 1 6.5 3ZM7 10l3-3 3 3-3 3Z",
32
+ pixel: "M3 3h5v5H3ZM12 3h5v5h-5ZM3 12h5v5H3ZM12 12h5v5h-5Z",
33
+ chinese: "M3 8c3 0 5-2 7-5 2 3 4 5 7 5M4 8h12M6 8v8m8-8v8M3 16h14M8 16v-5h4v5",
34
+ soviet: "M3 17h14M5 17V8h4v9m0-12h6v12M7 8V5h2m2 3h2m-2 3h2m-2 3h2M10 5V3h4v2",
35
+ more: "M4 9.9v.2M10 9.9v.2M16 9.9v.2",
36
+ copy: "M7 7h8a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V7ZM13 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2",
37
+ edit: "M11.5 4.5l4 4M4 12l9-9a1.4 1.4 0 0 1 2 0l2 2a1.4 1.4 0 0 1 0 2l-9 9-5 1Z",
38
+ link: "M8 6l2-2a4.2 4.2 0 0 1 6 6l-2 2M12 14l-2 2a4.2 4.2 0 0 1-6-6l2-2M7 13l6-6",
39
+ trash: "M3.5 5.5h13M7 5.5V3h6v2.5M5 5.5l.7 11.5h8.6L15 5.5M8 9v5M12 9v5",
40
+ spinner: "M10 3a7 7 0 1 1-7 7",
41
+ "circle-check": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM6 10l2.7 2.7 5.3-5.4",
42
+ "circle-error": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM7.2 7.2l5.6 5.6M12.8 7.2l-5.6 5.6",
43
+ "circle-info": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM10 9v5M10 6.1v.15",
44
+ "triangle-alert": "M8.7 3.5a1.5 1.5 0 0 1 2.6 0l6.4 11.3a1.5 1.5 0 0 1-1.3 2.2H3.6a1.5 1.5 0 0 1-1.3-2.2ZM10 7.2v4.4M10 14v.15",
45
+ refresh: "M16.5 7.2A7 7 0 0 0 4.3 5.9L2.5 8M2.5 3.5V8H7M3.5 12.8a7 7 0 0 0 12.2 1.3l1.8-2.1M13 12h4.5v4.5",
46
+ external: "M11.5 3H17v5.5M17 3l-8 8M8 3H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3",
47
+ home: "M3.5 10.25 10 4l6.5 6.25M5.75 8.75v7a.75.75 0 0 0 .75.75h7.5a.75.75 0 0 0 .75-.75v-7",
48
+ settings: "M3.5 5.5h13M3.5 10h13M3.5 14.5h13M7 4v3M12.5 8.5v3M8 13v3",
49
+ star: "M10 2.5l2.4 5.1 5.6.4-4.2 3.7 1.3 5.5-5.1-3-5.1 3 1.3-5.5L1.8 8l5.6-.4Z",
50
+ eye: "M2.2 10s3-5.4 7.8-5.4S17.8 10 17.8 10s-3 5.4-7.8 5.4S2.2 10 2.2 10ZM10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8Z",
51
+ "eye-off": "M2.2 10s3-5.4 7.8-5.4S17.8 10 17.8 10s-3 5.4-7.8 5.4S2.2 10 2.2 10ZM10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8ZM3.5 3.5l13 13",
52
+ inbox: "M3.5 12.25h3.7l1.5 2.5h2.6l1.5-2.5h3.7M4.7 5.5l-1.2 6.75v3.25a1.5 1.5 0 0 0 1.5 1.5h10a1.5 1.5 0 0 0 1.5-1.5v-3.25L15.3 5.5a1.3 1.3 0 0 0-1.25-1H5.95a1.3 1.3 0 0 0-1.25 1Z",
53
+ bell: "M10 3.5a4.5 4.5 0 0 1 4.5 4.5c0 4.5 1.8 5.7 2.5 6.5H3c.7-.8 2.5-2 2.5-6.5A4.5 4.5 0 0 1 10 3.5ZM8.5 16.5a1.6 1.6 0 0 0 3 0",
54
+ users: "M13.8 16.5v-1.5a3.5 3.5 0 0 0-3.5-3.5H6.3a3.5 3.5 0 0 0-3.5 3.5v1.5M8.3 8.9a2.7 2.7 0 1 0 0-5.4 2.7 2.7 0 0 0 0 5.4ZM16.5 16.5v-1.3a3.3 3.3 0 0 0-2.3-3.1M12.3 3.7a2.7 2.7 0 0 1 0 5.2",
55
+ activity: "M17 10h-2.6l-2 5.8L8 4.2 6 10H3",
56
+ "trend-up": "M3.5 14.5l4.2-4.2 2.8 2.8 5.9-5.9M12.4 7.2h4.2v4.2",
57
+ "trend-down": "M3.5 5.5l4.2 4.2 2.8-2.8 5.9 5.9M12.4 12.8h4.2V8.6",
58
+ rocket: "M10 2.5c2 1.5 3.2 4 3.2 6.8 0 1.5-.3 2.9-.8 4.2H7.6c-.5-1.3-.8-2.7-.8-4.2 0-2.8 1.2-5.3 3.2-6.8ZM10 8.6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM7.6 12.5 5.6 15.4c-.9.3-1.6 1-2 2M12.4 12.5l2 2.9c.9.3 1.6 1 2 2M8.7 13.8c0 1.8.5 3.1 1.3 4.2.8-1.1 1.3-2.4 1.3-4.2",
59
+ bold: "M6.5 4h4.2a3 3 0 0 1 0 6H6.5M6.5 10h5a3 3 0 0 1 0 6H6.5M6.5 4v12",
60
+ italic: "M8.5 4.5h7M4.5 15.5h7M12.5 4.5l-5 11",
61
+ underline: "M6 4v5.5a4 4 0 0 0 8 0V4M4.5 16h11",
62
+ "align-left": "M3.5 4.5h13M3.5 10h8.5M3.5 15.5h11",
63
+ "align-center": "M3.5 4.5h13M5.75 10h8.5M4.5 15.5h11",
64
+ "align-right": "M3.5 4.5h13M8 10h8.5M5.5 15.5h11",
65
+ list: "M6.5 5h10M6.5 10h10M6.5 15h10M3.5 5h.01M3.5 10h.01M3.5 15h.01",
66
+ server: "M3 3h14a1.5 1.5 0 0 1 1.5 1.5v2A1.5 1.5 0 0 1 17 8H3a1.5 1.5 0 0 1-1.5-1.5v-2A1.5 1.5 0 0 1 3 3ZM3 12h14a1.5 1.5 0 0 1 1.5 1.5v2A1.5 1.5 0 0 1 17 17H3a1.5 1.5 0 0 1-1.5-1.5v-2A1.5 1.5 0 0 1 3 12ZM5 5.5h.01M5 14.5h.01",
67
+ sparkle: "M10 2.5l1.6 4.3 4.3 1.6-4.3 1.6L10 14.3l-1.6-4.3-4.3-1.6 4.3-1.6ZM15.5 12.5l.8 2.1 2.1.8-2.1.8-.8 2.1-.8-2.1-2.1-.8 2.1-.8Z",
68
+ play: "M6.5 4.8v10.4c0 .9 1 1.5 1.8 1l8.3-5.2a1.2 1.2 0 0 0 0-2L8.3 3.8a1.2 1.2 0 0 0-1.8 1Z",
69
+ "chart-line": "M3.5 3.5v13h13M6.5 12l2.8-2.8 2.2 2.2 4-4.4",
70
+ layers: "M10 3.2 3.6 6.5 10 9.8l6.4-3.3ZM4.5 10.4 10 13.2l5.5-2.8M4.5 13.6 10 16.4l5.5-2.8",
71
+ box: "M17 6 10 3.2 3 6v8l7 2.8 7-2.8ZM3 6l7 2.8L17 6M10 9v7.8",
72
+ filter: "M4 4.5h12l-4.4 5.1v5l-3.2-1.6V9.6Z",
73
+ columns: "M3.5 4h13v12h-13ZM8.2 4v12M12.8 4v12",
74
+ download: "M10 3.5v8M6.8 8.3 10 11.5l3.2-3.2M4 15v2.5a1.5 1.5 0 0 0 1.5 1.5h9a1.5 1.5 0 0 0 1.5-1.5V15"
75
+ };
76
+ var custom = /* @__PURE__ */ new Map();
77
+ function iconPath(name) {
78
+ return Object.hasOwn(ICON_PATHS, name) ? ICON_PATHS[name] : custom.get(name) ?? null;
79
+ }
80
+ function iconAttributes(o = {}) {
81
+ const size = Number.isFinite(o.size) && o.size > 0 ? o.size : 16;
82
+ return { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", width: String(size), height: String(size), fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round", focusable: "false", class: ["icen-symbol", o.className].filter(Boolean).join(" "), ...o.label ? { role: "img", "aria-label": o.label } : { "aria-hidden": "true" } };
83
+ }
84
+ function createIcon(name, o = {}) {
85
+ if (typeof document === "undefined") return null;
86
+ const path = iconPath(name);
87
+ if (!path) return null;
88
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
89
+ for (const [key, value] of Object.entries(iconAttributes(o))) svg.setAttribute(key, value);
90
+ const line = document.createElementNS(svg.namespaceURI, "path");
91
+ line.setAttribute("d", path);
92
+ svg.append(line);
93
+ return svg;
94
+ }
95
+
1
96
  // src/behaviors/popover.ts
97
+ function revealPopoverItem(item, scrollport, opts = {}) {
98
+ if (typeof document === "undefined") return;
99
+ if (opts.focus) item.focus({ preventScroll: true });
100
+ const rect = item.getBoundingClientRect(), bounds = scrollport.getBoundingClientRect();
101
+ const style = getComputedStyle(scrollport);
102
+ const inset = (value, extent) => {
103
+ const amount = Number.parseFloat(value) || 0;
104
+ return value.endsWith("%") ? amount * extent / 100 : amount;
105
+ };
106
+ if (opts.axis !== "inline") {
107
+ const top = bounds.top + scrollport.clientTop + inset(style.scrollPaddingTop, scrollport.clientHeight);
108
+ const bottom = bounds.top + scrollport.clientTop + scrollport.clientHeight - inset(style.scrollPaddingBottom, scrollport.clientHeight);
109
+ if (rect.top < top) scrollport.scrollTop -= top - rect.top;
110
+ else if (rect.bottom > bottom) scrollport.scrollTop += rect.bottom - bottom;
111
+ }
112
+ if (opts.axis === "inline" || opts.axis === "both") {
113
+ const left = bounds.left + scrollport.clientLeft + inset(style.scrollPaddingLeft, scrollport.clientWidth);
114
+ const right = bounds.left + scrollport.clientLeft + scrollport.clientWidth - inset(style.scrollPaddingRight, scrollport.clientWidth);
115
+ if (rect.left < left) scrollport.scrollLeft -= left - rect.left;
116
+ else if (rect.right > right) scrollport.scrollLeft += rect.right - right;
117
+ }
118
+ }
2
119
  var PANEL_SIZING_ATTRS = {
3
- width: "data-panel-width",
4
- minWidth: "data-panel-min",
5
- maxWidth: "data-panel-max",
6
- minHeight: "data-panel-min-height",
7
- maxHeight: "data-panel-max-height"
120
+ width: "data-icen-panel-width",
121
+ minWidth: "data-icen-panel-min",
122
+ maxWidth: "data-icen-panel-max",
123
+ minHeight: "data-icen-panel-min-height",
124
+ maxHeight: "data-icen-panel-max-height"
8
125
  };
9
126
  function readPanelSizing(el) {
10
127
  const out = {};
@@ -74,10 +191,10 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
74
191
  const preferredSide = opts.side ?? "top";
75
192
  const align = opts.align ?? "start";
76
193
  if (preferredSide === "left" || preferredSide === "right") {
194
+ const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
77
195
  const availableLeft = Math.max(0, anchor.left - margin - offset);
78
196
  const availableRight = Math.max(0, viewport.width - anchor.right - margin - offset);
79
- const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= DEFAULT_MIN_WIDTH ? preferredSide : preferredSide === "left" ? "right" : "left";
80
- const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
197
+ const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= minWidth2 ? preferredSide : preferredSide === "left" ? "right" : "left";
81
198
  const maxWidth2 = Math.min(
82
199
  Math.max(opts.maxWidth ?? DEFAULT_MAX_WIDTH, minWidth2),
83
200
  side2 === "left" ? availableLeft : availableRight
@@ -106,7 +223,7 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
106
223
  const minHeight = Math.min(Math.max(80, opts.minHeight ?? DEFAULT_MIN_HEIGHT), availableHeight);
107
224
  const requestedMaxHeight = Math.max(minHeight, opts.maxHeight ?? DEFAULT_MAX_HEIGHT);
108
225
  const fallbackHeight = Math.min(260, requestedMaxHeight);
109
- const contentHeight = Math.max(opts.contentHeightHint ?? 0, fallbackHeight);
226
+ const contentHeight = opts.contentHeightHint != null && opts.contentHeightHint > 0 ? opts.contentHeightHint : fallbackHeight;
110
227
  const desiredHeight = clamp(contentHeight, minHeight, Math.min(requestedMaxHeight, availableHeight));
111
228
  const side = chooseSide(preferredSide, availableTop, availableBottom, desiredHeight);
112
229
  const sideSpace = side === "top" ? availableTop : availableBottom;
@@ -122,6 +239,49 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
122
239
  const top = clamp(desiredTop, margin, viewport.height - margin - positionedHeight);
123
240
  return { side, left, top, width, maxHeight };
124
241
  }
242
+ var menuCloser = null;
243
+ function claimMenuFocus(close) {
244
+ menuCloser?.();
245
+ menuCloser = close;
246
+ return () => {
247
+ if (menuCloser === close) menuCloser = null;
248
+ };
249
+ }
250
+
251
+ // src/behaviors/svg-parse.ts
252
+ function parseSvg(source) {
253
+ if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
254
+ const trimmed = source.trimStart();
255
+ if (!trimmed.startsWith("<svg")) return null;
256
+ const src = /^<svg(?![^>]*\bxmlns[=:])/i.test(trimmed) ? trimmed.replace(/^<svg/i, '<svg xmlns="http://www.w3.org/2000/svg"') : trimmed;
257
+ let parsed;
258
+ try {
259
+ parsed = new DOMParser().parseFromString(src, "image/svg+xml");
260
+ } catch {
261
+ return null;
262
+ }
263
+ const root = parsed.documentElement;
264
+ if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) return null;
265
+ const sanitize = (el) => {
266
+ for (const attr of Array.from(el.attributes)) {
267
+ const name = attr.name.toLowerCase();
268
+ if (name.startsWith("on")) el.removeAttribute(attr.name);
269
+ if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
270
+ el.removeAttribute(attr.name);
271
+ }
272
+ }
273
+ for (const child of Array.from(el.children)) {
274
+ const tag = child.tagName.toLowerCase();
275
+ if (tag === "script" || tag === "foreignobject") {
276
+ child.remove();
277
+ continue;
278
+ }
279
+ sanitize(child);
280
+ }
281
+ };
282
+ sanitize(root);
283
+ return document.importNode(root, true);
284
+ }
125
285
 
126
286
  // src/behaviors/events.ts
127
287
  function emitIcen(source, type, detail) {
@@ -130,6 +290,850 @@ function emitIcen(source, type, detail) {
130
290
  );
131
291
  }
132
292
 
293
+ // src/behaviors/i18n.ts
294
+ var ICEN_LOCALE_ZH_CN = {
295
+ /* ── aiBranch ── */
296
+ "aiBranch.nextVersion": "\u4E0B\u4E00\u7248\u672C",
297
+ "aiBranch.prevVersion": "\u4E0A\u4E00\u7248\u672C",
298
+ "aiBranch.version": "\u5206\u652F\u7248\u672C",
299
+ /* ── aiChat ── */
300
+ "aiChat.backToBottom": "\u56DE\u5230\u5E95\u90E8",
301
+ "aiChat.backToBottomCount": "\u56DE\u5230\u5E95\u90E8 \xB7 {p0} \u6761\u65B0\u6D88\u606F",
302
+ "aiChat.continue": "\u7EE7\u7EED\u751F\u6210",
303
+ "aiChat.download": "\u4E0B\u8F7D",
304
+ "aiChat.file": "\u6587\u4EF6",
305
+ "aiChat.roleSystem": "\u7CFB",
306
+ "aiChat.roleTool": "\u5DE5",
307
+ "aiChat.roleUser": "\u6211",
308
+ "aiChat.thinking": "\u601D\u8003 {p0}",
309
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
310
+ /* ── aiComposer ── */
311
+ "aiComposer.attachAgent": "\u4EE3\u7406",
312
+ "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
313
+ "aiComposer.searchLibrary": "\u641C\u7D22\u6280\u80FD\u3001\u5DE5\u5177\u3001\u6587\u4EF6\u4E0E\u547D\u4EE4",
314
+ "aiComposer.all": "\u5168\u90E8",
315
+ "aiComposer.skills": "\u6280\u80FD",
316
+ "aiComposer.tools": "\u5DE5\u5177",
317
+ "aiComposer.libraryHint": "\u4E0A\u4E0B\u6587\u968F\u6D88\u606F\u53D1\u9001 \xB7 \u547D\u4EE4\u5148\u586B\u5165\u8F93\u5165\u6846",
318
+ "aiComposer.commandHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u6267\u884C \xB7 Esc \u8FD4\u56DE",
319
+ "aiComposer.refHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u5F15\u7528 \xB7 Esc \u8FD4\u56DE",
320
+ "aiComposer.noLibraryMatch": "\u6CA1\u6709\u5339\u914D\u7684\u9879\u76EE\uFF0C\u8BD5\u8BD5\u5176\u4ED6\u5173\u952E\u8BCD",
321
+ "aiComposer.filesNeedAdapter": "\u9644\u4EF6\u5C1A\u672A\u63A5\u901A\u4E0A\u4F20\u3002\u8BF7\u914D\u7F6E prepareMessage \u540E\u91CD\u8BD5\uFF0C\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u6B64\u8BF7\u6C42\u4E2D\u3002",
322
+ "aiComposer.attachDoc": "\u6587\u6863",
323
+ "aiComposer.attachFile": "\u6587\u4EF6",
324
+ "aiComposer.attachFolder": "\u6587\u4EF6\u5939",
325
+ "aiComposer.cacheInvalidHint": "\u5207\u6362\u6A21\u578B\u4F1A\u4F7F prompt \u7F13\u5B58\u5931\u6548",
326
+ "aiComposer.commands": "\u547D\u4EE4",
327
+ "aiComposer.currentTodos": "\u5F53\u524D\u5F85\u529E",
328
+ "aiComposer.done": "\u5B8C\u6210",
329
+ "aiComposer.justNow": "\u521A\u521A \xB7 {p0}",
330
+ "aiComposer.modelAria": "\u6A21\u578B {p0}\uFF08{p1}\uFF09",
331
+ "aiComposer.noCommandMatch": "\u65E0\u5339\u914D\u547D\u4EE4",
332
+ "aiComposer.noModelMatch": "\u65E0\u5339\u914D\u6A21\u578B",
333
+ "aiComposer.noRefMatch": "\u65E0\u5339\u914D\u5F15\u7528",
334
+ "aiComposer.placeholder": "\u8F93\u5165\u6D88\u606F\uFF0C/ \u547D\u4EE4 \xB7 @ \u5F15\u7528 \xB7 Enter \u53D1\u9001",
335
+ "aiComposer.refs": "\u5F15\u7528",
336
+ "aiComposer.removeAttachment": "\u79FB\u9664\u9644\u4EF6 {p0}",
337
+ "aiComposer.removeQueued": "\u79FB\u9664\u6392\u961F\u6D88\u606F {p0}",
338
+ "aiComposer.removeRef": "\u79FB\u9664\u5F15\u7528 {p0}",
339
+ "aiComposer.searchModels": "\u641C\u7D22\u6A21\u578B",
340
+ "aiComposer.selectModel": "\u9009\u62E9\u6A21\u578B",
341
+ "aiComposer.send": "\u53D1\u9001",
342
+ "aiComposer.stop": "\u505C\u6B62\u751F\u6210",
343
+ "aiComposer.stopped": "\u5DF2\u505C\u6B62",
344
+ "aiComposer.todoChip": "\u5F53\u524D\u5F85\u529E {p0}/{p1}{p2}",
345
+ "aiComposer.todoHasError": "\uFF08\u6709\u5931\u8D25\u9879\uFF09",
346
+ /* ── aiCore ── */
347
+ "aiCore.kindBrowser": "\u6D4F\u89C8",
348
+ "aiCore.kindChart": "\u56FE\u8868",
349
+ "aiCore.kindDelete": "\u5220\u9664",
350
+ "aiCore.kindEdit": "\u7F16\u8F91",
351
+ "aiCore.kindFetch": "\u8BF7\u6C42",
352
+ "aiCore.kindGlob": "\u5339\u914D",
353
+ "aiCore.kindGrep": "\u641C\u7D22",
354
+ "aiCore.kindNote": "\u7B14\u8BB0",
355
+ "aiCore.kindPlan": "\u8BA1\u5212",
356
+ "aiCore.kindRead": "\u8BFB\u53D6",
357
+ "aiCore.kindSearch": "\u68C0\u7D22",
358
+ "aiCore.kindShell": "\u547D\u4EE4",
359
+ "aiCore.kindSkill": "\u6280\u80FD",
360
+ "aiCore.kindSubagent": "\u5B50\u4EE3\u7406",
361
+ "aiCore.kindTodo": "\u5F85\u529E",
362
+ "aiCore.kindWrite": "\u5199\u5165",
363
+ "aiCore.statusApproval": "\u5F85\u786E\u8BA4",
364
+ "aiCore.statusCancelled": "\u5DF2\u53D6\u6D88",
365
+ "aiCore.statusDone": "\u5B8C\u6210",
366
+ "aiCore.statusError": "\u5931\u8D25",
367
+ "aiCore.statusPending": "\u7B49\u5F85",
368
+ "aiCore.statusRunning": "\u6267\u884C\u4E2D",
369
+ "aiCore.statusStreaming": "\u6D41\u5F0F\u4E2D",
370
+ "aiCore.todoProgress": "{p0}/{p1} \u5B8C\u6210",
371
+ /* ── aiDiff ── */
372
+ "aiDiff.accepted": "\u5DF2\u63A5\u53D7",
373
+ "aiDiff.binary": "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u663E\u793A\u6587\u672C\u5DEE\u5F02",
374
+ "aiDiff.empty": "\u65E0\u5DEE\u5F02\u5185\u5BB9",
375
+ "aiDiff.rejected": "\u5DF2\u62D2\u7EDD",
376
+ /* ── aiFeedback ── */
377
+ "aiFeedback.helpful": "\u6709\u5E2E\u52A9",
378
+ "aiFeedback.notHelpful": "\u65E0\u5E2E\u52A9",
379
+ "aiFeedback.reasonCitationMismatch": "\u5F15\u7528\u4E0D\u7B26",
380
+ "aiFeedback.reasonOutdated": "\u5185\u5BB9\u8FC7\u65F6",
381
+ "aiFeedback.reasonUnauthorized": "\u8D8A\u6743\u4FE1\u606F",
382
+ "aiFeedback.reasonUnsourced": "\u65E0\u5F15\u7528\u4F9D\u636E",
383
+ "aiFeedback.reasonWrong": "\u7B54\u6848\u6709\u8BEF",
384
+ "aiFeedback.thanks": "\u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u5173\u8054\u5230\u8BE5\u6761\u56DE\u7B54\u7684\u8FFD\u8E2A\u8BB0\u5F55",
385
+ /* ── aiPanel ── */
386
+ "aiPanel.audit": "\u5BA1\u8BA1",
387
+ "aiPanel.cacheRead": "\u7F13\u5B58\u8BFB",
388
+ "aiPanel.cacheWrite": "\u7F13\u5B58\u5199",
389
+ "aiPanel.callsTokens": "{p0} \u6B21 \xB7 {p1} tok{p2}",
390
+ "aiPanel.clearAudit": "\u6E05\u9664\u5BA1\u8BA1",
391
+ "aiPanel.context": "\u4E0A\u4E0B\u6587",
392
+ "aiPanel.contextWindow": "\u4E0A\u4E0B\u6587\u7A97\u53E3",
393
+ "aiPanel.errorsCount": "{p0} \u5931\u8D25",
394
+ "aiPanel.files": "\u6587\u4EF6 ({p0})",
395
+ "aiPanel.itemStatus": "{p0}\uFF0C\u72B6\u6001\uFF1A{p1}",
396
+ "aiPanel.noAudit": "\u6682\u65E0\u5BA1\u8BA1\u8BB0\u5F55",
397
+ "aiPanel.noUsage": "\u6682\u65E0\u7528\u91CF",
398
+ "aiPanel.reasoning": "\u63A8\u7406",
399
+ "aiPanel.requestsCount": "{p0} \u6B21\u8BF7\u6C42",
400
+ "aiPanel.ringPercent": "\u4E0A\u4E0B\u6587\u7A97\u53E3\u5360\u7528 {p0}%\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
401
+ "aiPanel.ringUsed": "\u5DF2\u7528 {p0}\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
402
+ "aiPanel.taskProgress": "\u4EFB\u52A1\u8FDB\u5EA6",
403
+ "aiPanel.toolsCount": "{p0} \u5DE5\u5177",
404
+ "aiPanel.usage": "\u7528\u91CF",
405
+ "aiPanel.usageAria": "\u7528\u91CF\uFF1A{p0}",
406
+ /* ── aiProvider ── */
407
+ "aiProvider.audioUrlOnly": "\u4EC5 URL \u7684\u97F3\u9891\uFF08input_audio \u9700 base64\uFF0C\u8BF7\u5148\u53D6\u56DE\u5185\u8054\uFF09",
408
+ "aiProvider.audioUrlOnlyAnthropic": "\u4EC5 URL \u7684\u97F3\u9891\uFF08audio \u5757\u9700 base64 source\uFF09",
409
+ "aiProvider.base64File": "base64 \u6587\u4EF6\uFF08file \u90E8\u4EF6\u9700 Files API file_id\uFF0C\u8BF7\u7F6E\u4E8E url \u69FD\uFF09",
410
+ "aiProvider.corsHint": "\uFF1B\u6D4F\u89C8\u5668\u76F4\u8FDE {p0}\uFF08{p1}\uFF09\u5F88\u53EF\u80FD\u88AB CORS \u62E6\u622A\uFF0C\u5EFA\u8BAE\u7ECF\u4EE3\u7406/\u81EA\u5EFA\u7F51\u5173\u8F6C\u53D1",
411
+ "aiProvider.emptyResponse": "\u54CD\u5E94\u4E3A\u7A7A",
412
+ "aiProvider.glmLabel": "GLM\uFF08\u667A\u8C31\uFF09",
413
+ "aiProvider.invalidJson": "\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5 JSON",
414
+ "aiProvider.kimiLabel": "Kimi\uFF08\u6708\u4E4B\u6697\u9762\uFF09",
415
+ "aiProvider.networkFailed": "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A{p0}{p1}",
416
+ "aiProvider.nonPdfDocument": "\u975E PDF \u6587\u4EF6\u5757\uFF08document \u5757\u4E3A application/pdf\uFF0C\u6536\u5230 {p0}\uFF09",
417
+ "aiProvider.requestCancelled": "\u8BF7\u6C42\u5DF2\u53D6\u6D88",
418
+ "aiProvider.resourceRef": "[\u8D44\u6E90] {p0} ({p1})",
419
+ "aiProvider.streamError": "\u6D41\u5F0F\u54CD\u5E94\u9519\u8BEF",
420
+ "aiProvider.toolRoleNoCallId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08openai \u65CF\u9700 tool_call_id\uFF09",
421
+ "aiProvider.toolRoleNoUseId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08anthropic \u65CF\u6620\u5C04 tool_result \u9700 tool_use_id\uFF09",
422
+ "aiProvider.unsupported": "{p0} \u7EBF\u534F\u8BAE\u4E0D\u652F\u6301 {p1}",
423
+ "aiProvider.videoUnsupported": "video \u8F93\u5165\uFF08\u65E0\u4E3B\u6D41 chat API \u652F\u6301\uFF09",
424
+ "aiProvider.videoUnsupportedAnthropic": "video \u8F93\u5165",
425
+ /* ── aiThreads ── */
426
+ "aiThreads.actionsAria": "\u4F1A\u8BDD\u64CD\u4F5C",
427
+ "aiThreads.archived": "\u5DF2\u5F52\u6863",
428
+ /* ── aiTool ── */
429
+ "aiTool.allow": "\u5141\u8BB8",
430
+ "aiTool.reject": "\u62D2\u7EDD",
431
+ /* ── aiTools ── */
432
+ "aiTools.chart.area": "line \u591A\u7CFB\u5217\u586B\u5145\u9762\u79EF",
433
+ "aiTools.chart.data": "\u4EFB\u610F\u7EF4\u5EA6\u539F\u59CB\u8BB0\u5F55 + dims \u5B57\u6BB5\u6620\u5C04\uFF08\u81EA\u52A8\u900F\u89C6\u6210 \u7C7B\u76EE \xD7 \u7CFB\u5217\uFF09",
434
+ "aiTools.chart.dates": "\u8D21\u732E\u65E5\u5386 ISO \u65E5\u671F\uFF08\u4E0E values \u914D\u5BF9\uFF09",
435
+ "aiTools.chart.description": "\u5728\u7528\u6237\u754C\u9762\u6E32\u67D3\u4E00\u5F20\u56FE\u8868\u53EF\u89C6\u5316\u3002\u8F93\u5165\u4E00\u4EFD\u56FE\u8868\u89C4\u683C\uFF08\u7EAF JSON\uFF09\uFF1Alabels+values\uFF08\u7C7B\u76EE\u6570\u503C\uFF09\u3001series\uFF08\u591A\u7CFB\u5217\uFF09\u3001segments\uFF08\u5360\u6BD4\uFF09\u3001points\uFF08\u6563\u70B9\u6C14\u6CE1\uFF09\u3001dates\uFF08\u8D21\u732E\u65E5\u5386\uFF09\u4EFB\u7ED9\u5176\u4E00\uFF1Btype \u7F3A\u7701\u65F6\u6309\u6570\u636E\u5F62\u6001\u81EA\u52A8\u9009\u578B\uFF08\u65F6\u95F4\u5E8F\u5217\u2192\u6298\u7EBF\u3001\u5360\u6BD4\u2192\u73AF\u5F62\u3001\u65E5\u671F\u2192\u8D21\u732E\u65E5\u5386\u3001\u5750\u6807\u70B9\u2192\u6563\u70B9\uFF09\u3002\u56FE\u8868\u5E26\u4EA4\u4E92\uFF08\u60AC\u505C\u63D0\u793A/\u70B9\u51FB/\u53F3\u952E\uFF09\u4E0E\u53EF\u9690\u85CF\u56FE\u4F8B\u3002",
436
+ "aiTools.chart.dims": "data[] \u7684\u5B57\u6BB5\u6620\u5C04\uFF1A{label?, series?, value?, x?, y?}",
437
+ "aiTools.chart.format": "\u6570\u503C\u683C\u5F0F\u5316\uFF1A{notation?: compact|percent|ms, unit?}",
438
+ "aiTools.chart.labels": "\u7C7B\u76EE\u8F74\uFF08line/vbar/hbar\uFF09",
439
+ "aiTools.chart.legend": "false = \u521D\u59CB\u9690\u85CF\u56FE\u4F8B",
440
+ "aiTools.chart.lttb": "\u5927\u6570\u636E\u91CF\u964D\u91C7\u6837\uFF1Atrue=\u81EA\u52A8\u4E0A\u9650\uFF0C\u6570\u5B57=\u6700\u5927\u4FDD\u7559\u70B9\u6570\uFF08\u6E32\u67D3\u5C42\u5951\u7EA6\uFF0C\u968F\u56FE\u8868\u91CD\u5EA6\u573A\u666F\u843D\u5730\uFF09",
441
+ "aiTools.chart.marks": "\u6807\u8BB0\u5C42\uFF08\u9608\u503C\u7EBF/\u53C2\u8003\u533A\u95F4/\u5F3A\u8C03\u70B9\uFF09\uFF0C\u5143\u7D20\u4E3A\u7EAF JSON \u63CF\u8FF0\u5B50\uFF08\u6E32\u67D3\u5C42\u5951\u7EA6\uFF0C\u968F\u56FE\u8868\u91CD\u5EA6\u573A\u666F\u843D\u5730\uFF09",
442
+ "aiTools.chart.points": "\u6563\u70B9/\u6C14\u6CE1\uFF1A[{x,y,size?,label?}]",
443
+ "aiTools.chart.radarAxes": "\u96F7\u8FBE\u8F74\u540D",
444
+ "aiTools.chart.segments": "\u5360\u6BD4\u578B\uFF08donut/stack\uFF09\uFF1A[{label,value}]",
445
+ "aiTools.chart.series": "\u591A\u7CFB\u5217\uFF08line/vbar/radar\uFF09",
446
+ "aiTools.chart.stacked": "vbar \u591A\u7CFB\u5217\u5806\u53E0\uFF08\u9ED8\u8BA4\u5206\u7EC4\uFF09",
447
+ "aiTools.chart.title": "\u56FE\u8868\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5934\u90E8\u884C\u5DE6\u4FA7\uFF09",
448
+ "aiTools.chart.tooltip": "false = \u5173\u95ED\u5185\u7F6E\u63D0\u793A",
449
+ "aiTools.chart.type": "\u56FE\u8868\u7C7B\u578B\uFF0C\u7F3A\u7701\u81EA\u52A8\u63A8\u65AD",
450
+ "aiTools.chart.values": "\u5355\u7CFB\u5217\u6570\u503C\uFF08\u4E0E labels \u914D\u5BF9\uFF09",
451
+ "aiTools.chart.zoom": "\u7F29\u653E\u4EA4\u4E92\uFF1A'x'=\u7C7B\u76EE\u8F74\u533A\u95F4\u7F29\u653E\uFF0C'brush'=\u5237\u9009\u7F29\u653E",
452
+ "aiTools.datatable.columns": "\u5217\u5B9A\u4E49\u6570\u7EC4\uFF1A\u6BCF\u9879 { key, title, sortable?, filterable? }\uFF08key \u5BF9\u5E94 rows \u5143\u7D20\u5B57\u6BB5\u540D\uFF09",
453
+ "aiTools.datatable.description": "\u5728\u7528\u6237\u754C\u9762\u6E32\u67D3\u4E00\u4E2A\u53EF\u641C\u7D22\u3001\u5206\u9875\u3001\u53EF\u5BFC\u51FA CSV \u7684\u6570\u636E\u8868\u683C\u3002\u8F93\u5165\u7EAF JSON\uFF1Acolumns \u4E3A\u5217\u5B9A\u4E49\uFF08key/title \u5FC5\u586B\uFF09\uFF0Crows \u4E3A\u884C\u5BF9\u8C61\u6570\u7EC4\uFF08\u5B57\u6BB5\u540D\u5BF9\u9F50\u5217 key\uFF09\u3002\u8FD4\u56DE { title, rows: \u884C\u6570 } \u6458\u8981\u3002",
454
+ "aiTools.datatable.rows": "\u884C\u6570\u636E\u6570\u7EC4\uFF1A\u6BCF\u9879\u4E3A\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u5B57\u6BB5\u540D\u5BF9\u9F50 columns[].key",
455
+ "aiTools.datatable.title": "\u8868\u683C\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5DE5\u5177\u680F\u5DE6\u4FA7\uFF09",
456
+ "aiTools.execFailed": "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A{p0}",
457
+ "aiTools.execTimeout": "\u6267\u884C\u8D85\u65F6\uFF08{p0}ms\uFF09",
458
+ "aiTools.manifestHeader": "\u53EF\u7528 UI \u5DE5\u5177\uFF08\u8C03\u7528\u540E\u5728\u7528\u6237\u754C\u9762\u6302\u8F7D\u53EF\u89C6\u5316\u7ED3\u679C\uFF09\uFF1A",
459
+ "aiTools.missingRequired": "\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5",
460
+ "aiTools.none": "\uFF08\u65E0\u5DF2\u6CE8\u518C\u7684 UI \u5DE5\u5177\uFF09",
461
+ "aiTools.notInEnum": "\u4E0D\u5728\u5141\u8BB8\u53D6\u503C\u5185\uFF08{p0}\uFF09",
462
+ "aiTools.numMax": "\u6570\u503C {p0} \u5927\u4E8E\u6700\u5927\u503C {p1}",
463
+ "aiTools.numMin": "\u6570\u503C {p0} \u5C0F\u4E8E\u6700\u5C0F\u503C {p1}",
464
+ "aiTools.removeMount": "\u79FB\u9664 {p0} \u6302\u8F7D",
465
+ "aiTools.strMax": "\u957F\u5EA6 {p0} \u8D85\u8FC7\u4E0A\u9650 {p1}",
466
+ "aiTools.strMin": "\u957F\u5EA6 {p0} \u5C0F\u4E8E\u4E0B\u9650 {p1}",
467
+ "aiTools.typeMismatch": "\u671F\u671B {p0}\uFF0C\u5B9E\u5F97 {p1}",
468
+ "aiTools.validationFailed": "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF08{p0} \u9879\uFF09",
469
+ /* ── autocomplete ── */
470
+ "suggestions.loading": "\u6B63\u5728\u67E5\u627E\u5EFA\u8BAE\u2026",
471
+ "suggestions.error": "\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\u5EFA\u8BAE\uFF0C\u8BF7\u91CD\u8BD5\u3002",
472
+ "suggestions.options": "\u5EFA\u8BAE",
473
+ "suggestions.empty": "\u6CA1\u6709\u5339\u914D\u7684\u5EFA\u8BAE",
474
+ "autocomplete.empty": "\u65E0\u5339\u914D\u7ED3\u679C",
475
+ /* ── backTop ── */
476
+ "backTop.label": "\u56DE\u5230\u9876\u90E8",
477
+ /* ── carousel ── */
478
+ "carousel.item": "\u7B2C {p0} \u5F20",
479
+ "carousel.region": "\u8F6E\u64AD",
480
+ "carousel.slide": "\u5E7B\u706F\u7247",
481
+ "carousel.status": "\u7B2C {p0} / {p1} \u5F20",
482
+ /* ── charts ── */
483
+ "charts.calendarWeekdays": ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"],
484
+ "charts.few": "\u5C11",
485
+ "charts.hideLegend": "\u9690\u85CF\u56FE\u4F8B",
486
+ "charts.loading": "\u52A0\u8F7D\u4E2D",
487
+ "charts.many": "\u591A",
488
+ "charts.monthLabel": "{p0}\u6708",
489
+ "charts.noData": "\u6682\u65E0\u6570\u636E",
490
+ "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
491
+ "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
492
+ "charts.type.area": "\u9762\u79EF\u56FE",
493
+ "charts.type.donut": "\u73AF\u5F62\u56FE",
494
+ "charts.type.gauge": "\u4EEA\u8868\u76D8",
495
+ "charts.type.graph": "\u77E5\u8BC6\u56FE\u8C31",
496
+ "charts.type.heatmap": "\u70ED\u529B\u56FE",
497
+ "charts.type.line": "\u6298\u7EBF\u56FE",
498
+ "charts.type.map": "\u5730\u56FE",
499
+ "charts.type.radar": "\u96F7\u8FBE\u56FE",
500
+ "charts.type.scatter": "\u6563\u70B9\u56FE",
501
+ "charts.type.sparkline": "\u8FF7\u4F60\u8D8B\u52BF",
502
+ "charts.seriesName": "\u7CFB\u5217{p0}",
503
+ "charts.showLegend": "\u663E\u793A\u56FE\u4F8B",
504
+ "charts.value": "\u6570\u503C",
505
+ /* ── themeSwitcher ── */
506
+ "themeSwitcher.appearance": "\u5916\u89C2",
507
+ "themeSwitcher.theme": "\u4E3B\u9898",
508
+ "themeSwitcher.primitive": "\u539F\u8BED",
509
+ "themeSwitcher.mode": "\u660E\u6697",
510
+ "themeSwitcher.light": "\u6D45\u8272",
511
+ "themeSwitcher.dark": "\u6DF1\u8272",
512
+ "themeSwitcher.modern": "\u73B0\u4EE3",
513
+ "themeSwitcher.dongyun": "\u4E1C\u97F5",
514
+ "themeSwitcher.jugou": "\u5DE8\u6784",
515
+ "themeSwitcher.piano": "\u94A2\u7434",
516
+ "themeSwitcher.monet": "\u83AB\u5948",
517
+ "themeSwitcher.vangogh": "\u68B5\u9AD8",
518
+ "themeSwitcher.chinese": "\u4E2D\u5F0F",
519
+ "themeSwitcher.soviet": "\u82CF\u5F0F",
520
+ "themeSwitcher.pixel": "\u50CF\u7D20",
521
+ /* ── codeBlock ── */
522
+ "codeBlock.collapse": "\u6536\u8D77",
523
+ "codeBlock.region": "\u4EE3\u7801\u5185\u5BB9",
524
+ "codeBlock.copyFailed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
525
+ "codeBlock.copyRetry": "\u91CD\u8BD5\u590D\u5236",
526
+ "codeBlock.copy": "\u590D\u5236",
527
+ "codeBlock.foldCollapse": "\u6298\u53E0\u4EE3\u7801",
528
+ "codeBlock.foldExpand": "\u5C55\u5F00\u4EE3\u7801",
529
+ "codeBlock.linesTotal": "\u5171 {p0} \u884C",
530
+ "codeBlock.numHide": "\u9690\u85CF\u884C\u53F7",
531
+ "codeBlock.numShow": "\u663E\u793A\u884C\u53F7",
532
+ "codeBlock.tailAria": "\u5C55\u5F00\u6216\u6536\u8D77\u4EE3\u7801",
533
+ "codeBlock.wrapOff": "\u5173\u95ED\u6362\u884C",
534
+ "codeBlock.wrapOn": "\u81EA\u52A8\u6362\u884C",
535
+ /* ── common ── */
536
+ "common.accept": "\u63A5\u53D7",
537
+ "common.add": "\u65B0\u589E",
538
+ "common.all": "\u5168\u90E8",
539
+ "common.approve": "\u6279\u51C6",
540
+ "common.cancel": "\u53D6\u6D88",
541
+ "common.actionFailed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002",
542
+ "common.close": "\u5173\u95ED",
543
+ "common.confirm": "\u786E\u8BA4",
544
+ "common.copied": "\u5DF2\u590D\u5236",
545
+ "common.copy": "\u590D\u5236",
546
+ "common.delete": "\u5220\u9664",
547
+ "common.enable": "\u542F\u7528",
548
+ "common.exportCsv": "\u5BFC\u51FA CSV",
549
+ "common.healthy": "\u6B63\u5E38",
550
+ "common.input": "\u8F93\u5165",
551
+ "common.loadingEllipsis": "\u52A0\u8F7D\u4E2D\u2026",
552
+ "common.official": "\u5B98\u65B9",
553
+ "common.output": "\u8F93\u51FA",
554
+ "common.page": "\u7B2C {p0} \u9875",
555
+ "common.reject": "\u62D2\u7EDD",
556
+ "common.remove": "\u79FB\u9664",
557
+ "common.requestAccess": "\u7533\u8BF7\u8BBF\u95EE",
558
+ "common.requestAccessFor": "\u7533\u8BF7\u8BBF\u95EE {p0}",
559
+ "common.restricted": "\u53D7\u9650",
560
+ "common.retry": "\u91CD\u8BD5",
561
+ "common.rows": "{p0} \u884C",
562
+ "common.run": "\u8FD0\u884C",
563
+ "common.steps": "{p0} \u6B65",
564
+ "common.submit": "\u63D0\u4EA4",
565
+ "common.unknown": "\u672A\u77E5",
566
+ /* ── contextMenu ── */
567
+ "contextMenu.back": "\u540E\u9000",
568
+ "contextMenu.copyPageLink": "\u590D\u5236\u9875\u9762\u94FE\u63A5",
569
+ "contextMenu.forward": "\u524D\u8FDB",
570
+ "contextMenu.refresh": "\u5237\u65B0",
571
+ /* ── copy ── */
572
+ "copy.copied": "\u5DF2\u590D\u5236",
573
+ "copy.failed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
574
+ "copy.denied": "clipboard API \u88AB\u62D2\uFF08{p0}\uFF09\u4E14\u56DE\u9000 execCommand \u5931\u8D25",
575
+ "copy.unavailable": "\u526A\u8D34\u677F\u4E0D\u53EF\u7528\uFF08\u65E0 clipboard API \u4E14 execCommand \u56DE\u9000\u5931\u8D25\uFF09",
576
+ "copy.unknown": "\u672A\u77E5\u9519\u8BEF",
577
+ /* ── datatable ── */
578
+ "datatable.clear": "\u6E05\u7A7A",
579
+ "datatable.collapseGroup": "\u6298\u53E0\u5206\u7EC4 {p0}",
580
+ "datatable.columnSettingsAria": "\u5217\u8BBE\u7F6E",
581
+ "datatable.countUnit": "{p0} \u6761",
582
+ "datatable.editHint": "\u7F16\u8F91\u300C{p0}\u300D\uFF1A\u53CC\u51FB\u6216\u6309 Enter",
583
+ "datatable.editHintWithValue": "{p0}\uFF08\u53CC\u51FB\u6216\u6309 Enter \u7F16\u8F91\u300C{p1}\u300D\uFF09",
584
+ "datatable.empty": "\u6682\u65E0\u6570\u636E",
585
+ "datatable.emptyValue": "\uFF08\u7A7A\uFF09",
586
+ "datatable.expandGroup": "\u5C55\u5F00\u5206\u7EC4 {p0}",
587
+ "datatable.expandRow": "\u5C55\u5F00\u884C",
588
+ "datatable.filterChipAria": "\u7B5B\u9009\u300C{p0}\u300D",
589
+ "datatable.pageSizeAria": "\u6BCF\u9875\u6761\u6570",
590
+ "datatable.paginationAria": "\u5206\u9875",
591
+ "datatable.reset": "\u91CD\u7F6E",
592
+ "datatable.resizeAria": "\u8C03\u6574\u300C{p0}\u300D\u5217\u5BBD",
593
+ "datatable.searchAria": "\u641C\u7D22\u8868\u683C",
594
+ "datatable.searchPlaceholder": "\u641C\u7D22\u2026",
595
+ "datatable.selectAll": "\u5168\u9009",
596
+ "datatable.selectRow": "\u9009\u62E9\u8BE5\u884C",
597
+ "datatable.selectedCount": "\u5DF2\u9009 {p0} \u9879",
598
+ "datatable.totalCount": "\u5171 {p0} \u6761",
599
+ "datatable.totalLabel": "\u5408\u8BA1",
600
+ /* ── datePicker ── */
601
+ "datePicker.noDates": "\u6CA1\u6709\u53EF\u9009\u65E5\u671F",
602
+ "datePicker.clear": "\u6E05\u9664",
603
+ "datePicker.nextMonth": "\u4E0B\u4E00\u6708",
604
+ "datePicker.prevMonth": "\u4E0A\u4E00\u6708",
605
+ "datePicker.selectDate": "\u9009\u62E9\u65E5\u671F",
606
+ "datePicker.today": "\u4ECA\u5929",
607
+ "datePicker.weekdays": ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"],
608
+ "datePicker.weekdaysSunFirst": ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"],
609
+ "datePicker.yearMonth": "{p0} \u5E74 {p1} \u6708",
610
+ /* ── formValidate ── */
611
+ "formValidate.email": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740",
612
+ "formValidate.invalid": "\u8F93\u5165\u4E0D\u5408\u6CD5",
613
+ "formValidate.matches": "\u4E24\u6B21\u8F93\u5165\u4E0D\u4E00\u81F4",
614
+ "formValidate.max": "\u4E0D\u80FD\u5927\u4E8E {max}",
615
+ "formValidate.maxlength": "\u6700\u591A\u8F93\u5165 {max} \u4E2A\u5B57\u7B26",
616
+ "formValidate.min": "\u4E0D\u80FD\u5C0F\u4E8E {min}",
617
+ "formValidate.minlength": "\u81F3\u5C11\u8F93\u5165 {min} \u4E2A\u5B57\u7B26",
618
+ "formValidate.number": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57",
619
+ "formValidate.pattern": "\u8F93\u5165\u683C\u5F0F\u4E0D\u6B63\u786E",
620
+ "formValidate.required": "\u6B64\u9879\u4E3A\u5FC5\u586B\u9879",
621
+ "formValidate.selectPlaceholder": "\u8BF7\u9009\u62E9",
622
+ "formValidate.step": "\u6570\u503C\u5FC5\u987B\u662F {step} \u7684\u500D\u6570",
623
+ "formValidate.summary": "\u8868\u5355\u6709 {p0} \u9879\u5185\u5BB9\u9700\u8981\u4FEE\u6B63\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0\u63D0\u4EA4",
624
+ "formValidate.tool.description": "\u5411\u7528\u6237\u6E32\u67D3\u4E00\u4E2A\u7ED3\u6784\u5316\u8868\u5355\u6536\u96C6\u8F93\u5165",
625
+ "formValidate.tool.fields": "\u5B57\u6BB5\u5217\u8868",
626
+ "formValidate.tool.help": "\u5B57\u6BB5\u4E0B\u65B9\u7684\u5E2E\u52A9\u6587\u6848",
627
+ "formValidate.tool.label": "\u5B57\u6BB5\u6807\u7B7E",
628
+ "formValidate.tool.max": "\u6700\u5927\u503C\uFF08number \u7528\uFF09",
629
+ "formValidate.tool.min": "\u6700\u5C0F\u503C\uFF08number \u7528\uFF09",
630
+ "formValidate.tool.name": "\u5B57\u6BB5\u540D\uFF08\u63D0\u4EA4\u503C\u7684 key\uFF09",
631
+ "formValidate.tool.options": "select \u9009\u9879\uFF08\u5B57\u7B26\u4E32\u6216 {label,value}\uFF09",
632
+ "formValidate.tool.pattern": "\u6B63\u5219\u7EA6\u675F\uFF08HTML pattern \u8BED\u6CD5\uFF0C\u6574\u4E32\u5339\u914D\uFF09",
633
+ "formValidate.tool.required": "\u662F\u5426\u5FC5\u586B",
634
+ "formValidate.tool.submitText": "\u63D0\u4EA4\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4\u300C\u63D0\u4EA4\u300D",
635
+ "formValidate.tool.title": "\u8868\u5355\u6807\u9898\uFF08\u53EF\u9009\uFF09",
636
+ "formValidate.tool.type": "\u63A7\u4EF6\u7C7B\u578B\uFF0C\u9ED8\u8BA4 text",
637
+ "formValidate.url": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u94FE\u63A5\u5730\u5740",
638
+ /* ── input ── */
639
+ "input.clearSearch": "\u6E05\u7A7A\u641C\u7D22",
640
+ "input.hidePassword": "\u9690\u85CF\u5BC6\u7801",
641
+ "input.otpPosition": "\u7B2C {p0} \u4F4D\uFF0C\u5171 {p1} \u4F4D",
642
+ "panel.expand": "\u5C55\u5F00",
643
+ "panel.collapse": "\u6298\u53E0",
644
+ "input.showPassword": "\u663E\u793A\u5BC6\u7801",
645
+ /* ── kbAccess ── */
646
+ "kbAccess.approveTip": "\u6279\u51C6\u8BE5\u8BBF\u95EE\u7533\u8BF7",
647
+ "kbAccess.approvedBadge": "\u5DF2\u6279\u51C6 \xB7 {p0}",
648
+ "kbAccess.approverNotePlaceholder": "\u7ED9\u8BF7\u6C42\u4EBA\u7684\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
649
+ "kbAccess.daysLeft": "{p0} \u5929\u540E",
650
+ "kbAccess.defaultSubject": "\u8BE5\u5185\u5BB9",
651
+ "kbAccess.deniedHint": "\u672A\u901A\u8FC7\u2014\u2014\u53EF\u8C03\u6574\u7406\u7531\u540E\u91CD\u65B0\u7533\u8BF7",
652
+ "kbAccess.denyNoteLabel": "\u62D2\u7EDD\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
653
+ "kbAccess.duration30d": "30 \u5929",
654
+ "kbAccess.duration7d": "7 \u5929",
655
+ "kbAccess.durationForever": "\u6C38\u4E45",
656
+ "kbAccess.durationLabel": "\u8BBF\u95EE\u65F6\u957F",
657
+ "kbAccess.expired": "\u5DF2\u5230\u671F",
658
+ "kbAccess.expiresAt": "{p0}\u5230\u671F",
659
+ "kbAccess.grantAsPrefix": "\u6279\u51C6\u4E3A{p0}",
660
+ "kbAccess.grantRoleLabel": "\u6279\u51C6\u89D2\u8272",
661
+ "kbAccess.hoursLeft": "{p0} \u5C0F\u65F6\u540E",
662
+ "kbAccess.minutesLeft": "{p0} \u5206\u949F\u540E",
663
+ "kbAccess.ownerLabel": "\u5185\u5BB9\u8D1F\u8D23\u4EBA",
664
+ "kbAccess.ownerPrefix": "\u8D1F\u8D23\u4EBA\uFF1A{p0}",
665
+ "kbAccess.reapply": "\u91CD\u65B0\u7533\u8BF7",
666
+ "kbAccess.reasonLabel": "\u7533\u8BF7\u7406\u7531",
667
+ "kbAccess.reasonPlaceholder": "\u8BF4\u660E\u4E1A\u52A1\u539F\u56E0\uFF08\u5BA1\u6279\u4EBA\u53EF\u89C1\uFF09",
668
+ "kbAccess.rejectTip": "\u62D2\u7EDD\u8BE5\u8BBF\u95EE\u7533\u8BF7",
669
+ "kbAccess.requestRenewal": "\u7533\u8BF7\u7EED\u671F",
670
+ "kbAccess.requestToPrefix": "\u8BF7\u6C42\u5C06\u53D1\u9001\u7ED9\uFF1A{p0}",
671
+ "kbAccess.restrictedContent": "\u53D7\u9650\u5185\u5BB9",
672
+ "kbAccess.restrictedHint": "\u6B64\u5185\u5BB9\u4EC5\u5BF9\u6388\u6743\u8005\u5F00\u653E",
673
+ "kbAccess.revokedHint": "\u8BBF\u95EE\u5DF2\u88AB\u6536\u56DE",
674
+ "kbAccess.roleLabel": "\u7533\u8BF7\u89D2\u8272",
675
+ "kbAccess.submitRequest": "\u63D0\u4EA4\u7533\u8BF7",
676
+ "kbAccess.switchIdentity": "\u5207\u6362\u8EAB\u4EFD",
677
+ "kbAccess.switchIdentityTip": "\u5207\u6362\u8EAB\u4EFD\u540E\u91CD\u65B0\u68C0\u67E5\u6743\u9650",
678
+ "kbAccess.unknownRequester": "\u672A\u77E5\u8BF7\u6C42\u4EBA",
679
+ "kbAccess.waitingApproval": "\u7B49\u5F85 {p0} \u5BA1\u6279",
680
+ /* ── kbAcl ── */
681
+ "kbAcl.breakHint": "\u505C\u6B62\u4ECE\u7236\u7EA7\u7EE7\u627F\uFF0C\u6539\u4E3A\u72EC\u7ACB\u7BA1\u7406\u672C\u9879\u6743\u9650",
682
+ "kbAcl.breakInheritance": "\u505C\u6B62\u7EE7\u627F",
683
+ "kbAcl.brokenNotice": "\u5DF2\u505C\u6B62\u7EE7\u627F\u2014\u2014\u672C\u9879\u6743\u9650\u72EC\u7ACB\u4E8E\u7236\u7EA7",
684
+ "kbAcl.detachedChildren": "{p0}\uFF1A{p1} \u4E2A\u5B50\u9879\u5DF2\u8131\u79BB",
685
+ "kbAcl.directAccess": "\u76F4\u63A5\u8BBF\u95EE",
686
+ "kbAcl.exception": "\u4F8B\u5916",
687
+ "kbAcl.expiredOn": "\u5DF2\u8FC7\u671F\uFF08{p0}\uFF09",
688
+ "kbAcl.expiresIn": "{p0} \u5230\u671F",
689
+ "kbAcl.grantAccess": "\u6388\u4E88\u8BBF\u95EE",
690
+ "kbAcl.inheritedFrom": "\u7EE7\u627F\u81EA {p0}",
691
+ "kbAcl.inheritedFromLabel": "\u7EE7\u627F\u81EA",
692
+ "kbAcl.linkAccess": "\u94FE\u63A5\u8BBF\u95EE",
693
+ "kbAcl.noDirect": "\u6682\u65E0\u76F4\u63A5\u6388\u6743",
694
+ "kbAcl.noLinks": "\u65E0\u94FE\u63A5",
695
+ "kbAcl.removeEntry": "\u79FB\u9664 {p0}",
696
+ "kbAcl.restoreHint": "\u6062\u590D\u7EE7\u627F\u5C06\u4E22\u5F03\u672C\u9879\u81EA\u5B9A\u4E49\u7684\u6743\u9650",
697
+ "kbAcl.restoreInheritance": "\u6062\u590D\u7EE7\u627F",
698
+ "kbAcl.rootNotice": "\u6839\u7EA7\u8D44\u6E90\u2014\u2014\u65E0\u7236\u7EA7\u7EE7\u627F",
699
+ "kbAcl.systemBadge": "\u7CFB\u7EDF\u7BA1\u7406",
700
+ "kbAcl.systemNote": "\u7CFB\u7EDF\u81EA\u52A8\uFF0C\u4E0D\u53EF\u624B\u5DE5\u79FB\u9664",
701
+ "kbAcl.unnamedResource": "\u672A\u547D\u540D\u8D44\u6E90",
702
+ "kbAcl.visibleToCount": "\u5BF9 {p0} \u4EBA\u53EF\u89C1",
703
+ /* ── kbAnswer ── */
704
+ "kbAnswer.chartBar": "\u67F1\u72B6",
705
+ "kbAnswer.chartLine": "\u6298\u7EBF",
706
+ "kbAnswer.chartPie": "\u997C\u56FE",
707
+ "kbAnswer.exportNoun": "\u5BFC\u51FA {p0}",
708
+ "kbAnswer.filtered": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4",
709
+ "kbAnswer.filteredDetail": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4\uFF1A{p0}",
710
+ "kbAnswer.followups": "\u8FFD\u95EE\u5EFA\u8BAE",
711
+ "kbAnswer.hitAssets": "\u547D\u4E2D\u8D44\u4EA7\uFF1A{p0}",
712
+ "kbAnswer.kindCurated": "\u4EBA\u5DE5\u7B56\u5C55",
713
+ "kbAnswer.kindFunction": "\u51FD\u6570",
714
+ "kbAnswer.kindParameterized": "\u53C2\u6570\u5316\u67E5\u8BE2",
715
+ "kbAnswer.maskedPrefix": "\u5DF2\u8131\u654F\u5217\uFF1A",
716
+ "kbAnswer.rerunTip": "\u53C2\u6570\u53EF\u6539\u91CD\u8DD1",
717
+ "kbAnswer.truncated": "\u5DF2\u622A\u65AD\uFF1A\u663E\u793A {p0}/{p1} \u884C{p2}",
718
+ "kbAnswer.verifiedBadge": "\u8BA4\u8BC1\u7B54\u6848",
719
+ /* ── kbAudit ── */
720
+ "kbAudit.actionDetail": "\u5904\u7F6E\uFF1A{p0} \xB7 {p1}",
721
+ "kbAudit.actionLabel": "\u5904\u7F6E",
722
+ "kbAudit.alertedNote": "\u5DF2\u5B9E\u65F6\u544A\u8B66\u5B89\u5168\u56E2\u961F",
723
+ "kbAudit.channelFilterAria": "\u5BA1\u8BA1\u901A\u9053\u8FC7\u6EE4",
724
+ "kbAudit.channelPermission": "\u6743\u9650\u53D8\u66F4",
725
+ "kbAudit.channelRead": "\u8BFB\u53D6",
726
+ "kbAudit.channelRequest": "\u7533\u8BF7",
727
+ "kbAudit.channelSystem": "\u7CFB\u7EDF",
728
+ "kbAudit.empty": "\u6682\u65E0\u5BA1\u8BA1\u4E8B\u4EF6",
729
+ "kbAudit.exportTip": "\u5BFC\u51FA\u5F53\u524D\u8FC7\u6EE4\u89C6\u56FE\u4E3A CSV",
730
+ "kbAudit.hygieneLabel": "\u6743\u9650\u5F02\u5473",
731
+ "kbAudit.noHygiene": "\u672A\u53D1\u73B0\u6743\u9650\u5F02\u5473",
732
+ /* ── kbCanvas ── */
733
+ "kbCanvas.splitterAria": "\u8C03\u6574\u753B\u5E03\u53CC\u680F\u6BD4\u4F8B",
734
+ "kbCanvas.splitterTip": "\u62D6\u62FD\u8C03\u6574\u6BD4\u4F8B\uFF08\u2190/\u2192 \u5FAE\u8C03\uFF0C\u53CC\u51FB\u590D\u4F4D\uFF09",
735
+ /* ── kbCheckpoint ── */
736
+ "kbCheckpoint.chatAuditNote": "\u8BA8\u8BBA\u5386\u53F2\u6709\u5BA1\u8BA1\u4EF7\u503C",
737
+ "kbCheckpoint.label": "\u68C0\u67E5\u70B9",
738
+ "kbCheckpoint.restore": "\u6062\u590D\u68C0\u67E5\u70B9",
739
+ "kbCheckpoint.scopeBoth": "\u5185\u5BB9\u4E0E\u5BF9\u8BDD",
740
+ "kbCheckpoint.scopeChat": "\u4EC5\u5BF9\u8BDD",
741
+ "kbCheckpoint.scopeContent": "\u4EC5\u5185\u5BB9\uFF08\u4FDD\u7559\u5BF9\u8BDD\uFF09",
742
+ "kbCheckpoint.scopeMissing": "\u8BE5\u68C0\u67E5\u70B9\u672A\u5305\u542B\u6B64\u6062\u590D\u8303\u56F4",
743
+ /* ── kbChunks ── */
744
+ "kbChunks.addKeyword": "+ \u5173\u952E\u8BCD",
745
+ "kbChunks.chunkAddKeywordAria": "chunk {p0} \u65B0\u589E\u5173\u952E\u8BCD",
746
+ "kbChunks.chunkContentAria": "chunk {p0} \u5185\u5BB9",
747
+ "kbChunks.chunkEnableAria": "chunk {p0} \u542F\u7528",
748
+ "kbChunks.deleteChunkAria": "\u5220\u9664 chunk {p0}",
749
+ "kbChunks.disableNote": "\u5173\u95ED\u540E\u4E0D\u5220\u9664\uFF0C\u4EC5\u6392\u9664\u51FA\u68C0\u7D22",
750
+ "kbChunks.edited": "\u5DF2\u7F16\u8F91",
751
+ "kbChunks.empty": "\u6682\u65E0 chunk",
752
+ "kbChunks.modeFull": "\u5168\u6587",
753
+ "kbChunks.modeLabel": "\u641C\u7D22\u6A21\u5F0F",
754
+ "kbChunks.modeVector": "\u8BED\u4E49",
755
+ "kbChunks.removeKeyword": "\u79FB\u9664\u5173\u952E\u8BCD {p0}",
756
+ "kbChunks.searchAria": "\u641C\u7D22 chunk",
757
+ "kbChunks.searchFullPlaceholder": "\u5168\u6587\u641C\u7D22 chunk\u2026",
758
+ "kbChunks.searchVectorPlaceholder": "\u8BED\u4E49\u641C\u7D22 chunk\u2026",
759
+ /* ── kbCitation ── */
760
+ "kbCitation.sourceN": "\u6765\u6E90 {p0}",
761
+ "kbCitation.unavailable": "\u6765\u6E90\u5DF2\u4E0D\u53EF\u7528",
762
+ /* ── kbClarify ── */
763
+ "kbClarify.parsedPrefix": "\u5DF2\u89E3\u6790\uFF1A",
764
+ /* ── kbConflict ── */
765
+ "kbConflict.owner": "\u8D23\u4EFB\u4EBA {p0}",
766
+ /* ── kbConnector ── */
767
+ "kbConnector.changeRate": "\u53D8\u66F4\u7387",
768
+ "kbConnector.crawlRate": "\u6293\u53D6\u7387",
769
+ "kbConnector.credentials": "\u51ED\u8BC1",
770
+ "kbConnector.credentialsExpired": "\u51ED\u8BC1\u8FC7\u671F",
771
+ "kbConnector.editSchedule": "\u7F16\u8F91\u8BA1\u5212",
772
+ "kbConnector.empty": "\u6682\u65E0\u8FDE\u63A5\u5668",
773
+ "kbConnector.failing": "\u5F02\u5E38",
774
+ "kbConnector.lastSync": "\u6700\u8FD1\u540C\u6B65 {p0}",
775
+ "kbConnector.neverSynced": "\u4ECE\u672A\u540C\u6B65",
776
+ "kbConnector.notConfigured": "\u672A\u914D\u7F6E",
777
+ "kbConnector.off": "\u5DF2\u505C\u7528",
778
+ "kbConnector.perDay": "{p0}/\u5929",
779
+ "kbConnector.reauth": "\u91CD\u65B0\u6388\u6743",
780
+ "kbConnector.stale": "\u505C\u6EDE",
781
+ "kbConnector.syncNow": "\u7ACB\u5373\u540C\u6B65",
782
+ "kbConnector.synced": "\u5DF2\u540C\u6B65",
783
+ /* ── kbCore ── */
784
+ "kbCore.accessDenied": "\u672A\u901A\u8FC7",
785
+ "kbCore.accessExpired": "\u5DF2\u8FC7\u671F",
786
+ "kbCore.accessExpiring": "\u5373\u5C06\u5230\u671F",
787
+ "kbCore.accessGranted": "\u5DF2\u5F00\u901A",
788
+ "kbCore.accessNotRequested": "\u672A\u7533\u8BF7",
789
+ "kbCore.accessPending": "\u5F85\u5BA1\u6279",
790
+ "kbCore.accessRequested": "\u5DF2\u63D0\u4EA4",
791
+ "kbCore.accessRevoked": "\u5DF2\u6536\u56DE",
792
+ "kbCore.auditApprove": "\u6279\u51C6",
793
+ "kbCore.auditBreakGlass": "\u5E94\u6025\u8BBF\u95EE",
794
+ "kbCore.auditDelegation": "\u59D4\u6D3E",
795
+ "kbCore.auditDeny": "\u62D2\u7EDD",
796
+ "kbCore.auditGrant": "\u6388\u4E88",
797
+ "kbCore.auditPermissionChange": "\u6743\u9650\u53D8\u66F4",
798
+ "kbCore.auditPreview": "\u9884\u89C8",
799
+ "kbCore.auditRead": "\u8BFB\u53D6",
800
+ "kbCore.auditRequest": "\u7533\u8BF7",
801
+ "kbCore.auditRevoke": "\u6536\u56DE",
802
+ "kbCore.auditSync": "\u6743\u9650\u540C\u6B65",
803
+ "kbCore.daysAgo": "{p0} \u5929\u524D",
804
+ "kbCore.hoursAgo": "{p0} \u5C0F\u65F6\u524D",
805
+ "kbCore.hygieneBroadGroup": "\u8FC7\u5BBD\u7EC4\u6388\u6743",
806
+ "kbCore.hygieneBrokenInheritance": "\u65AD\u7EE7\u627F",
807
+ "kbCore.hygieneOrgWideLink": "\u7EC4\u7EC7\u7EA7\u94FE\u63A5",
808
+ "kbCore.hygieneOrphanedOwner": "\u8D1F\u8D23\u4EBA\u7F3A\u4F4D",
809
+ "kbCore.hygieneOverexposed": "\u8FC7\u5EA6\u66B4\u9732",
810
+ "kbCore.hygieneSensitiveMismatch": "\u654F\u611F\u5EA6\u9519\u914D",
811
+ "kbCore.justNow": "\u521A\u521A",
812
+ "kbCore.levelComment": "\u53EF\u8BC4\u8BBA",
813
+ "kbCore.levelEdit": "\u53EF\u7F16\u8F91",
814
+ "kbCore.levelNone": "\u65E0\u6743\u9650",
815
+ "kbCore.levelOwner": "\u8D1F\u8D23\u4EBA",
816
+ "kbCore.levelView": "\u53EF\u67E5\u770B",
817
+ "kbCore.minutesAgo": "{p0} \u5206\u949F\u524D",
818
+ "kbCore.runCancelled": "\u5DF2\u53D6\u6D88",
819
+ "kbCore.runDone": "\u5DF2\u5B8C\u6210",
820
+ "kbCore.runFailed": "\u5931\u8D25",
821
+ "kbCore.runQueued": "\u6392\u961F\u4E2D",
822
+ "kbCore.runRunning": "\u8FDB\u884C\u4E2D",
823
+ "kbCore.runUnstarted": "\u672A\u5F00\u59CB",
824
+ "kbCore.stageAgent": "\u4EE3\u7406",
825
+ "kbCore.stageChunk": "\u5207\u7247",
826
+ "kbCore.stageEmbed": "\u5411\u91CF\u5316",
827
+ "kbCore.stageGeneration": "\u751F\u6210",
828
+ "kbCore.stageGuard": "\u62A4\u680F",
829
+ "kbCore.stageQuery": "\u67E5\u8BE2",
830
+ "kbCore.stageRerank": "\u91CD\u6392",
831
+ "kbCore.stageRetrieval": "\u68C0\u7D22",
832
+ "kbCore.stageTool": "\u5DE5\u5177",
833
+ "kbCore.typeApi": "\u63A5\u53E3",
834
+ "kbCore.typeCode": "\u4EE3\u7801",
835
+ "kbCore.typeDatabase": "\u6570\u636E\u5E93",
836
+ "kbCore.typeDocument": "\u6587\u6863",
837
+ "kbCore.typeEmail": "\u90AE\u4EF6",
838
+ "kbCore.typeImage": "\u56FE\u7247",
839
+ "kbCore.typeKb": "\u77E5\u8BC6\u5E93",
840
+ "kbCore.typeTable": "\u8868\u683C",
841
+ "kbCore.typeTicket": "\u5DE5\u5355",
842
+ "kbCore.typeWebpage": "\u7F51\u9875",
843
+ "kbCore.unnamedSource": "\u672A\u547D\u540D\u6765\u6E90",
844
+ "kbCore.unnamedSubject": "\u672A\u547D\u540D\u4E3B\u4F53",
845
+ "kbCore.visHidden": "\u4E0D\u53EF\u89C1",
846
+ "kbCore.visMetadataOnly": "\u4EC5\u5143\u6570\u636E",
847
+ "kbCore.visSummaryOnly": "\u4EC5\u6458\u8981",
848
+ "kbCore.visVisible": "\u53EF\u89C1",
849
+ /* ── kbEval ── */
850
+ "kbEval.avgA": "A \u5747\u5206 {p0}",
851
+ "kbEval.avgB": "B \u5747\u5206 {p0}",
852
+ "kbEval.compare": "\u5BF9\u6BD4",
853
+ "kbEval.runSelectAria": "\u9009\u62E9\u5BF9\u6BD4\u8FD0\u884C",
854
+ "kbEval.expected": "\u671F\u671B",
855
+ "kbEval.gradeImprovement": "\u63D0\u5347",
856
+ "kbEval.gradeRegression": "\u56DE\u5F52",
857
+ "kbEval.gradeTie": "\u6301\u5E73",
858
+ "kbEval.gradeTradeoff": "\u6743\u8861",
859
+ "kbEval.noData": "\u6CA1\u6709\u5BF9\u6BD4\u6570\u636E",
860
+ "kbEval.onlyRegression": "\u4EC5\u770B\u56DE\u5F52",
861
+ "kbEval.outputA": "\u8F93\u51FA A",
862
+ "kbEval.outputB": "\u8F93\u51FA B",
863
+ "kbEval.outputN": "\u8F93\u51FA {p0}",
864
+ /* ── kbExplain ── */
865
+ "kbExplain.empty": "\u6682\u65E0\u53E3\u5F84\u4FE1\u606F",
866
+ "kbExplain.groupAgg": "\u805A\u5408",
867
+ "kbExplain.groupColumn": "\u5217",
868
+ "kbExplain.groupFilter": "\u7B5B\u9009",
869
+ "kbExplain.groupTable": "\u8868",
870
+ "kbExplain.trigger": "\u8FD9\u4E2A\u6570\u5B57\u662F\u600E\u4E48\u7B97\u51FA\u6765\u7684",
871
+ "kbExplain.viewDefinition": "\u67E5\u770B\u53E3\u5F84",
872
+ /* ── kbFilter ── */
873
+ "kbFilter.addGroup": "+ \u7EC4",
874
+ "kbFilter.addRule": "+ \u89C4\u5219",
875
+ "kbFilter.and": "\u4E14",
876
+ "kbFilter.combineMode": "\u7EC4\u5408\u65B9\u5F0F {p0}",
877
+ "kbFilter.copyDsl": "\u590D\u5236 DSL",
878
+ "kbFilter.deleteGroup": "\u5220\u9664\u7EC4",
879
+ "kbFilter.deleteRule": "\u5220\u9664\u89C4\u5219",
880
+ "kbFilter.fieldLabel": "\u5B57\u6BB5",
881
+ "kbFilter.fieldPlaceholder": "\u8FC7\u6EE4\u5B57\u6BB5",
882
+ "kbFilter.noValueNeeded": "\uFF08\u65E0\u9700\u503C\uFF09",
883
+ "kbFilter.none": "\uFF08\u65E0\u8FC7\u6EE4\uFF09",
884
+ "kbFilter.opContains": "\u5305\u542B",
885
+ "kbFilter.opEq": "\u7B49\u4E8E",
886
+ "kbFilter.opExists": "\u5B58\u5728",
887
+ "kbFilter.opGt": "\u5927\u4E8E",
888
+ "kbFilter.opGte": "\u5927\u4E8E\u7B49\u4E8E",
889
+ "kbFilter.opIn": "\u5C5E\u4E8E",
890
+ "kbFilter.opLt": "\u5C0F\u4E8E",
891
+ "kbFilter.opLte": "\u5C0F\u4E8E\u7B49\u4E8E",
892
+ "kbFilter.opNe": "\u4E0D\u7B49\u4E8E",
893
+ "kbFilter.operatorLabel": "\u64CD\u4F5C\u7B26",
894
+ "kbFilter.or": "\u6216",
895
+ "kbFilter.toggleAndOr": "\u5207\u6362 AND / OR",
896
+ "kbFilter.valueAria": "\u8FC7\u6EE4\u503C",
897
+ "kbFilter.valueLabel": "\u503C",
898
+ "kbFilter.valuePlaceholder": "\u503C 1, \u503C 2\uFF08\u9017\u53F7\u5206\u9694\uFF09",
899
+ /* ── kbGap ── */
900
+ "kbGap.addSynonym": "\u52A0\u540C\u4E49\u8BCD",
901
+ "kbGap.colCount": "\u6B21\u6570",
902
+ "kbGap.colLastSeen": "\u6700\u8FD1\u51FA\u73B0",
903
+ "kbGap.colQuery": "\u67E5\u8BE2",
904
+ "kbGap.colShare": "\u5360\u6BD4",
905
+ "kbGap.createDoc": "\u5EFA\u6587\u6863",
906
+ "kbGap.empty": "\u6CA1\u6709\u672A\u547D\u4E2D\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u826F\u597D",
907
+ "kbGap.title": "\u672A\u547D\u4E2D\u67E5\u8BE2\u8D8B\u52BF",
908
+ "kbGap.zeroClickHint": "\u7528\u6237\u53EF\u80FD\u5DF2\u4ECE\u5F15\u7528\u7247\u6BB5\u5F97\u5230\u7B54\u6848\uFF1B\u96F6\u70B9\u51FB\u9700\u4EBA\u5DE5\u5224\u8BFB\uFF0C\u4E0D\u76F4\u63A5\u89C6\u4E3A\u5931\u8D25",
909
+ "kbGap.zeroClickRate": "\u96F6\u70B9\u51FB\u7387",
910
+ "kbGap.zeroClickTitle": "\u96F6\u70B9\u51FB \u2260 \u5931\u8D25",
911
+ /* ── kbHittest ── */
912
+ "kbHittest.addAria": "\u65B0\u589E\u6D4B\u8BD5\u95EE\u9898",
913
+ "kbHittest.addPlaceholder": "\u65B0\u589E\u95EE\u9898\uFF0CEnter \u6DFB\u52A0",
914
+ "kbHittest.avgScore": "\u5747\u5206",
915
+ "kbHittest.deleteQuestion": "\u5220\u9664\u95EE\u9898",
916
+ "kbHittest.empty": "\u6682\u65E0\u6D4B\u8BD5\u95EE\u9898\u2014\u2014\u6DFB\u52A0\u7B2C\u4E00\u6761\uFF0C\u5F00\u59CB\u53EC\u56DE\u56DE\u5F52",
917
+ "kbHittest.expectHit": "\u671F\u671B\u547D\u4E2D\u5728\u524D\u6392\u547D\u4E2D\u4E2D",
918
+ "kbHittest.expectMiss": "\u671F\u671B\u672A\u547D\u4E2D",
919
+ "kbHittest.hitRate": "\u547D\u4E2D\u7387",
920
+ "kbHittest.noExpectation": "\u672A\u8BBE\u671F\u671B",
921
+ "kbHittest.notRun": "\u672A\u8FD0\u884C",
922
+ "kbHittest.pass": "\u901A\u8FC7",
923
+ "kbHittest.pin": "\u7F6E\u9876\u56FA\u5B9A",
924
+ "kbHittest.runAll": "\u8FD0\u884C\u5168\u90E8",
925
+ "kbHittest.sessionOnly": "\u53C2\u6570\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
926
+ "kbHittest.sessionOnlyHint": "\u6D4B\u8BD5\u8FD0\u884C\u7684\u68C0\u7D22\u53C2\u6570\uFF08topK/\u9608\u503C/\u91CD\u6392\uFF09\u4E0D\u843D\u5E93\uFF0C\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
927
+ "kbHittest.unpin": "\u53D6\u6D88\u7F6E\u9876",
928
+ /* ── kbMetadata ── */
929
+ "kbMetadata.addField": "\u65B0\u589E\u5B57\u6BB5",
930
+ "kbMetadata.builtIn": "\u5185\u7F6E",
931
+ "kbMetadata.colField": "\u5B57\u6BB5",
932
+ "kbMetadata.colType": "\u7C7B\u578B",
933
+ "kbMetadata.colValue": "\u503C",
934
+ "kbMetadata.empty": "\u6682\u65E0\u5143\u6570\u636E\u5B57\u6BB5",
935
+ "kbMetadata.nameLabel": "\u65B0\u5B57\u6BB5\u540D",
936
+ "kbMetadata.namePlaceholder": "\u5B57\u6BB5\u540D\uFF0C\u5982 department",
937
+ "kbMetadata.removeField": "\u79FB\u9664\u5B57\u6BB5 {p0}",
938
+ "kbMetadata.typeLabel": "\u65B0\u5B57\u6BB5\u7C7B\u578B",
939
+ "kbMetadata.valueOf": "{p0} \u7684\u503C",
940
+ /* ── kbPassage ── */
941
+ "kbPassage.blockRange": "\u5757 {p0}\u2013{p1}",
942
+ "kbPassage.close": "\u5173\u95ED\u539F\u6587",
943
+ "kbPassage.expandContext": "\u5C55\u5F00\u4E0A\u4E0B\u6587",
944
+ "kbPassage.locate": "\u539F\u6587\u5B9A\u4F4D",
945
+ "kbPassage.none": "\uFF08\u65E0\u539F\u6587\uFF09",
946
+ "kbPassage.pageRange": "\u7B2C {p0}\u2013{p1} \u9875",
947
+ "kbPassage.restricted": "\u5185\u5BB9\u53D7\u9650",
948
+ "kbPassage.unitByte": "\u5B57\u8282",
949
+ "kbPassage.unitChar": "\u5B57\u7B26",
950
+ /* ── kbPipeline ── */
951
+ "kbPipeline.empty": "\u6682\u65E0\u89E3\u6790\u4EFB\u52A1",
952
+ "kbPipeline.progress": "\u89E3\u6790\u8FDB\u5EA6",
953
+ "kbPipeline.rerun": "\u91CD\u8DD1",
954
+ "kbPipeline.unknownStage": "\u672A\u77E5\u9636\u6BB5",
955
+ /* ── kbQa ── */
956
+ "kbQa.colAnswer": "\u7B54\u6848",
957
+ "kbQa.colQuestion": "\u95EE\u9898",
958
+ "kbQa.csvHint": "CSV \u6A21\u677F\uFF1Aquestion,answer\uFF08\u6BCF\u884C\u4E00\u5BF9\uFF0CUTF-8\uFF09",
959
+ "kbQa.deleteRow": "\u5220\u9664\u7B2C {p0} \u884C",
960
+ "kbQa.empty": "\u6682\u65E0\u8BA4\u8BC1\u95EE\u7B54\u5BF9",
961
+ "kbQa.importCsv": "\u5BFC\u5165 CSV",
962
+ /* ── kbRerank ── */
963
+ "kbRerank.after": "\u91CD\u6392\u540E",
964
+ "kbRerank.before": "\u91CD\u6392\u524D",
965
+ "kbRerank.compareTitle": "\u91CD\u6392\u5BF9\u6BD4",
966
+ "kbRerank.down": "\u4E0B\u964D {p0} \u4F4D",
967
+ "kbRerank.dropped": "\u843D\u9009",
968
+ "kbRerank.empty": "\u4E24\u4FA7\u5747\u4E3A\u7A7A\u2014\u2014\u8FD0\u884C\u68C0\u7D22\u540E\u518D\u5BF9\u6BD4",
969
+ "kbRerank.enableCompare": "\u542F\u7528\u91CD\u6392\u5BF9\u6BD4",
970
+ "kbRerank.newIn": "\u65B0\u8FDB",
971
+ "kbRerank.unmarked": "\u672A\u6807",
972
+ "kbRerank.up": "\u4E0A\u5347 {p0} \u4F4D",
973
+ /* ── kbRetrieval ── */
974
+ "kbRetrieval.breakdown": "\u62C6\u89E3",
975
+ "kbRetrieval.copyParams": "\u590D\u5236\u53C2\u6570 JSON",
976
+ "kbRetrieval.decreaseTopK": "\u51CF\u5C11 topK",
977
+ "kbRetrieval.empty": "\u8F93\u5165\u95EE\u9898\u5E76\u8FD0\u884C\uFF0C\u547D\u4E2D\u7ED3\u679C\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
978
+ "kbRetrieval.failOpenNotice": "fail-open\uFF1A\u5F53\u524D\u67E5\u8BE2\u672A\u643A\u5E26\u8EAB\u4EFD\u8FC7\u6EE4\uFF0C\u5C06\u8FD4\u56DE\u5168\u90E8\u5019\u9009\uFF08\u4EC5\u9650\u8C03\u8BD5\uFF09",
979
+ "kbRetrieval.hybridWeight": "\u6DF7\u5408\u6743\u91CD\uFF08\u5DE6\u8BED\u4E49\u53F3\u5173\u952E\u8BCD\uFF09",
980
+ "kbRetrieval.identityLabel": "\u68C0\u7D22\u8EAB\u4EFD",
981
+ "kbRetrieval.identityShort": "\u8EAB\u4EFD",
982
+ "kbRetrieval.increaseTopK": "\u589E\u52A0 topK",
983
+ "kbRetrieval.keywordHint": "\u5173\u952E\u8BCD\uFF1A\u5927\u5E93\u5FEB\u901F\u7CBE\u786E",
984
+ "kbRetrieval.layerLabel": "\u8FC7\u6EE4\u5C42",
985
+ "kbRetrieval.layerNone": "none\uFF1Afail-open\uFF0C\u65E0\u8EAB\u4EFD\u8FC7\u6EE4\u8FD4\u56DE\u5168\u90E8\u2014\u2014\u5371\u9669\uFF0C\u4EC5\u6F14\u793A",
986
+ "kbRetrieval.layerPost": "post-filter\uFF1A\u5206\u6570\u5DF2\u53EF\u89C2\u5BDF\u2014\u2014\u7F3A\u9677\u5C42\uFF0C\u4EC5\u6F14\u793A",
987
+ "kbRetrieval.layerPre": "pre-filter\uFF1AACL \u5728\u68C0\u7D22\u6267\u884C\u4F53\u5185\u751F\u6548\u2014\u2014\u5B89\u5168\u57FA\u7EBF",
988
+ "kbRetrieval.leakNote": "\u5206\u6BCD\u672A\u8FC7\u6EE4\u524D\u8BA1\u6570\u5C5E\u6CC4\u9732\uFF0C\u4E0D\u663E\u793A",
989
+ "kbRetrieval.modeHybrid": "\u6DF7\u5408",
990
+ "kbRetrieval.modeKeyword": "\u5173\u952E\u8BCD",
991
+ "kbRetrieval.modeLabel": "\u68C0\u7D22\u6A21\u5F0F",
992
+ "kbRetrieval.modeVector": "\u5411\u91CF",
993
+ "kbRetrieval.postFilterNotice": "post-filter\uFF1A\u5206\u6570\u5DF2\u5728\u8FC7\u6EE4\u524D\u4EA7\u751F\uFF08\u7F3A\u9677\u5C42\u6F14\u793A\uFF09",
994
+ "kbRetrieval.queryLabel": "\u68C0\u7D22\u95EE\u9898",
995
+ "kbRetrieval.queryPlaceholder": "\u68C0\u7D22\u95EE\u9898\uFF0CEnter \u8FD0\u884C",
996
+ "kbRetrieval.rerankLabel": "\u91CD\u6392",
997
+ "kbRetrieval.rerankThresholdOff": "\u9608\u503C \u5173 \xB7 \u5B58\u6D3B {p0}",
998
+ "kbRetrieval.rerankThresholdOn": "\u9608\u503C {p0} \xB7 \u5B58\u6D3B {p1}",
999
+ "kbRetrieval.running": "\u8FD0\u884C\u4E2D\u2026",
1000
+ "kbRetrieval.thresholdLabel": "\u5206\u6570\u9608\u503C",
1001
+ "kbRetrieval.thresholdValue": "\u9608\u503C N/A",
1002
+ "kbRetrieval.vectorHint": "\u8BED\u4E49\uFF1A\u8DE8\u8BED\u8A00/\u65E0\u7CBE\u786E\u8BCD",
1003
+ "kbRetrieval.vectorPercent": "\u8BED\u4E49 {p0}",
1004
+ "kbRetrieval.weightValue": "\u5411\u91CF {p0}% / \u5173\u952E\u8BCD {p1}%",
1005
+ /* ── kbReview ── */
1006
+ "kbReview.assignee": "\u5206\u914D\u4EBA",
1007
+ "kbReview.doneNext": "\u5B8C\u6210\u5E76\u4E0B\u4E00\u6761",
1008
+ "kbReview.empty": "\u6CA1\u6709\u5F85\u5BA1\u67E5\u6761\u76EE",
1009
+ "kbReview.emptyAssignee": "\u8BE5\u5206\u914D\u4EBA\u4E0B\u6CA1\u6709\u6761\u76EE",
1010
+ "kbReview.emptyQueue": "\u961F\u5217\u4E3A\u7A7A",
1011
+ "kbReview.kbCloseHint": "\u5173\u95ED\u63D0\u793A",
1012
+ "kbReview.kbSelectOption": "\u9009\u62E9\u9009\u9879",
1013
+ "kbReview.kbSwitchItem": "\u5207\u6362\u6761\u76EE",
1014
+ "kbReview.kbToggleHint": "\u663E\u793A/\u9690\u85CF\u672C\u63D0\u793A",
1015
+ "kbReview.shortcuts": "? \u5FEB\u6377\u952E",
1016
+ "kbReview.typeAnswer": "\u56DE\u7B54",
1017
+ "kbReview.typeMessage": "\u6D88\u606F",
1018
+ "kbReview.typeTrace": "\u8F68\u8FF9",
1019
+ "kbReview.unassigned": "\u672A\u5206\u914D",
1020
+ /* ── kbSandbox ── */
1021
+ "kbSandbox.noResolver": "\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668",
1022
+ "kbSandbox.notReady": "kb-sandbox: \u5E94\u7528\u672A\u5C31\u7EEA",
1023
+ "kbSandbox.resolveFailed": "ui:// \u89E3\u6790\u5931\u8D25\uFF1A{p0}",
1024
+ "kbSandbox.timeout": "kb-sandbox: \u8C03\u7528\u8D85\u65F6\uFF08{p0}ms\uFF09",
1025
+ "kbSandbox.title": "MCP App \u6C99\u7BB1",
1026
+ /* ── kbSegment ── */
1027
+ "kbSegment.avgLength": "\u5747\u957F {p0}",
1028
+ "kbSegment.childNote": "\u5B50\u5206\u6BB5\u6309\u957F\u5EA6\u81EA\u52A8\u751F\u6210",
1029
+ "kbSegment.cleanBlankLines": "\u5408\u5E76\u8FDE\u7EED\u7A7A\u884C",
1030
+ "kbSegment.cleanEmails": "\u53BB\u9664\u90AE\u7BB1",
1031
+ "kbSegment.cleanLinks": "\u53BB\u9664\u94FE\u63A5",
1032
+ "kbSegment.empty": "\u6837\u672C\u4E3A\u7A7A\uFF0C\u6682\u65E0\u53EF\u9884\u89C8\u5206\u6BB5",
1033
+ "kbSegment.maxLengthLabel": "\u6700\u5927\u957F\u5EA6",
1034
+ "kbSegment.maxLengthPlaceholder": "\u5206\u6BB5\u6700\u5927\u957F\u5EA6",
1035
+ "kbSegment.modeAuto": "\u81EA\u52A8",
1036
+ "kbSegment.modeCustom": "\u81EA\u5B9A\u4E49",
1037
+ "kbSegment.modeLabel": "\u5206\u6BB5\u6A21\u5F0F",
1038
+ "kbSegment.modeNote": "\u5206\u6BB5\u6A21\u5F0F\u521B\u5EFA\u540E\u4E0D\u53EF\u66F4\u6539\uFF0C\u53C2\u6570\u53EF\u968F\u65F6\u8C03\u6574",
1039
+ "kbSegment.modeParentChild": "\u7236\u5B50",
1040
+ "kbSegment.overlapInvalid": "\u91CD\u53E0\u9700\u5C0F\u4E8E\u6700\u5927\u957F\u5EA6",
1041
+ "kbSegment.overlapLabel": "\u91CD\u53E0",
1042
+ "kbSegment.overlapPlaceholder": "\u5206\u6BB5\u91CD\u53E0",
1043
+ "kbSegment.previewNote": "\u5171 {p0} \u6BB5\uFF0C\u4EC5\u9884\u89C8\u524D {p1} \u6BB5",
1044
+ "kbSegment.segmentsCount": "{p0} \u6BB5",
1045
+ "kbSegment.separatorLabel": "\u5206\u9694\u7B26",
1046
+ "kbSegment.separatorPlaceholder": "\u5206\u6BB5\u5206\u9694\u7B26",
1047
+ "kbSegment.toggleTip": "\u70B9\u51FB\u5C55\u5F00/\u6536\u8D77",
1048
+ /* ── kbSources ── */
1049
+ "kbSources.cited": "\u88AB\u5F15 \xD7{p0}",
1050
+ "kbSources.empty": "\u4E0B\u4E00\u6761\u7B54\u6848\u5F15\u7528\u7684\u6BB5\u843D\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
1051
+ /* ── kbSql ── */
1052
+ "kbSql.adminOnly": "\u4EC5\u7BA1\u7406\u5458\u53EF\u89C1",
1053
+ "kbSql.applyFix": "\u5E94\u7528\u4FEE\u590D\u5E76\u91CD\u8DD1",
1054
+ "kbSql.confirmRerun": "\u786E\u8BA4\u5E76\u91CD\u8DD1",
1055
+ "kbSql.editRerun": "\u7F16\u8F91\u91CD\u8DD1",
1056
+ "kbSql.fixReady": "\u68C0\u6D4B\u5230\u4E0A\u7248\u62A5\u9519\uFF0C\u4FEE\u590D\u5EFA\u8BAE\u5DF2\u5C31\u7EEA",
1057
+ "kbSql.generated": "\u751F\u6210\u7684 SQL",
1058
+ /* ── kbTrace ── */
1059
+ "kbTrace.empty": "\u6682\u65E0\u8C03\u7528\u94FE\u6570\u636E",
1060
+ "kbTrace.hits": "\u547D\u4E2D {p0}",
1061
+ /* ── kbVisibility ── */
1062
+ "kbVisibility.adminOnlyNote": "\u4EE5\u4E0A\u5BF9\u7167\u4EC5\u9650 admin \u5BA1\u8BA1",
1063
+ "kbVisibility.adminWarn": "admin \u5BA1\u8BA1\u89C6\u56FE\u2014\u2014\u547D\u4E2D\u5DEE\u5F02\u5BF9\u7167\u5BF9\u666E\u901A\u7528\u6237\u6784\u6210\u6CC4\u9732\uFF0C\u52FF\u5D4C\u5165\u7EC8\u7AEF\u7528\u6237\u754C\u9762",
1064
+ "kbVisibility.failOpenNote": "fail-open\uFF1AKendra \u65E0\u8EAB\u4EFD\u4E0A\u4E0B\u6587\u8FD4\u56DE\u5168\u90E8\u6587\u6863\u2014\u2014\u68C0\u7D22\u5FC5\u987B\u643A\u5E26\u670D\u52A1\u7AEF\u8EAB\u4EFD",
1065
+ "kbVisibility.focusColumn": "\u805A\u7126\u8EAB\u4EFD {p0} \u7684\u5217",
1066
+ "kbVisibility.layerValue": "\u8FC7\u6EE4\u5C42\uFF1A{p0}",
1067
+ "kbVisibility.leakageNote": "\u8BA1\u6570\u5DEE\u5F02\u5373 volume leakage\uFF1A\u5BF9\u666E\u901A\u7528\u6237\u53EA\u53EF\u7ED9\u300C\u5DF2\u6309\u6743\u9650\u8FC7\u6EE4\u300D\u6052\u5B9A\u6587\u6848\uFF0C\u7F13\u89E3\u53EA\u6709 padding \u53D6\u6574",
1068
+ "kbVisibility.postFilterNote": "post-filter\uFF1AtopK \u88AB\u65E0\u6743\u7ED3\u679C\u5360\u7528\u4E14\u76F8\u4F3C\u5EA6\u5206\u6570\u53EF\u88AB\u89C2\u5BDF",
1069
+ "kbVisibility.queryLabel": "\u67E5\u8BE2\uFF1A{p0}",
1070
+ "kbVisibility.safeCount": "\u5B89\u5168\u8BA1\u6570 {p0}",
1071
+ "kbVisibility.sourceUnavailable": "\u539F\u6587\u4E0D\u53EF\u7528",
1072
+ "kbVisibility.unnamedHit": "\u672A\u547D\u540D\u547D\u4E2D",
1073
+ /* ── kbWhoCan ── */
1074
+ "kbWhoCan.check": "\u68C0\u67E5",
1075
+ "kbWhoCan.checkIdentity": "\u68C0\u67E5\u8EAB\u4EFD",
1076
+ "kbWhoCan.daysUntil": "{p0} \u5929\u540E",
1077
+ "kbWhoCan.deniedBy": "\u88AB\u7B56\u7565\u62D2\u7EDD\uFF1A{p0}",
1078
+ "kbWhoCan.denyVeto": "\u88AB Deny \u4E00\u7968\u5426\u51B3",
1079
+ "kbWhoCan.direct": "\u76F4\u63A5",
1080
+ "kbWhoCan.expiresSoon": "\u6700\u8FD1\u5230\u671F {p0}",
1081
+ "kbWhoCan.hoursUntil": "{p0} \u5C0F\u65F6\u540E",
1082
+ "kbWhoCan.inherit": "\u7EE7\u627F",
1083
+ "kbWhoCan.link": "\u94FE\u63A5",
1084
+ "kbWhoCan.noDeny": "\u65E0 Deny \u751F\u6548",
1085
+ "kbWhoCan.noIdentity": "\u672A\u63D0\u4F9B\u53EF\u68C0\u67E5\u7684\u8EAB\u4EFD",
1086
+ "kbWhoCan.none": "\u672A\u547D\u4E2D\u4EFB\u4F55\u6388\u6743\u2014\u2014\u9ED8\u8BA4\u62D2\u7EDD",
1087
+ "kbWhoCan.recheckTip": "\u91CD\u65B0\u68C0\u67E5\u5F53\u524D\u8EAB\u4EFD\u7684\u6709\u6548\u6743\u9650",
1088
+ "kbWhoCan.stackRule": "\u53E0\u52A0\u89C4\u5219\uFF1A\u591A\u6765\u6E90\u5E76\u96C6 \u2192 {p0}\uFF1B{p1}",
1089
+ /* ── mentions ── */
1090
+ "mentions.create": "\u521B\u5EFA\u201C{p0}\u201D",
1091
+ "mentions.customBadge": "\u81EA\u5B9A\u4E49",
1092
+ "mentions.loading": "\u52A0\u8F7D\u4E2D\u2026",
1093
+ /* ── notification ── */
1094
+ "notification.groupBusy": "\u64CD\u4F5C\u7ED3\u675F\u540E\u53EF\u4EE5\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5\u3002",
1095
+ "notification.groupUnread": "{count} \u6761\u540C\u7EC4\u901A\u77E5\uFF0C{unread} \u6761\u672A\u8BFB",
1096
+ "notification.groupCount": "{count} \u6761\u540C\u7EC4\u901A\u77E5",
1097
+ "notification.groupExpanded": "\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5",
1098
+ "notification.ariaLabel": "\u901A\u77E5",
1099
+ "notification.viewDetails": "\u67E5\u770B\u8BE6\u60C5",
1100
+ /* ── pagination ── */
1101
+ "pagination.next": "\u4E0B\u4E00\u9875",
1102
+ "pagination.pageSize": "{p0} \u6761/\u9875",
1103
+ "pagination.prev": "\u4E0A\u4E00\u9875",
1104
+ /* ── select ── */
1105
+ "select.fieldLabel": "\u9009\u62E9\u9009\u9879",
1106
+ "select.noMatch": "\u65E0\u5339\u914D\u9879",
1107
+ "select.remove": "\u79FB\u9664 {p0}",
1108
+ "select.searchPlaceholder": "\u641C\u7D22\u2026",
1109
+ /* ── cascader / tree-select ── */
1110
+ "cascader.placeholder": "\u8BF7\u9009\u62E9",
1111
+ "cascader.noMatch": "\u65E0\u5339\u914D",
1112
+ "cascader.search": "\u641C\u7D22",
1113
+ "treeSelect.placeholder": "\u8BF7\u9009\u62E9",
1114
+ "treeSelect.noMatch": "\u65E0\u5339\u914D",
1115
+ "treeSelect.search": "\u641C\u7D22",
1116
+ /* ── tagInput ── */
1117
+ "tagInput.ariaLabel": "\u6807\u7B7E\u8F93\u5165\uFF0C\u5171 {p0} \u4E2A",
1118
+ "tagInput.remove": "\u79FB\u9664 {p0}",
1119
+ "tagInput.field": "\u6DFB\u52A0\u6807\u7B7E",
1120
+ "tagInput.added": "\u5DF2\u6DFB\u52A0 {p0} \u4E2A\u6807\u7B7E\u3002",
1121
+ "tagInput.removed": "\u5DF2\u79FB\u9664 {p0}\u3002",
1122
+ "tagInput.duplicate": "\u5DF2\u6709\u300C{p0}\u300D\uFF0C\u53EF\u4EE5\u7F16\u8F91\u540E\u91CD\u8BD5\u3002",
1123
+ "tagInput.limit": "\u6700\u591A {p0} \u4E2A\u6807\u7B7E\uFF0C\u8BF7\u5148\u79FB\u9664\u4E00\u4E2A\u3002",
1124
+ /* ── upload ── */
1125
+ "upload.remove": "\u79FB\u9664 {p0}",
1126
+ "upload.tooBig": "\u6587\u4EF6\u8D85\u8FC7 {p0}",
1127
+ "upload.tooMany": "\u6700\u591A {p0} \u4E2A\u6587\u4EF6",
1128
+ "upload.typeNotAllowed": "\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301"
1129
+ };
1130
+ var current = { ...ICEN_LOCALE_ZH_CN };
1131
+ function t(key, vars) {
1132
+ const raw = current[key] ?? ICEN_LOCALE_ZH_CN[key];
1133
+ if (vars == null || Array.isArray(raw)) return raw;
1134
+ return raw.replace(/\{(\w+)\}/g, (m, name) => name in vars ? String(vars[name]) : m);
1135
+ }
1136
+
133
1137
  // src/behaviors/context-menu.ts
134
1138
  var FLIP_MARGIN = 10;
135
1139
  var CLAMP_MARGIN = 8;
@@ -137,31 +1141,35 @@ function emitMenuSelect(source, item) {
137
1141
  emitIcen(item, "icen:menu-select", {
138
1142
  source,
139
1143
  item,
140
- value: item.dataset.value ?? "",
1144
+ value: item.dataset.icenValue ?? "",
141
1145
  /* 优先专用 label 子元素(避开快捷键/图标文本混入),无则退整项文本 */
142
- label: (item.querySelector(".menu-item-label, .command-item-label")?.textContent ?? item.textContent ?? "").trim().slice(0, 80)
1146
+ label: (item.querySelector(".icen-menu-item-label, .command-item-label")?.textContent ?? item.textContent ?? "").trim().slice(0, 80)
143
1147
  });
144
1148
  }
1149
+ var returnFocus = null;
1150
+ var typed = "";
1151
+ var typedAt = 0;
1152
+ var releaseMenu = null;
145
1153
  var panel = null;
146
1154
  var focusableItems = [];
147
1155
  var focusedIndex = -1;
148
1156
  function buildItem(item, menuPanel) {
149
1157
  if ("type" in item && item.type === "separator") {
150
1158
  const sep = document.createElement("div");
151
- sep.className = "menu-separator";
1159
+ sep.className = "icen-menu-separator";
152
1160
  sep.setAttribute("role", "separator");
153
1161
  return sep;
154
1162
  }
155
1163
  if ("type" in item && item.type === "header") {
156
1164
  const header = document.createElement("div");
157
- header.className = "menu-header";
1165
+ header.className = "icen-menu-header";
158
1166
  const label2 = document.createElement("span");
159
- label2.className = "menu-header-label";
1167
+ label2.className = "icen-menu-header-label";
160
1168
  label2.textContent = item.label;
161
1169
  header.appendChild(label2);
162
1170
  if (item.description) {
163
1171
  const desc = document.createElement("span");
164
- desc.className = "menu-header-desc";
1172
+ desc.className = "icen-menu-header-desc";
165
1173
  desc.textContent = item.description;
166
1174
  header.appendChild(desc);
167
1175
  }
@@ -170,43 +1178,54 @@ function buildItem(item, menuPanel) {
170
1178
  const entry = item;
171
1179
  const btn = document.createElement("button");
172
1180
  btn.type = "button";
173
- btn.className = entry.danger ? "menu-item pressable menu-item--danger" : "menu-item pressable";
1181
+ btn.className = entry.danger ? "icen-menu-item icen-pressable icen-menu-item--danger" : "icen-menu-item icen-pressable";
174
1182
  if (entry.disabled) btn.disabled = true;
1183
+ if (entry.disabled) btn.setAttribute("aria-disabled", "true");
175
1184
  btn.setAttribute("role", "menuitem");
176
1185
  btn.tabIndex = -1;
177
1186
  const icon = document.createElement("span");
178
- icon.className = "menu-item-icon";
179
- if (entry.icon) icon.innerHTML = entry.icon;
1187
+ icon.className = "icen-menu-item-icon";
1188
+ const symbol = entry.iconName ? createIcon(entry.iconName) : entry.icon ? parseSvg(entry.icon) : null;
1189
+ if (symbol) {
1190
+ symbol.setAttribute("aria-hidden", "true");
1191
+ icon.append(symbol);
1192
+ }
180
1193
  btn.appendChild(icon);
181
1194
  const label = document.createElement("span");
182
- label.className = "menu-item-label";
1195
+ label.className = "icen-menu-item-label";
183
1196
  label.textContent = entry.label;
184
1197
  if (entry.subLabel) {
185
1198
  const sub = document.createElement("span");
186
- sub.className = "menu-item-sub";
1199
+ sub.className = "icen-menu-item-sub";
187
1200
  sub.textContent = entry.subLabel;
188
1201
  label.appendChild(sub);
189
1202
  }
190
1203
  btn.appendChild(label);
191
1204
  if (entry.shortcut) {
192
1205
  const shortcut = document.createElement("span");
193
- shortcut.className = "menu-item-shortcut";
1206
+ shortcut.className = "icen-menu-item-shortcut";
194
1207
  shortcut.textContent = entry.shortcut;
1208
+ shortcut.setAttribute("aria-hidden", "true");
195
1209
  btn.appendChild(shortcut);
196
1210
  }
197
1211
  btn.addEventListener("click", () => {
198
1212
  emitMenuSelect(menuPanel, btn);
1213
+ if (panel === menuPanel) closeContextMenu(menuPanel.contains(document.activeElement));
199
1214
  entry.onClick?.();
200
- closeContextMenu();
201
1215
  });
202
1216
  return btn;
203
1217
  }
204
1218
  function openContextMenu(x, y, items, opts) {
205
1219
  if (typeof document === "undefined") return;
206
1220
  closeContextMenu();
1221
+ releaseMenu = claimMenuFocus(() => closeContextMenu());
1222
+ returnFocus = opts?.returnFocus ?? (document.activeElement instanceof HTMLElement ? document.activeElement : null);
1223
+ typed = "";
1224
+ typedAt = 0;
207
1225
  panel = document.createElement("div");
208
- panel.className = "menu menu--context";
1226
+ panel.className = "icen-menu icen-menu--context";
209
1227
  panel.setAttribute("role", "menu");
1228
+ panel.tabIndex = -1;
210
1229
  panel.style.visibility = "hidden";
211
1230
  applyPanelSizing(panel, opts?.sizing ?? {});
212
1231
  for (const item of items) panel.appendChild(buildItem(item, panel));
@@ -220,23 +1239,29 @@ function openContextMenu(x, y, items, opts) {
220
1239
  if (y + rect.height > vh - FLIP_MARGIN) ny = y - rect.height;
221
1240
  if (nx < CLAMP_MARGIN) nx = CLAMP_MARGIN;
222
1241
  if (ny < CLAMP_MARGIN) ny = CLAMP_MARGIN;
223
- panel.dataset.side = ny < y ? "top" : "bottom";
1242
+ panel.dataset.icenSide = ny < y ? "top" : "bottom";
224
1243
  panel.style.left = `${nx}px`;
225
1244
  panel.style.top = `${ny}px`;
226
1245
  panel.style.visibility = "";
227
- focusableItems = Array.from(panel.querySelectorAll(".menu-item:not(:disabled)"));
1246
+ focusableItems = Array.from(panel.querySelectorAll(".icen-menu-item:not(:disabled)"));
228
1247
  focusedIndex = -1;
1248
+ const openedPanel = panel;
229
1249
  requestAnimationFrame(() => {
230
- if (!panel || focusableItems.length === 0) return;
231
- setFocused(0);
1250
+ if (panel !== openedPanel) return;
1251
+ if (focusableItems.length) setFocused(0);
1252
+ else panel.focus({ preventScroll: true });
232
1253
  });
233
1254
  document.addEventListener("pointerdown", onOutsidePointerDown, true);
234
1255
  document.addEventListener("scroll", onScrollSignal, true);
235
1256
  window.addEventListener("resize", onCloseSignal);
236
- window.addEventListener("keydown", onKeyDown);
1257
+ window.addEventListener("keydown", onKeyDown, true);
237
1258
  }
238
- function closeContextMenu() {
1259
+ function closeContextMenu(restoreFocus = false) {
239
1260
  if (!panel) return;
1261
+ releaseMenu?.();
1262
+ releaseMenu = null;
1263
+ if (restoreFocus && returnFocus?.isConnected) returnFocus.focus({ preventScroll: true });
1264
+ returnFocus = null;
240
1265
  panel.remove();
241
1266
  panel = null;
242
1267
  focusableItems = [];
@@ -244,12 +1269,16 @@ function closeContextMenu() {
244
1269
  document.removeEventListener("pointerdown", onOutsidePointerDown, true);
245
1270
  document.removeEventListener("scroll", onScrollSignal, true);
246
1271
  window.removeEventListener("resize", onCloseSignal);
247
- window.removeEventListener("keydown", onKeyDown);
1272
+ window.removeEventListener("keydown", onKeyDown, true);
248
1273
  }
249
1274
  function setFocused(next) {
250
1275
  if (!panel || focusableItems.length === 0) return;
251
1276
  focusedIndex = (next % focusableItems.length + focusableItems.length) % focusableItems.length;
252
- focusableItems[focusedIndex].focus();
1277
+ focusableItems.forEach((item, i) => {
1278
+ item.tabIndex = i === focusedIndex ? 0 : -1;
1279
+ item.classList.toggle("is-highlighted", i === focusedIndex);
1280
+ });
1281
+ revealPopoverItem(focusableItems[focusedIndex], panel, { focus: true });
253
1282
  }
254
1283
  function onOutsidePointerDown(e) {
255
1284
  if (!panel) return;
@@ -265,9 +1294,15 @@ function onCloseSignal() {
265
1294
  }
266
1295
  function onKeyDown(e) {
267
1296
  if (!panel) return;
1297
+ if (e.isComposing || e.keyCode === 229) return;
268
1298
  if (e.key === "Escape") {
269
1299
  e.preventDefault();
270
- closeContextMenu();
1300
+ e.stopPropagation();
1301
+ closeContextMenu(true);
1302
+ return;
1303
+ }
1304
+ if (e.key === "Tab") {
1305
+ closeContextMenu(true);
271
1306
  return;
272
1307
  }
273
1308
  if (focusableItems.length === 0) return;
@@ -277,38 +1312,100 @@ function onKeyDown(e) {
277
1312
  } else if (e.key === "ArrowUp") {
278
1313
  e.preventDefault();
279
1314
  setFocused(focusedIndex - 1);
280
- } else if (e.key === "Enter" && focusedIndex >= 0) {
1315
+ } else if (e.key === "Home" || e.key === "End") {
1316
+ e.preventDefault();
1317
+ setFocused(e.key === "Home" ? 0 : focusableItems.length - 1);
1318
+ } else if ((e.key === "Enter" || e.key === " ") && focusedIndex >= 0) {
281
1319
  e.preventDefault();
282
1320
  focusableItems[focusedIndex].click();
1321
+ } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
1322
+ const now = Date.now();
1323
+ typed = now - typedAt < 600 ? typed + e.key : e.key;
1324
+ typedAt = now;
1325
+ let query = typed.toLocaleLowerCase();
1326
+ if ([...query].every((c) => c === query[0])) query = typed = query[0];
1327
+ for (let step = 1; step <= focusableItems.length; step++) {
1328
+ const index = (Math.max(0, focusedIndex) + (query.length === 1 ? step : step - 1)) % focusableItems.length;
1329
+ if (focusableItems[index].querySelector(".icen-menu-item-label")?.textContent?.trim().toLocaleLowerCase().startsWith(query)) {
1330
+ e.preventDefault();
1331
+ setFocused(index);
1332
+ break;
1333
+ }
1334
+ }
283
1335
  }
284
1336
  }
285
1337
 
286
1338
  // src/behaviors/datatable.ts
287
- var SVG_NS = "http://www.w3.org/2000/svg";
288
- function svgIcon(d, size = 12) {
289
- const svg = document.createElementNS(SVG_NS, "svg");
290
- svg.setAttribute("width", String(size));
291
- svg.setAttribute("height", String(size));
292
- svg.setAttribute("viewBox", "0 0 24 24");
293
- svg.setAttribute("fill", "none");
294
- svg.setAttribute("stroke", "currentColor");
295
- svg.setAttribute("stroke-width", "2");
296
- svg.setAttribute("stroke-linecap", "round");
297
- svg.setAttribute("stroke-linejoin", "round");
298
- const path = document.createElementNS(SVG_NS, "path");
299
- path.setAttribute("d", d);
300
- svg.appendChild(path);
301
- return svg;
302
- }
303
- var ICON_SEARCH = "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm10 2-4.3-4.3";
304
- var ICON_FUNNEL = "M22 3H2l8 9.46V19l4 2v-8.54L22 3Z";
305
- var ICON_CHEVRON = "m6 9 6 6 6-6";
306
- var ICON_COLUMNS = "M3 3h7v18H3zM14 3h7v18h-7z";
307
- var ICON_DOWNLOAD = "M12 3v12m0 0-4-4m4 4 4-4M5 21h14";
308
1339
  function defaultCompare(a, b) {
309
- if (typeof a === "number" && typeof b === "number") return a - b;
1340
+ if (typeof a === "number" && typeof b === "number") {
1341
+ if (Number.isNaN(a) || Number.isNaN(b)) {
1342
+ if (Number.isNaN(a) && Number.isNaN(b)) return 0;
1343
+ return Number.isNaN(a) ? 1 : -1;
1344
+ }
1345
+ return a - b;
1346
+ }
310
1347
  return String(a ?? "").localeCompare(String(b ?? ""), "zh-CN", { numeric: true });
311
1348
  }
1349
+ function toNum(v) {
1350
+ if (typeof v === "number") return Number.isFinite(v) ? v : null;
1351
+ if (typeof v === "string" && v.trim() !== "") {
1352
+ const n = Number(v);
1353
+ return Number.isNaN(n) ? null : n;
1354
+ }
1355
+ return null;
1356
+ }
1357
+ function formatAggNumber(n) {
1358
+ if (!Number.isFinite(n)) return "\u2014";
1359
+ const r = Math.round(n * 100) / 100;
1360
+ return String(r);
1361
+ }
1362
+ function computeAggregates(rows, columns) {
1363
+ const out = {};
1364
+ for (const col of columns) {
1365
+ const agg = col.aggregate;
1366
+ if (!agg) continue;
1367
+ if (typeof agg === "function") {
1368
+ const vals = [];
1369
+ for (const row of rows) {
1370
+ const n = toNum(row[col.key]);
1371
+ if (n != null) vals.push(n);
1372
+ }
1373
+ out[col.key] = agg(vals);
1374
+ continue;
1375
+ }
1376
+ if (agg === "count") {
1377
+ let c = 0;
1378
+ for (const row of rows) {
1379
+ const v = row[col.key];
1380
+ if (v !== null && v !== void 0 && v !== "") c++;
1381
+ }
1382
+ out[col.key] = String(c);
1383
+ continue;
1384
+ }
1385
+ let acc = 0;
1386
+ let cnt = 0;
1387
+ let extreme = 0;
1388
+ for (const row of rows) {
1389
+ const n = toNum(row[col.key]);
1390
+ if (n == null) continue;
1391
+ if (cnt === 0) extreme = n;
1392
+ else if (agg === "min") extreme = Math.min(extreme, n);
1393
+ else if (agg === "max") extreme = Math.max(extreme, n);
1394
+ acc += n;
1395
+ cnt++;
1396
+ }
1397
+ if (cnt === 0) {
1398
+ out[col.key] = "\u2014";
1399
+ } else if (agg === "sum") {
1400
+ out[col.key] = formatAggNumber(acc);
1401
+ } else if (agg === "avg") {
1402
+ out[col.key] = formatAggNumber(acc / cnt);
1403
+ } else {
1404
+ out[col.key] = formatAggNumber(extreme);
1405
+ }
1406
+ }
1407
+ return out;
1408
+ }
312
1409
  function noopHandle() {
313
1410
  const noop = () => void 0;
314
1411
  return {
@@ -320,6 +1417,10 @@ function noopHandle() {
320
1417
  setSort: noop,
321
1418
  refresh: noop,
322
1419
  destroy: noop,
1420
+ getSorts: () => [],
1421
+ setSorts: noop,
1422
+ moveColumn: noop,
1423
+ updateCell: noop,
323
1424
  getData: () => [],
324
1425
  exportCSV: noop,
325
1426
  showColumn: noop,
@@ -334,14 +1435,20 @@ function createTable(el, opts) {
334
1435
  let search = "";
335
1436
  let page = 1;
336
1437
  let pageSize = opts.pageSize ?? 10;
337
- let sortKey = null;
338
- let sortDir = "asc";
1438
+ let sorts = [];
339
1439
  let scrollTop = 0;
340
1440
  const filters = /* @__PURE__ */ new Map();
341
1441
  const selected = /* @__PURE__ */ new Set();
342
1442
  const expanded = /* @__PURE__ */ new Set();
343
1443
  const colWidths = /* @__PURE__ */ new Map();
344
1444
  const colHidden = /* @__PURE__ */ new Map();
1445
+ let colOrder = null;
1446
+ const groupState = /* @__PURE__ */ new Map();
1447
+ let editing = null;
1448
+ let drag = null;
1449
+ let lastDragEndAt = 0;
1450
+ let navTotal = 0;
1451
+ let focusPos = null;
345
1452
  let lastClickedIndex = -1;
346
1453
  let destroyed = false;
347
1454
  const virtual = opts.virtual === true;
@@ -351,7 +1458,23 @@ function createTable(el, opts) {
351
1458
  const selectable = opts.selectable === true;
352
1459
  const expandable = !virtual ? opts.expandable : void 0;
353
1460
  const resizable = opts.resizable !== false;
354
- const cols = () => opts.columns.filter((c) => !(c.hidden || colHidden.get(c.key)));
1461
+ const multiSort = opts.multiSort === true;
1462
+ const reorderable = opts.reorderable === true;
1463
+ const groupFn = opts.groupBy ? typeof opts.groupBy === "function" ? opts.groupBy : (row) => String(row[opts.groupBy] ?? "") : null;
1464
+ const frozenSide = (c) => c.frozen === true ? "left" : c.frozen === "left" || c.frozen === "right" ? c.frozen : null;
1465
+ const isEditable = (c) => c.editable === true || typeof c.editable === "string";
1466
+ const editKind = (c) => c.editable === "number" || c.editable === "select" ? c.editable : "text";
1467
+ function cols() {
1468
+ const order = colOrder ?? opts.columns.map((c) => c.key);
1469
+ const byKey = new Map(opts.columns.map((c) => [c.key, c]));
1470
+ const out = [];
1471
+ for (const k of order) {
1472
+ const c = byKey.get(k);
1473
+ if (c && !(c.hidden || colHidden.get(k))) out.push(c);
1474
+ }
1475
+ return out;
1476
+ }
1477
+ const colByKey = (key) => opts.columns.find((c) => c.key === key);
355
1478
  const keyOf = (row, index) => {
356
1479
  if (typeof opts.rowKey === "function") return opts.rowKey(row);
357
1480
  if (typeof opts.rowKey === "string") return String(row[opts.rowKey]);
@@ -366,6 +1489,7 @@ function createTable(el, opts) {
366
1489
  let pipelineCache = null;
367
1490
  function invalidate() {
368
1491
  pipelineCache = null;
1492
+ flatCache = null;
369
1493
  }
370
1494
  function pipeline() {
371
1495
  if (pipelineCache) return pipelineCache;
@@ -384,47 +1508,92 @@ function createTable(el, opts) {
384
1508
  return true;
385
1509
  });
386
1510
  }
387
- if (sortKey) {
388
- const col = opts.columns.find((c) => c.key === sortKey);
389
- const cmp = col?.sortFn ? (a, b) => col.sortFn(a, b) : (a, b) => defaultCompare(a[sortKey], b[sortKey]);
390
- rows = [...rows].sort((a, b) => sortDir === "asc" ? cmp(a, b) : -cmp(a, b));
1511
+ if (sorts.length > 0) {
1512
+ rows = [...rows].sort((a, b) => {
1513
+ for (const s of sorts) {
1514
+ const col = colByKey(s.key);
1515
+ const cmp = col?.sortFn ? col.sortFn(a, b) : defaultCompare(a[s.key], b[s.key]);
1516
+ if (cmp !== 0) return s.dir === "asc" ? cmp : -cmp;
1517
+ }
1518
+ return 0;
1519
+ });
391
1520
  }
392
1521
  pipelineCache = rows;
393
1522
  return rows;
394
1523
  }
1524
+ let flatCache = null;
1525
+ function flatEntries() {
1526
+ const rows = pipeline();
1527
+ if (flatCache && flatCache.base === rows) return flatCache.entries;
1528
+ const entries = [];
1529
+ if (groupFn) {
1530
+ const groups = [];
1531
+ const byKey = /* @__PURE__ */ new Map();
1532
+ rows.forEach((row, i) => {
1533
+ const label = groupFn(row);
1534
+ let g = byKey.get(label);
1535
+ if (!g) {
1536
+ g = { label, items: [] };
1537
+ byKey.set(label, g);
1538
+ groups.push(g);
1539
+ }
1540
+ g.items.push({ row, i });
1541
+ });
1542
+ for (const g of groups) {
1543
+ const collapsed = groupState.get(g.label) === true;
1544
+ const gRows = g.items.map((it) => it.row);
1545
+ entries.push({
1546
+ kind: "group",
1547
+ gkey: g.label,
1548
+ label: g.label,
1549
+ count: g.items.length,
1550
+ aggs: computeAggregates(gRows, opts.columns),
1551
+ collapsed
1552
+ });
1553
+ if (!collapsed) {
1554
+ for (const it of g.items) entries.push({ kind: "data", row: it.row, pipeIndex: it.i });
1555
+ }
1556
+ }
1557
+ } else {
1558
+ rows.forEach((row, i) => entries.push({ kind: "data", row, pipeIndex: i }));
1559
+ }
1560
+ flatCache = { base: rows, entries };
1561
+ return entries;
1562
+ }
395
1563
  el.textContent = "";
396
1564
  const root = document.createElement("div");
397
- root.className = "datatable";
398
- if (opts.striped) root.classList.add("datatable--striped");
399
- if (virtual) root.classList.add("datatable--virtual");
400
- if (compact) root.classList.add("datatable--compact");
401
- if (opts.columns.some((c) => c.frozen)) root.classList.add("datatable--frozen");
1565
+ root.className = "icen-datatable";
1566
+ if (opts.striped) root.classList.add("icen-datatable--striped");
1567
+ if (virtual) root.classList.add("icen-datatable--virtual");
1568
+ if (compact) root.classList.add("icen-datatable--compact");
1569
+ if (opts.columns.some((c) => c.frozen)) root.classList.add("icen-datatable--frozen");
1570
+ if (reorderable) root.classList.add("icen-datatable--reorderable");
402
1571
  let searchInput = null;
403
1572
  const needsToolbar = opts.searchable || opts.columnVisibility || opts.exportable;
404
1573
  let toolbar = null;
405
1574
  if (needsToolbar) {
406
1575
  toolbar = document.createElement("div");
407
- toolbar.className = "dt-toolbar";
1576
+ toolbar.className = "icen-dt-toolbar";
408
1577
  if (opts.searchable) {
409
1578
  const box = document.createElement("div");
410
- box.className = "dt-search";
411
- box.appendChild(svgIcon(ICON_SEARCH, 14));
1579
+ box.className = "icen-dt-search";
1580
+ box.appendChild(createIcon("search", { size: 14 }));
412
1581
  searchInput = document.createElement("input");
413
- searchInput.className = "dt-search-input";
1582
+ searchInput.className = "icen-dt-search-input";
414
1583
  searchInput.type = "search";
415
- searchInput.placeholder = opts.searchPlaceholder ?? "\u641C\u7D22\u2026";
416
- searchInput.setAttribute("aria-label", "\u641C\u7D22\u8868\u683C");
1584
+ searchInput.placeholder = opts.searchPlaceholder ?? t("datatable.searchPlaceholder");
1585
+ searchInput.setAttribute("aria-label", t("datatable.searchAria"));
417
1586
  box.appendChild(searchInput);
418
1587
  toolbar.appendChild(box);
419
1588
  }
420
1589
  const actions = document.createElement("div");
421
- actions.className = "dt-toolbar-actions";
1590
+ actions.className = "icen-dt-toolbar-actions";
422
1591
  if (opts.columnVisibility) {
423
1592
  const colBtn = document.createElement("button");
424
1593
  colBtn.type = "button";
425
- colBtn.className = "dt-tool-btn";
426
- colBtn.setAttribute("aria-label", "\u5217\u8BBE\u7F6E");
427
- colBtn.appendChild(svgIcon(ICON_COLUMNS, 14));
1594
+ colBtn.className = "icen-dt-tool-btn";
1595
+ colBtn.setAttribute("aria-label", t("datatable.columnSettingsAria"));
1596
+ colBtn.appendChild(createIcon("columns", { size: 14 }));
428
1597
  colBtn.addEventListener("click", (ev) => {
429
1598
  ev.stopPropagation();
430
1599
  if (openPanel?.key === "__cols") closeFilterPanel();
@@ -438,9 +1607,9 @@ function createTable(el, opts) {
438
1607
  if (opts.exportable) {
439
1608
  const expBtn = document.createElement("button");
440
1609
  expBtn.type = "button";
441
- expBtn.className = "dt-tool-btn";
442
- expBtn.setAttribute("aria-label", "\u5BFC\u51FA CSV");
443
- expBtn.appendChild(svgIcon(ICON_DOWNLOAD, 14));
1610
+ expBtn.className = "icen-dt-tool-btn";
1611
+ expBtn.setAttribute("aria-label", t("common.exportCsv"));
1612
+ expBtn.appendChild(createIcon("download", { size: 14 }));
444
1613
  expBtn.addEventListener("click", () => exportCSV());
445
1614
  actions.appendChild(expBtn);
446
1615
  }
@@ -448,45 +1617,69 @@ function createTable(el, opts) {
448
1617
  root.appendChild(toolbar);
449
1618
  }
450
1619
  const scroll = document.createElement("div");
451
- scroll.className = "dt-scroll";
1620
+ scroll.className = "icen-dt-scroll";
452
1621
  if (virtual) scroll.style.maxHeight = opts.height ?? "420px";
453
1622
  const canvas = document.createElement("div");
454
- canvas.className = "dt-canvas";
1623
+ canvas.className = "icen-dt-canvas";
455
1624
  canvas.setAttribute("role", "grid");
456
1625
  const head = document.createElement("div");
457
- head.className = "dt-head";
1626
+ head.className = "icen-dt-head";
458
1627
  head.setAttribute("role", "rowgroup");
459
1628
  const headRow = document.createElement("div");
460
- headRow.className = "dt-row dt-row--head";
1629
+ headRow.className = "icen-dt-row icen-dt-row--head";
461
1630
  headRow.setAttribute("role", "row");
462
1631
  head.appendChild(headRow);
463
1632
  const body = document.createElement("div");
464
- body.className = "dt-body";
1633
+ body.className = "icen-dt-body";
465
1634
  body.setAttribute("role", "rowgroup");
466
- canvas.append(head, body);
1635
+ const summaryEl = opts.summaryRow ? document.createElement("div") : null;
1636
+ if (summaryEl) {
1637
+ summaryEl.className = "icen-dt-row icen-dt-row--summary";
1638
+ summaryEl.setAttribute("role", "row");
1639
+ summaryEl.hidden = true;
1640
+ }
1641
+ canvas.append(head, body, ...summaryEl ? [summaryEl] : []);
467
1642
  scroll.appendChild(canvas);
468
1643
  root.appendChild(scroll);
469
1644
  const foot = document.createElement("div");
470
- foot.className = "dt-foot";
1645
+ foot.className = "icen-dt-foot";
471
1646
  root.appendChild(foot);
472
1647
  el.appendChild(root);
1648
+ function parsePx(w) {
1649
+ const m = /^(\d+(?:\.\d+)?)px/.exec(w);
1650
+ return m ? Number(m[1]) : 0;
1651
+ }
473
1652
  function frozenOffsets() {
474
- const offsets = /* @__PURE__ */ new Map();
475
- if (!opts.columns.some((c) => c.frozen)) return offsets;
1653
+ const left = /* @__PURE__ */ new Map();
1654
+ const right = /* @__PURE__ */ new Map();
476
1655
  const visible = cols();
1656
+ if (!visible.some((c) => c.frozen)) return { left, right };
477
1657
  let acc = 0;
478
1658
  if (selectable) acc += 40;
479
1659
  if (expandable) acc += 34;
480
1660
  for (const c of visible) {
481
- if (c.frozen) offsets.set(c.key, acc);
482
- const w = colWidths.get(c.key) ?? c.width ?? "minmax(0,1fr)";
483
- acc += parsePx(w);
1661
+ if (frozenSide(c) === "left") left.set(c.key, acc);
1662
+ acc += parsePx(colWidths.get(c.key) ?? c.width ?? "minmax(0,1fr)");
1663
+ }
1664
+ let accR = 0;
1665
+ for (let i = visible.length - 1; i >= 0; i--) {
1666
+ const c = visible[i];
1667
+ if (frozenSide(c) === "right") right.set(c.key, accR);
1668
+ accR += parsePx(colWidths.get(c.key) ?? c.width ?? "minmax(0,1fr)");
484
1669
  }
485
- return offsets;
1670
+ return { left, right };
486
1671
  }
487
- function parsePx(w) {
488
- const m = /^(\d+(?:\.\d+)?)px/.exec(w);
489
- return m ? Number(m[1]) : 0;
1672
+ function applyFrozen(cell, col, frz) {
1673
+ const side = frozenSide(col);
1674
+ if (side === "left") {
1675
+ cell.classList.add("icen-dt-cell--frozen");
1676
+ const off = frz.left.get(col.key);
1677
+ if (off != null) cell.style.left = `${off}px`;
1678
+ } else if (side === "right") {
1679
+ cell.classList.add("icen-dt-cell--frozen-right");
1680
+ const off = frz.right.get(col.key);
1681
+ if (off != null) cell.style.right = `${off}px`;
1682
+ }
490
1683
  }
491
1684
  function template() {
492
1685
  const parts = [];
@@ -508,11 +1701,40 @@ function createTable(el, opts) {
508
1701
  function makeCheck(checked, label) {
509
1702
  const input = document.createElement("input");
510
1703
  input.type = "checkbox";
511
- input.className = "dt-check";
1704
+ input.className = "icen-dt-check";
512
1705
  input.checked = checked;
513
1706
  input.setAttribute("aria-label", label);
514
1707
  return input;
515
1708
  }
1709
+ function applySorts(next, nullDir = "asc", emit = true) {
1710
+ sorts = next;
1711
+ invalidate();
1712
+ const primary = sorts[0];
1713
+ if (primary && emit) emitIcen(root, "icen:table-sort-change", { key: primary.key, dir: primary.dir });
1714
+ opts.onSortChange?.(primary?.key ?? null, primary?.dir ?? nullDir);
1715
+ renderAll();
1716
+ }
1717
+ function toggleSort(key, append) {
1718
+ const cur = sorts.find((s) => s.key === key);
1719
+ if (!multiSort || !append) {
1720
+ if (!cur) applySorts([{ key, dir: "asc" }]);
1721
+ else if (cur.dir === "asc") applySorts([{ key, dir: "desc" }]);
1722
+ else applySorts([], cur.dir);
1723
+ return;
1724
+ }
1725
+ if (!cur) applySorts([...sorts, { key, dir: "asc" }]);
1726
+ else if (cur.dir === "asc") applySorts(sorts.map((s) => s.key === key ? { key, dir: "desc" } : s));
1727
+ else applySorts(sorts.filter((s) => s.key !== key), cur.dir);
1728
+ }
1729
+ function sanitizeSorts(arr) {
1730
+ const out = [];
1731
+ for (const s of arr ?? []) {
1732
+ if (!s || typeof s.key !== "string" || !colByKey(s.key)) continue;
1733
+ const dir = s.dir === "desc" ? "desc" : "asc";
1734
+ if (!out.some((o) => o.key === s.key)) out.push({ key: s.key, dir });
1735
+ }
1736
+ return out;
1737
+ }
516
1738
  let openPanel = null;
517
1739
  function positionDropdownPanel(panel2, btn) {
518
1740
  panel2.hidden = false;
@@ -536,7 +1758,7 @@ function createTable(el, opts) {
536
1758
  if (!openPanel) return;
537
1759
  openPanel.el.remove();
538
1760
  openPanel = null;
539
- headRow.querySelectorAll(".dt-filter-btn").forEach((b) => b.classList.remove("is-open"));
1761
+ headRow.querySelectorAll(".icen-dt-filter-btn").forEach((b) => b.classList.remove("is-open"));
540
1762
  window.removeEventListener("scroll", onPanelScroll, true);
541
1763
  window.removeEventListener("resize", onPanelScroll);
542
1764
  }
@@ -553,13 +1775,15 @@ function createTable(el, opts) {
553
1775
  closeFilterPanel();
554
1776
  headRow.textContent = "";
555
1777
  headRow.style.gridTemplateColumns = template();
1778
+ const frz = frozenOffsets();
556
1779
  if (selectable) {
557
1780
  const cell = document.createElement("div");
558
- cell.className = "dt-cell dt-cell--check";
1781
+ cell.className = "icen-dt-cell icen-dt-cell--check";
1782
+ cell.setAttribute("role", "columnheader");
559
1783
  const rows = pipeline();
560
1784
  const allKeys = rows.map((r) => keyOfRow(r));
561
1785
  const selCount = allKeys.filter((k) => selected.has(k)).length;
562
- const box = makeCheck(selCount > 0 && selCount === allKeys.length, "\u5168\u9009");
1786
+ const box = makeCheck(selCount > 0 && selCount === allKeys.length, t("datatable.selectAll"));
563
1787
  box.indeterminate = selCount > 0 && selCount < allKeys.length;
564
1788
  box.addEventListener("change", () => {
565
1789
  if (box.checked) allKeys.forEach((k) => selected.add(k));
@@ -573,48 +1797,48 @@ function createTable(el, opts) {
573
1797
  }
574
1798
  if (expandable) {
575
1799
  const cell = document.createElement("div");
576
- cell.className = "dt-cell dt-cell--expand";
1800
+ cell.className = "icen-dt-cell icen-dt-cell--expand";
1801
+ cell.setAttribute("role", "columnheader");
577
1802
  headRow.appendChild(cell);
578
1803
  }
579
1804
  for (const col of cols()) {
580
1805
  const cell = document.createElement("div");
581
- cell.className = "dt-cell dt-cell--head";
582
- if (col.align) cell.dataset.align = col.align;
583
- if (col.frozen) cell.classList.add("dt-cell--frozen");
1806
+ cell.className = "icen-dt-cell icen-dt-cell--head";
1807
+ cell.setAttribute("role", "columnheader");
1808
+ if (col.align) cell.dataset.icenAlign = col.align;
1809
+ cell.dataset.icenColKey = col.key;
1810
+ applyFrozen(cell, col, frz);
584
1811
  const title = document.createElement("span");
585
- title.className = "dt-head-title";
1812
+ title.className = "icen-dt-head-title";
586
1813
  title.textContent = col.title;
587
1814
  cell.appendChild(title);
588
1815
  if (col.sortable) {
589
1816
  cell.classList.add("is-sortable");
590
1817
  cell.setAttribute("role", "columnheader");
591
1818
  cell.tabIndex = 0;
592
- const active = sortKey === col.key;
593
- cell.setAttribute("aria-sort", active ? sortDir === "asc" ? "ascending" : "descending" : "none");
1819
+ const si = sorts.findIndex((s) => s.key === col.key);
1820
+ const active = si >= 0;
1821
+ cell.setAttribute("aria-sort", active ? sorts[si].dir === "asc" ? "ascending" : "descending" : "none");
594
1822
  const arrow = document.createElement("span");
595
- arrow.className = "dt-sort";
596
- arrow.textContent = active ? sortDir === "asc" ? "\u2191" : "\u2193" : "\u2195";
1823
+ arrow.className = "icen-dt-sort";
1824
+ arrow.append(createIcon(active ? sorts[si].dir === "asc" ? "arrow-up" : "arrow-down" : "sort", { size: 14 }));
597
1825
  if (active) arrow.classList.add("is-active");
598
1826
  cell.appendChild(arrow);
599
- const toggleSort = () => {
600
- if (sortKey !== col.key) {
601
- sortKey = col.key;
602
- sortDir = "asc";
603
- } else if (sortDir === "asc") sortDir = "desc";
604
- else sortKey = null;
605
- invalidate();
606
- if (sortKey) emitIcen(root, "icen:table-sort-change", { key: sortKey, dir: sortDir });
607
- opts.onSortChange?.(sortKey, sortDir);
608
- renderAll();
609
- };
1827
+ if (active && sorts.length > 1) {
1828
+ const badge = document.createElement("span");
1829
+ badge.className = "icen-dt-sort-badge";
1830
+ badge.textContent = String(si + 1);
1831
+ cell.appendChild(badge);
1832
+ }
610
1833
  cell.addEventListener("click", (ev) => {
611
- if (ev.target.closest(".dt-filter-btn, .dt-resize")) return;
612
- toggleSort();
1834
+ if (ev.target.closest(".icen-dt-filter-btn, .icen-dt-resize")) return;
1835
+ if (Date.now() - lastDragEndAt < 200) return;
1836
+ toggleSort(col.key, ev.shiftKey);
613
1837
  });
614
1838
  cell.addEventListener("keydown", (ev) => {
615
1839
  if (ev.key === "Enter" || ev.key === " ") {
616
1840
  ev.preventDefault();
617
- toggleSort();
1841
+ toggleSort(col.key, ev.shiftKey);
618
1842
  }
619
1843
  });
620
1844
  }
@@ -622,11 +1846,11 @@ function createTable(el, opts) {
622
1846
  const hasFilter = filters.has(col.key);
623
1847
  const btn = document.createElement("button");
624
1848
  btn.type = "button";
625
- btn.className = "dt-filter-btn";
1849
+ btn.className = "icen-dt-filter-btn";
626
1850
  btn.dataset.colKey = col.key;
627
1851
  if (hasFilter) btn.classList.add("is-active");
628
- btn.setAttribute("aria-label", `\u7B5B\u9009\u300C${col.title}\u300D`);
629
- btn.appendChild(svgIcon(ICON_FUNNEL, 12));
1852
+ btn.setAttribute("aria-label", t("datatable.filterChipAria", { p0: col.title }));
1853
+ btn.appendChild(createIcon("filter", { size: 12 }));
630
1854
  btn.addEventListener("click", (ev) => {
631
1855
  ev.stopPropagation();
632
1856
  if (openPanel?.key === col.key) closeFilterPanel();
@@ -639,25 +1863,26 @@ function createTable(el, opts) {
639
1863
  }
640
1864
  if (resizable && col !== cols()[cols().length - 1]) {
641
1865
  const handle = document.createElement("div");
642
- handle.className = "dt-resize";
1866
+ handle.className = "icen-dt-resize";
643
1867
  handle.setAttribute("role", "separator");
644
1868
  handle.setAttribute("aria-orientation", "vertical");
645
- handle.setAttribute("aria-label", `\u8C03\u6574\u300C${col.title}\u300D\u5217\u5BBD`);
1869
+ handle.setAttribute("aria-label", t("datatable.resizeAria", { p0: col.title }));
646
1870
  attachResize(handle, col);
647
1871
  cell.appendChild(handle);
648
1872
  }
1873
+ if (reorderable) attachReorderDrag(cell, col);
649
1874
  headRow.appendChild(cell);
650
1875
  }
651
1876
  }
652
1877
  function syncHeadState() {
653
- const headBox = headRow.querySelector(".dt-cell--check .dt-check");
1878
+ const headBox = headRow.querySelector(".icen-dt-cell--check .icen-dt-check");
654
1879
  if (headBox) {
655
1880
  const allKeys = pipeline().map((r) => keyOfRow(r));
656
1881
  const selCount = allKeys.filter((k) => selected.has(k)).length;
657
1882
  headBox.checked = selCount > 0 && selCount === allKeys.length;
658
1883
  headBox.indeterminate = selCount > 0 && selCount < allKeys.length;
659
1884
  }
660
- headRow.querySelectorAll(".dt-filter-btn").forEach((b) => {
1885
+ headRow.querySelectorAll(".icen-dt-filter-btn").forEach((b) => {
661
1886
  const key = b.dataset.colKey;
662
1887
  if (key) b.classList.toggle("is-active", filters.has(key));
663
1888
  });
@@ -671,7 +1896,7 @@ function createTable(el, opts) {
671
1896
  window.addEventListener("scroll", onPanelScroll, true);
672
1897
  window.addEventListener("resize", onPanelScroll);
673
1898
  if (keep.key !== "__cols") {
674
- headRow.querySelectorAll(".dt-filter-btn").forEach((b) => {
1899
+ headRow.querySelectorAll(".icen-dt-filter-btn").forEach((b) => {
675
1900
  if (b.dataset.colKey === keep.key) b.classList.add("is-open");
676
1901
  });
677
1902
  }
@@ -681,14 +1906,17 @@ function createTable(el, opts) {
681
1906
  ev.preventDefault();
682
1907
  ev.stopPropagation();
683
1908
  const startX = ev.clientX;
684
- const startW = handle.closest(".dt-cell").getBoundingClientRect().width;
685
- handle.setPointerCapture(ev.pointerId);
1909
+ const startW = handle.closest(".icen-dt-cell").getBoundingClientRect().width;
1910
+ try {
1911
+ handle.setPointerCapture(ev.pointerId);
1912
+ } catch {
1913
+ }
686
1914
  const onMove = (e) => {
687
1915
  const delta = e.clientX - startX;
688
1916
  const next = Math.max(48, Math.round(startW + delta));
689
1917
  colWidths.set(col.key, `${next}px`);
690
1918
  headRow.style.gridTemplateColumns = template();
691
- body.querySelectorAll(".dt-row").forEach((r) => {
1919
+ body.querySelectorAll(".icen-dt-row").forEach((r) => {
692
1920
  r.style.gridTemplateColumns = template();
693
1921
  });
694
1922
  };
@@ -700,23 +1928,145 @@ function createTable(el, opts) {
700
1928
  handle.removeEventListener("pointermove", onMove);
701
1929
  handle.removeEventListener("pointerup", onUp);
702
1930
  handle.removeEventListener("pointercancel", onUp);
1931
+ const width = colWidths.get(col.key);
1932
+ if (width) emitIcen(root, "icen:table-column-resize", { key: col.key, width });
703
1933
  };
704
1934
  handle.addEventListener("pointermove", onMove);
705
1935
  handle.addEventListener("pointerup", onUp);
706
1936
  handle.addEventListener("pointercancel", onUp);
707
1937
  });
708
1938
  }
1939
+ const clampN = (v, lo, hi) => hi < lo ? lo : Math.min(hi, Math.max(lo, v));
1940
+ function reorderBounds(key) {
1941
+ const vis = cols();
1942
+ const leftCount = vis.filter((c) => frozenSide(c) === "left").length;
1943
+ const rightCount = vis.filter((c) => frozenSide(c) === "right").length;
1944
+ const col = colByKey(key);
1945
+ if (!col) return [0, vis.length - 1];
1946
+ const side = frozenSide(col);
1947
+ if (side === "left") return [0, leftCount - 1];
1948
+ if (side === "right") return [vis.length - rightCount, vis.length - 1];
1949
+ return [leftCount, vis.length - rightCount - 1];
1950
+ }
1951
+ function moveColumn(key, toIndex) {
1952
+ if (!colByKey(key) || !Number.isFinite(toIndex)) return;
1953
+ if (!colOrder) colOrder = opts.columns.map((c) => c.key);
1954
+ const hiddenSet = new Set(opts.columns.filter((c) => c.hidden || colHidden.get(c.key)).map((c) => c.key));
1955
+ const vis = colOrder.filter((k) => !hiddenSet.has(k));
1956
+ const from = vis.indexOf(key);
1957
+ if (from < 0) return;
1958
+ const [lo, hi] = reorderBounds(key);
1959
+ const target = clampN(Math.round(toIndex), lo, hi);
1960
+ if (target === from) return;
1961
+ vis.splice(from, 1);
1962
+ vis.splice(target, 0, key);
1963
+ const newOrder = [];
1964
+ let vi = 0;
1965
+ for (const k of colOrder) {
1966
+ newOrder.push(hiddenSet.has(k) ? k : vis[vi++]);
1967
+ }
1968
+ colOrder = newOrder;
1969
+ invalidate();
1970
+ emitIcen(root, "icen:table-column-reorder", { key, fromIndex: from, toIndex: target });
1971
+ renderAll();
1972
+ }
1973
+ function attachReorderDrag(cell, col) {
1974
+ cell.addEventListener("pointerdown", (ev) => {
1975
+ if (destroyed || ev.button !== 0) return;
1976
+ const t2 = ev.target;
1977
+ if (t2 instanceof Element && t2.closest(".icen-dt-resize, .icen-dt-filter-btn, button, input, select, textarea, a")) return;
1978
+ const startX = ev.clientX;
1979
+ const startY = ev.clientY;
1980
+ let started = false;
1981
+ let latestX = startX;
1982
+ let latestY = startY;
1983
+ let raf = 0;
1984
+ const headCellsExcl = () => Array.from(headRow.querySelectorAll(".icen-dt-cell--head")).filter((c) => c.dataset.icenColKey !== col.key);
1985
+ const targetFromX = (x) => {
1986
+ const cells = headCellsExcl();
1987
+ let target = cells.length;
1988
+ for (let i = 0; i < cells.length; i++) {
1989
+ const r = cells[i].getBoundingClientRect();
1990
+ if (x < r.left + r.width / 2) {
1991
+ target = i;
1992
+ break;
1993
+ }
1994
+ }
1995
+ const [lo, hi] = reorderBounds(col.key);
1996
+ return clampN(target, lo, hi);
1997
+ };
1998
+ const placeIndicator = (target) => {
1999
+ if (!drag) return;
2000
+ const cells = headCellsExcl();
2001
+ const scrollRect = scroll.getBoundingClientRect();
2002
+ let x;
2003
+ if (cells.length === 0) x = scrollRect.left;
2004
+ else if (target >= cells.length) x = cells[cells.length - 1].getBoundingClientRect().right;
2005
+ else x = cells[target].getBoundingClientRect().left;
2006
+ drag.indicator.style.left = `${Math.max(0, x - 1)}px`;
2007
+ drag.indicator.style.top = `${scrollRect.top}px`;
2008
+ drag.indicator.style.height = `${scrollRect.height}px`;
2009
+ };
2010
+ const paint = () => {
2011
+ raf = 0;
2012
+ if (!drag || !started) return;
2013
+ drag.ghost.style.left = `${latestX + 12}px`;
2014
+ drag.ghost.style.top = `${latestY + 10}px`;
2015
+ placeIndicator(targetFromX(latestX));
2016
+ };
2017
+ const onMove = (e) => {
2018
+ if (!started && Math.hypot(e.clientX - startX, e.clientY - startY) > 5) {
2019
+ started = true;
2020
+ const ghost = document.createElement("div");
2021
+ ghost.className = "icen-dt-col-ghost";
2022
+ ghost.textContent = col.title;
2023
+ const indicator = document.createElement("div");
2024
+ indicator.className = "icen-dt-col-indicator";
2025
+ document.body.append(ghost, indicator);
2026
+ cell.classList.add("is-drag-source");
2027
+ drag = { key: col.key, ghost, indicator, off: cleanup };
2028
+ }
2029
+ latestX = e.clientX;
2030
+ latestY = e.clientY;
2031
+ if (started && !raf) raf = requestAnimationFrame(paint);
2032
+ };
2033
+ const cleanup = () => {
2034
+ window.cancelAnimationFrame(raf);
2035
+ document.removeEventListener("pointermove", onMove, true);
2036
+ document.removeEventListener("pointerup", onUp, true);
2037
+ document.removeEventListener("pointercancel", onUp, true);
2038
+ if (drag) {
2039
+ drag.ghost.remove();
2040
+ drag.indicator.remove();
2041
+ drag = null;
2042
+ }
2043
+ cell.classList.remove("is-drag-source");
2044
+ };
2045
+ const onUp = (e) => {
2046
+ const wasDrag = started;
2047
+ const target = wasDrag ? targetFromX(e.clientX) : -1;
2048
+ cleanup();
2049
+ if (wasDrag) {
2050
+ lastDragEndAt = Date.now();
2051
+ moveColumn(col.key, target);
2052
+ }
2053
+ };
2054
+ document.addEventListener("pointermove", onMove, true);
2055
+ document.addEventListener("pointerup", onUp, true);
2056
+ document.addEventListener("pointercancel", onUp, true);
2057
+ });
2058
+ }
709
2059
  function openColumnPanel(btn) {
710
2060
  const panel2 = document.createElement("div");
711
- panel2.className = "dt-filter-panel dt-col-panel";
2061
+ panel2.className = "icen-dt-filter-panel dt-col-panel";
712
2062
  panel2.hidden = true;
713
2063
  panel2.addEventListener("click", (ev) => ev.stopPropagation());
714
2064
  const list = document.createElement("div");
715
- list.className = "dt-filter-list";
2065
+ list.className = "icen-dt-filter-list";
716
2066
  for (const col of opts.columns) {
717
2067
  if (col.key === "__select" || col.key === "__expand") continue;
718
2068
  const row = document.createElement("label");
719
- row.className = "dt-filter-item";
2069
+ row.className = "icen-dt-filter-item";
720
2070
  const isHidden = colHidden.get(col.key) ?? col.hidden ?? false;
721
2071
  const box = makeCheck(!isHidden, col.title);
722
2072
  box.addEventListener("change", () => {
@@ -747,7 +2097,7 @@ function createTable(el, opts) {
747
2097
  const lines = rows.map(
748
2098
  (row) => visible.map((c) => csvEscape(String(row[c.key] ?? ""))).join(",")
749
2099
  );
750
- const csv = "\uFEFF" + [header, ...lines].join("\r\n");
2100
+ const csv = String.fromCharCode(65279) + [header, ...lines].join("\r\n");
751
2101
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
752
2102
  const url = URL.createObjectURL(blob);
753
2103
  const a = document.createElement("a");
@@ -762,15 +2112,15 @@ function createTable(el, opts) {
762
2112
  }
763
2113
  function buildFilterPanel(col) {
764
2114
  const panel2 = document.createElement("div");
765
- panel2.className = "dt-filter-panel";
2115
+ panel2.className = "icen-dt-filter-panel";
766
2116
  panel2.hidden = true;
767
2117
  panel2.addEventListener("click", (ev) => ev.stopPropagation());
768
2118
  const list = document.createElement("div");
769
- list.className = "dt-filter-list";
2119
+ list.className = "icen-dt-filter-list";
770
2120
  const values = Array.from(new Set(data.map((r) => String(r[col.key] ?? "")))).sort((a, b) => a.localeCompare(b, "zh-CN", { numeric: true }));
771
2121
  for (const v of values) {
772
2122
  const row = document.createElement("label");
773
- row.className = "dt-filter-item";
2123
+ row.className = "icen-dt-filter-item";
774
2124
  const box = makeCheck(filters.get(col.key)?.has(v) ?? true, v);
775
2125
  box.addEventListener("change", () => {
776
2126
  const cur = new Set(filters.get(col.key) ?? values);
@@ -785,21 +2135,21 @@ function createTable(el, opts) {
785
2135
  syncHeadState();
786
2136
  });
787
2137
  const text = document.createElement("span");
788
- text.textContent = v === "" ? "\uFF08\u7A7A\uFF09" : v;
2138
+ text.textContent = v === "" ? t("datatable.emptyValue") : v;
789
2139
  row.append(box, text);
790
2140
  list.appendChild(row);
791
2141
  }
792
2142
  const footRow = document.createElement("div");
793
- footRow.className = "dt-filter-foot";
2143
+ footRow.className = "icen-dt-filter-foot";
794
2144
  const reset = document.createElement("button");
795
2145
  reset.type = "button";
796
- reset.className = "dt-filter-reset";
797
- reset.textContent = "\u91CD\u7F6E";
2146
+ reset.className = "icen-dt-filter-reset";
2147
+ reset.textContent = t("datatable.reset");
798
2148
  reset.addEventListener("click", () => {
799
2149
  filters.delete(col.key);
800
2150
  invalidate();
801
2151
  page = 1;
802
- list.querySelectorAll(".dt-check").forEach((b) => {
2152
+ list.querySelectorAll(".icen-dt-check").forEach((b) => {
803
2153
  b.checked = true;
804
2154
  });
805
2155
  renderBody();
@@ -809,25 +2159,197 @@ function createTable(el, opts) {
809
2159
  panel2.append(list, footRow);
810
2160
  return panel2;
811
2161
  }
812
- function makeRow(row, rowIndex, key, offsets) {
2162
+ function startEdit(cell, row, col, rowKey) {
2163
+ if (!isEditable(col) || editing) return;
2164
+ const kind = editKind(col);
2165
+ let editor;
2166
+ if (kind === "select") {
2167
+ const sel = document.createElement("select");
2168
+ sel.className = "icen-dt-editor icen-dt-editor--select";
2169
+ const cur = String(row[col.key] ?? "");
2170
+ for (const opt of col.editOptions ?? []) {
2171
+ const o = document.createElement("option");
2172
+ o.value = typeof opt === "string" ? opt : opt.value;
2173
+ o.textContent = typeof opt === "string" ? opt : opt.label;
2174
+ if (o.value === cur) o.selected = true;
2175
+ sel.appendChild(o);
2176
+ }
2177
+ editor = sel;
2178
+ } else {
2179
+ const inp = document.createElement("input");
2180
+ inp.className = "icen-dt-editor";
2181
+ if (kind === "number") {
2182
+ inp.type = "text";
2183
+ inp.inputMode = "decimal";
2184
+ } else {
2185
+ inp.type = "text";
2186
+ }
2187
+ inp.value = String(row[col.key] ?? "");
2188
+ editor = inp;
2189
+ }
2190
+ const session = {
2191
+ rowKey,
2192
+ col,
2193
+ row,
2194
+ cell,
2195
+ editor,
2196
+ onKey: (ev) => {
2197
+ const ke = ev;
2198
+ if (ke.key === "Enter") {
2199
+ ke.preventDefault();
2200
+ ke.stopPropagation();
2201
+ commitEdit();
2202
+ } else if (ke.key === "Escape") {
2203
+ ke.preventDefault();
2204
+ ke.stopPropagation();
2205
+ cancelEdit();
2206
+ }
2207
+ },
2208
+ /* 失焦提交(点击表外/切格);值非法时 markInvalid 内会夺回焦点 */
2209
+ onBlur: () => {
2210
+ commitEdit();
2211
+ },
2212
+ onChange: () => {
2213
+ if (editing?.editor instanceof HTMLSelectElement) commitEdit();
2214
+ }
2215
+ };
2216
+ editing = session;
2217
+ cell.classList.add("is-editing");
2218
+ cell.textContent = "";
2219
+ cell.appendChild(editor);
2220
+ editor.addEventListener("keydown", session.onKey);
2221
+ editor.addEventListener("blur", session.onBlur);
2222
+ if (editor instanceof HTMLSelectElement) editor.addEventListener("change", session.onChange);
2223
+ editor.addEventListener("input", () => editor.classList.remove("is-invalid"));
2224
+ editor.focus();
2225
+ if (editor instanceof HTMLInputElement) editor.select();
2226
+ }
2227
+ function markInvalid(s) {
2228
+ s.editor.classList.add("is-invalid");
2229
+ s.editor.focus();
2230
+ }
2231
+ function commitEdit() {
2232
+ const s = editing;
2233
+ if (!s) return;
2234
+ let value;
2235
+ if (s.editor instanceof HTMLSelectElement) {
2236
+ value = s.editor.value;
2237
+ } else if (editKind(s.col) === "number") {
2238
+ const raw = s.editor.value.trim();
2239
+ const n = raw === "" ? NaN : Number(raw);
2240
+ if (Number.isNaN(n)) {
2241
+ markInvalid(s);
2242
+ return;
2243
+ }
2244
+ value = n;
2245
+ } else {
2246
+ value = s.editor.value;
2247
+ }
2248
+ editing = null;
2249
+ s.editor.removeEventListener("keydown", s.onKey);
2250
+ s.editor.removeEventListener("blur", s.onBlur);
2251
+ s.editor.removeEventListener("change", s.onChange);
2252
+ emitIcen(root, "icen:table-cell-edit", { rowKey: s.rowKey, field: s.col.key, value, row: s.row });
2253
+ opts.onCellEdit?.(s.rowKey, s.col.key, value, s.row);
2254
+ renderBody();
2255
+ refocusCell(s.rowKey, s.col.key);
2256
+ }
2257
+ function cancelEdit(silent = false) {
2258
+ const s = editing;
2259
+ if (!s) return;
2260
+ editing = null;
2261
+ s.editor.removeEventListener("keydown", s.onKey);
2262
+ s.editor.removeEventListener("blur", s.onBlur);
2263
+ s.editor.removeEventListener("change", s.onChange);
2264
+ if (!silent) {
2265
+ renderBody();
2266
+ refocusCell(s.rowKey, s.col.key);
2267
+ }
2268
+ }
2269
+ function refocusCell(rowKey, colKey) {
2270
+ const rowEl = Array.from(body.querySelectorAll(".icen-dt-row[data-icen-key]")).find((r) => r.dataset.icenKey === rowKey);
2271
+ const cell = rowEl ? Array.from(rowEl.querySelectorAll(".icen-dt-cell[data-icen-col-key]")).find((c) => c.dataset.icenColKey === colKey) : null;
2272
+ if (cell) {
2273
+ focusPos = { key: rowKey, col: colKey };
2274
+ cell.focus();
2275
+ }
2276
+ }
2277
+ function updateCell(rowKey, field, value) {
2278
+ const row = data.find((r) => keyOfRow(r) === rowKey);
2279
+ if (!row) return;
2280
+ row[field] = value;
2281
+ invalidate();
2282
+ renderAll();
2283
+ }
2284
+ function toggleGroup(label, collapsed) {
2285
+ const next = collapsed ?? groupState.get(label) !== true;
2286
+ groupState.set(label, next);
2287
+ emitIcen(root, "icen:table-group-toggle", { key: label, collapsed: next });
2288
+ invalidate();
2289
+ renderBody();
2290
+ }
2291
+ function makeGroupRow(entry) {
813
2292
  const tr = document.createElement("div");
814
- tr.className = "dt-row";
2293
+ tr.className = "icen-dt-row icen-dt-row--group";
2294
+ if (entry.collapsed) tr.classList.add("is-collapsed");
815
2295
  tr.setAttribute("role", "row");
816
2296
  tr.style.gridTemplateColumns = template();
817
2297
  if (virtual) tr.style.height = `${rowH}px`;
2298
+ const cell = document.createElement("div");
2299
+ cell.className = "icen-dt-cell icen-dt-cell--group";
2300
+ cell.setAttribute("role", "gridcell");
2301
+ cell.style.gridColumn = "1 / -1";
2302
+ const btn = document.createElement("button");
2303
+ btn.type = "button";
2304
+ btn.className = "icen-dt-group-toggle";
2305
+ btn.setAttribute("aria-expanded", String(!entry.collapsed));
2306
+ btn.setAttribute("aria-label", entry.collapsed ? t("datatable.expandGroup", { p0: entry.label }) : t("datatable.collapseGroup", { p0: entry.label }));
2307
+ btn.appendChild(createIcon("chevron-down", { size: 14 }));
2308
+ const label = document.createElement("span");
2309
+ label.className = "icen-dt-group-label";
2310
+ label.textContent = entry.label;
2311
+ const count = document.createElement("span");
2312
+ count.className = "icen-dt-group-count";
2313
+ count.textContent = t("datatable.countUnit", { p0: entry.count });
2314
+ cell.append(btn, label, count);
2315
+ const aggKeys = Object.keys(entry.aggs);
2316
+ if (aggKeys.length > 0) {
2317
+ const aggs = document.createElement("span");
2318
+ aggs.className = "icen-dt-group-aggs";
2319
+ for (const k of aggKeys) {
2320
+ const chip = document.createElement("span");
2321
+ chip.className = "icen-dt-group-agg";
2322
+ chip.textContent = `${colByKey(k)?.title ?? k} ${entry.aggs[k]}`;
2323
+ aggs.appendChild(chip);
2324
+ }
2325
+ cell.appendChild(aggs);
2326
+ }
2327
+ tr.appendChild(cell);
2328
+ tr.addEventListener("click", () => toggleGroup(entry.label));
2329
+ return tr;
2330
+ }
2331
+ function makeRow(row, flatIndex, pipeIndex, key, offsets) {
2332
+ const tr = document.createElement("div");
2333
+ tr.className = "icen-dt-row";
2334
+ tr.setAttribute("role", "row");
2335
+ tr.style.gridTemplateColumns = template();
2336
+ if (virtual) tr.style.height = `${rowH}px`;
2337
+ tr.dataset.icenRow = String(flatIndex);
2338
+ tr.dataset.icenKey = key;
818
2339
  if (selected.has(key)) tr.classList.add("is-selected");
819
2340
  if (opts.rowClassName) {
820
- const extra = opts.rowClassName(row, rowIndex);
2341
+ const extra = opts.rowClassName(row, pipeIndex);
821
2342
  if (extra) tr.classList.add(...extra.split(/\s+/).filter(Boolean));
822
2343
  }
823
2344
  if (selectable) {
824
2345
  const cell = document.createElement("div");
825
- cell.className = "dt-cell dt-cell--check";
826
- if (offsets.size > 0) {
827
- cell.classList.add("dt-cell--frozen");
2346
+ cell.className = "icen-dt-cell icen-dt-cell--check";
2347
+ cell.setAttribute("role", "gridcell");
2348
+ if (offsets.left.size > 0 || offsets.right.size > 0) {
2349
+ cell.classList.add("icen-dt-cell--frozen");
828
2350
  cell.style.left = "0px";
829
2351
  }
830
- const box = makeCheck(selected.has(key), "\u9009\u62E9\u8BE5\u884C");
2352
+ const box = makeCheck(selected.has(key), t("datatable.selectRow"));
831
2353
  let shiftClicked = false;
832
2354
  box.addEventListener("click", (ev) => {
833
2355
  shiftClicked = ev.shiftKey;
@@ -836,12 +2358,14 @@ function createTable(el, opts) {
836
2358
  box.addEventListener("change", () => {
837
2359
  const shift = shiftClicked;
838
2360
  shiftClicked = false;
839
- if (shift && lastClickedIndex >= 0 && lastClickedIndex !== rowIndex) {
840
- const rows = pipeline();
841
- const [lo, hi] = lastClickedIndex < rowIndex ? [lastClickedIndex, rowIndex] : [rowIndex, lastClickedIndex];
2361
+ if (shift && lastClickedIndex >= 0 && lastClickedIndex !== flatIndex) {
2362
+ const entries = flatEntries();
2363
+ const [lo, hi] = lastClickedIndex < flatIndex ? [lastClickedIndex, flatIndex] : [flatIndex, lastClickedIndex];
842
2364
  const willSelect = box.checked;
843
2365
  for (let i = lo; i <= hi; i++) {
844
- const k = keyOfRow(rows[i]);
2366
+ const entry = entries[i];
2367
+ if (!entry || entry.kind !== "data") continue;
2368
+ const k = keyOfRow(entry.row);
845
2369
  if (willSelect) selected.add(k);
846
2370
  else selected.delete(k);
847
2371
  }
@@ -851,51 +2375,62 @@ function createTable(el, opts) {
851
2375
  else selected.delete(key);
852
2376
  tr.classList.toggle("is-selected", box.checked);
853
2377
  }
854
- lastClickedIndex = rowIndex;
2378
+ lastClickedIndex = flatIndex;
855
2379
  emitSelection();
856
2380
  syncHeadState();
857
- renderFoot(opts.remote ? opts.totalCount ?? data.length : pipeline().length);
2381
+ renderFoot(currentTotal, pipeline().length);
858
2382
  });
859
2383
  cell.appendChild(box);
860
2384
  tr.appendChild(cell);
861
2385
  }
862
2386
  if (expandable) {
863
2387
  const cell = document.createElement("div");
864
- cell.className = "dt-cell dt-cell--expand";
2388
+ cell.className = "icen-dt-cell icen-dt-cell--expand";
2389
+ cell.setAttribute("role", "gridcell");
865
2390
  const btn = document.createElement("button");
866
2391
  btn.type = "button";
867
- btn.className = "dt-expand-btn";
868
- btn.setAttribute("aria-label", "\u5C55\u5F00\u884C");
2392
+ btn.className = "icen-dt-expand-btn";
2393
+ btn.setAttribute("aria-label", t("datatable.expandRow"));
869
2394
  btn.setAttribute("aria-expanded", String(expanded.has(key)));
870
- btn.appendChild(svgIcon(ICON_CHEVRON, 14));
2395
+ btn.appendChild(createIcon("chevron-down", { size: 14 }));
871
2396
  btn.addEventListener("click", (ev) => {
872
2397
  ev.stopPropagation();
873
2398
  if (expanded.has(key)) expanded.delete(key);
874
2399
  else expanded.add(key);
875
- emitIcen(root, "icen:table-row-toggle", { row, index: rowIndex, expanded: expanded.has(key) });
2400
+ emitIcen(root, "icen:table-row-toggle", { row, index: pipeIndex, expanded: expanded.has(key) });
876
2401
  renderBody();
877
2402
  });
878
2403
  cell.appendChild(btn);
879
2404
  tr.appendChild(cell);
880
2405
  }
2406
+ let ci = 0;
881
2407
  for (const col of cols()) {
882
2408
  const cell = document.createElement("div");
883
- cell.className = "dt-cell";
884
- if (col.align) cell.dataset.align = col.align;
885
- if (col.frozen) {
886
- cell.classList.add("dt-cell--frozen");
887
- const off = offsets.get(col.key);
888
- if (off != null) cell.style.left = `${off}px`;
2409
+ cell.className = "icen-dt-cell";
2410
+ cell.setAttribute("role", "gridcell");
2411
+ if (col.align) cell.dataset.icenAlign = col.align;
2412
+ cell.dataset.icenCol = String(ci);
2413
+ cell.dataset.icenColKey = col.key;
2414
+ cell.tabIndex = -1;
2415
+ applyFrozen(cell, col, offsets);
2416
+ fillCell(cell, col, row, pipeIndex);
2417
+ if (isEditable(col)) {
2418
+ cell.classList.add("is-editable");
2419
+ cell.setAttribute("aria-label", t("datatable.editHintWithValue", { p0: cell.textContent ?? "", p1: col.title }));
2420
+ cell.addEventListener("dblclick", (ev) => {
2421
+ ev.stopPropagation();
2422
+ startEdit(cell, row, col, key);
2423
+ });
889
2424
  }
890
- fillCell(cell, col, row, rowIndex);
891
2425
  tr.appendChild(cell);
2426
+ ci++;
892
2427
  }
893
2428
  if (opts.onRowClick) {
894
2429
  tr.classList.add("is-clickable");
895
2430
  tr.addEventListener("click", () => opts.onRowClick(row));
896
2431
  }
897
2432
  tr.addEventListener("click", () => {
898
- emitIcen(root, "icen:table-row-click", { row, index: rowIndex });
2433
+ emitIcen(root, "icen:table-row-click", { row, index: pipeIndex });
899
2434
  });
900
2435
  if (opts.contextMenu) {
901
2436
  tr.addEventListener("contextmenu", (ev) => {
@@ -910,15 +2445,213 @@ function createTable(el, opts) {
910
2445
  }
911
2446
  function makeExpandRow(row) {
912
2447
  const wrap = document.createElement("div");
913
- wrap.className = "dt-expand-row";
2448
+ wrap.className = "icen-dt-expand-row";
914
2449
  const out = expandable(row);
915
2450
  if (out instanceof Node) wrap.appendChild(out);
916
2451
  else wrap.textContent = String(out);
917
2452
  return wrap;
918
2453
  }
919
- function visibleRange(total) {
2454
+ function renderSummary() {
2455
+ if (!summaryEl) return;
2456
+ summaryEl.textContent = "";
2457
+ summaryEl.hidden = true;
2458
+ const cfg = opts.summaryRow;
2459
+ if (!cfg) return;
2460
+ const rows = pipeline();
2461
+ if (rows.length === 0) return;
2462
+ const spec = cfg === true ? Object.fromEntries(
2463
+ opts.columns.filter((c) => typeof c.aggregate === "string").map((c) => [c.key, c.aggregate])
2464
+ ) : cfg;
2465
+ if (Object.keys(spec).length === 0) return;
2466
+ summaryEl.hidden = false;
2467
+ summaryEl.style.gridTemplateColumns = template();
2468
+ const frz = frozenOffsets();
2469
+ if (selectable) {
2470
+ const cell = document.createElement("div");
2471
+ cell.className = "icen-dt-cell icen-dt-cell--check";
2472
+ cell.setAttribute("role", "gridcell");
2473
+ summaryEl.appendChild(cell);
2474
+ }
2475
+ if (expandable) {
2476
+ const cell = document.createElement("div");
2477
+ cell.className = "icen-dt-cell icen-dt-cell--expand";
2478
+ cell.setAttribute("role", "gridcell");
2479
+ summaryEl.appendChild(cell);
2480
+ }
2481
+ for (const col of cols()) {
2482
+ const cell = document.createElement("div");
2483
+ cell.className = "icen-dt-cell icen-dt-cell--summary";
2484
+ cell.setAttribute("role", "gridcell");
2485
+ if (col.align) cell.dataset.icenAlign = col.align;
2486
+ applyFrozen(cell, col, frz);
2487
+ const s = spec[col.key];
2488
+ if (s === "label") cell.textContent = t("datatable.totalLabel");
2489
+ else if (s) cell.textContent = computeAggregates(rows, [{ ...col, aggregate: s }])[col.key] ?? "";
2490
+ summaryEl.appendChild(cell);
2491
+ }
2492
+ }
2493
+ function onBodyFocusIn(ev) {
2494
+ const cell = ev.target.closest(".icen-dt-cell");
2495
+ if (!cell || !body.contains(cell) || cell.dataset.icenCol == null) return;
2496
+ if (cell.classList.contains("is-editing")) return;
2497
+ const tr = cell.parentElement;
2498
+ focusPos = { key: tr?.dataset.icenKey ?? "", col: cell.dataset.icenColKey ?? "" };
2499
+ body.querySelectorAll(".icen-dt-cell[data-icen-col]").forEach((c) => {
2500
+ c.tabIndex = c === cell ? 0 : -1;
2501
+ });
2502
+ }
2503
+ function syncNavFocus() {
2504
+ const cells = body.querySelectorAll(".icen-dt-cell[data-icen-col]");
2505
+ let marked = false;
2506
+ cells.forEach((c) => {
2507
+ const tr = c.parentElement;
2508
+ const match = focusPos != null && tr?.dataset.icenKey === focusPos.key && c.dataset.icenColKey === focusPos.col;
2509
+ c.tabIndex = match ? 0 : -1;
2510
+ if (match) marked = true;
2511
+ });
2512
+ if (!marked) {
2513
+ const first = body.querySelector(".icen-dt-cell[data-icen-col]");
2514
+ if (first) first.tabIndex = 0;
2515
+ }
2516
+ }
2517
+ function navStep() {
2518
+ if (virtual) return Math.max(1, Math.floor((scroll.clientHeight || rowH * 10) / rowH));
2519
+ return Math.max(1, pageSize);
2520
+ }
2521
+ function findNavCell(r, c, dir) {
2522
+ let nr = r;
2523
+ while (nr >= 0 && nr < navTotal) {
2524
+ const el2 = body.querySelector(
2525
+ `.icen-dt-row[data-icen-row="${nr}"] .icen-dt-cell[data-icen-col="${c}"]`
2526
+ );
2527
+ if (el2) return el2;
2528
+ if (dir === 0) return null;
2529
+ nr += dir;
2530
+ }
2531
+ return null;
2532
+ }
2533
+ function onBodyKeydown(ev) {
2534
+ if (editing) return;
2535
+ const t2 = ev.target;
2536
+ if (t2 instanceof HTMLInputElement || t2 instanceof HTMLSelectElement || t2 instanceof HTMLTextAreaElement) return;
2537
+ const cell = t2 instanceof Element ? t2.closest(".icen-dt-cell") : null;
2538
+ if (!cell || cell.dataset.icenCol == null) return;
2539
+ if ((ev.ctrlKey || ev.metaKey) && (ev.key === "c" || ev.key === "C")) {
2540
+ copyFocusedCell(cell);
2541
+ return;
2542
+ }
2543
+ const rowEl = cell.parentElement;
2544
+ const r = Number(rowEl?.dataset.icenRow ?? -1);
2545
+ const c = Number(cell.dataset.icenCol);
2546
+ const colCount = cols().length;
2547
+ let nr = r;
2548
+ let nc = c;
2549
+ let dir = 0;
2550
+ switch (ev.key) {
2551
+ case "ArrowLeft":
2552
+ nc = c - 1;
2553
+ break;
2554
+ case "ArrowRight":
2555
+ nc = c + 1;
2556
+ break;
2557
+ case "ArrowUp":
2558
+ nr = r - 1;
2559
+ dir = -1;
2560
+ break;
2561
+ case "ArrowDown":
2562
+ nr = r + 1;
2563
+ dir = 1;
2564
+ break;
2565
+ case "Home":
2566
+ nc = 0;
2567
+ break;
2568
+ case "End":
2569
+ nc = colCount - 1;
2570
+ break;
2571
+ case "PageUp":
2572
+ nr = r - navStep();
2573
+ dir = -1;
2574
+ break;
2575
+ case "PageDown":
2576
+ nr = r + navStep();
2577
+ dir = 1;
2578
+ break;
2579
+ case "Enter": {
2580
+ const key = rowEl?.dataset.icenKey ?? "";
2581
+ const row = data.find((rr) => keyOfRow(rr) === key);
2582
+ const col = cols()[c];
2583
+ if (row && col && isEditable(col)) {
2584
+ ev.preventDefault();
2585
+ startEdit(cell, row, col, key);
2586
+ }
2587
+ return;
2588
+ }
2589
+ default:
2590
+ return;
2591
+ }
2592
+ ev.preventDefault();
2593
+ if (nc < 0) nc = 0;
2594
+ if (nc >= colCount) nc = colCount - 1;
2595
+ if (nr < 0) nr = 0;
2596
+ const maxRow = navTotal - 1;
2597
+ if (nr > maxRow) nr = maxRow;
2598
+ let target = findNavCell(nr, nc, dir);
2599
+ if (!target && virtual) {
2600
+ scroll.scrollTop = Math.max(0, Math.min(nr, maxRow)) * rowH;
2601
+ onScroll();
2602
+ target = findNavCell(nr, nc, dir);
2603
+ } else if (!target && opts.pagination !== false && !opts.remote) {
2604
+ const pages = Math.max(1, Math.ceil(navTotal / pageSize));
2605
+ const want = clampN(Math.floor(nr / pageSize) + 1, 1, pages);
2606
+ if (want !== page) {
2607
+ page = want;
2608
+ emitIcen(root, "icen:table-page-change", { page, pageSize });
2609
+ opts.onPageChange?.(page, pageSize);
2610
+ renderBody();
2611
+ target = findNavCell(nr, nc, 0);
2612
+ }
2613
+ }
2614
+ target?.focus();
2615
+ }
2616
+ function copyFocusedCell(cell) {
2617
+ let text;
2618
+ if (selectable && selected.size > 0) {
2619
+ const vis = cols();
2620
+ const rows = data.filter((r) => selected.has(keyOfRow(r)));
2621
+ text = rows.map((row) => vis.map((col) => tsvSafe(String(row[col.key] ?? ""))).join(" ")).join("\n");
2622
+ } else {
2623
+ text = tsvSafe(cell.textContent ?? "");
2624
+ }
2625
+ void writeClipboard(text);
2626
+ }
2627
+ function tsvSafe(s) {
2628
+ return s.replace(/[\t\r\n]+/g, " ");
2629
+ }
2630
+ function writeClipboard(text) {
2631
+ const nav = typeof navigator !== "undefined" ? navigator : void 0;
2632
+ if (nav?.clipboard && typeof nav.clipboard.writeText === "function") {
2633
+ nav.clipboard.writeText(text).catch(() => fallbackCopy(text));
2634
+ return;
2635
+ }
2636
+ fallbackCopy(text);
2637
+ }
2638
+ function fallbackCopy(text) {
2639
+ try {
2640
+ const ta = document.createElement("textarea");
2641
+ ta.value = text;
2642
+ ta.style.position = "fixed";
2643
+ ta.style.opacity = "0";
2644
+ document.body.appendChild(ta);
2645
+ ta.select();
2646
+ document.execCommand("copy");
2647
+ ta.remove();
2648
+ } catch {
2649
+ }
2650
+ }
2651
+ let currentTotal = 0;
2652
+ function visibleRange(total, avail) {
920
2653
  if (!virtual) {
921
- if (opts.remote || opts.pagination === false) return [0, total];
2654
+ if (opts.remote || opts.pagination === false) return [0, Math.min(total, avail)];
922
2655
  const start2 = (page - 1) * pageSize;
923
2656
  return [start2, Math.min(total, start2 + pageSize)];
924
2657
  }
@@ -929,33 +2662,43 @@ function createTable(el, opts) {
929
2662
  return [start, end];
930
2663
  }
931
2664
  function renderBody() {
2665
+ if (editing) cancelEdit(true);
932
2666
  const rows = pipeline();
933
- const total = opts.remote ? opts.totalCount ?? data.length : rows.length;
2667
+ const entries = groupFn ? flatEntries() : null;
2668
+ const total = entries ? entries.length : opts.remote ? opts.totalCount ?? data.length : rows.length;
2669
+ if (!opts.remote && opts.pagination !== false) {
2670
+ const pages = Math.max(1, Math.ceil(total / pageSize));
2671
+ if (page > pages) page = pages;
2672
+ }
2673
+ navTotal = entries ? entries.length : rows.length;
2674
+ currentTotal = total;
934
2675
  const keepTop = virtual ? scroll.scrollTop : 0;
935
2676
  body.textContent = "";
936
2677
  if (opts.loading) {
937
2678
  for (let i = 0; i < Math.min(pageSize, 8); i++) {
938
2679
  const sk = document.createElement("div");
939
- sk.className = "dt-skeleton-row";
2680
+ sk.className = "icen-dt-skeleton-row";
940
2681
  const bar = document.createElement("div");
941
- bar.className = "skeleton";
2682
+ bar.className = "icen-skeleton";
942
2683
  bar.style.height = "14px";
943
2684
  bar.style.width = `${88 - i % 3 * 14}%`;
944
2685
  sk.appendChild(bar);
945
2686
  body.appendChild(sk);
946
2687
  }
947
- renderFoot(total);
2688
+ renderFoot(total, rows.length);
2689
+ renderSummary();
948
2690
  return;
949
2691
  }
950
2692
  if (total === 0) {
951
2693
  const empty = document.createElement("div");
952
- empty.className = "dt-empty";
953
- empty.textContent = opts.emptyLabel ?? "\u6682\u65E0\u6570\u636E";
2694
+ empty.className = "icen-dt-empty";
2695
+ empty.textContent = opts.emptyLabel ?? t("datatable.empty");
954
2696
  body.appendChild(empty);
955
- renderFoot(total);
2697
+ renderFoot(total, rows.length);
2698
+ renderSummary();
956
2699
  return;
957
2700
  }
958
- const [start, end] = visibleRange(total);
2701
+ const [start, end] = visibleRange(total, rows.length);
959
2702
  const frag = document.createDocumentFragment();
960
2703
  const offsets = frozenOffsets();
961
2704
  if (virtual && start > 0) {
@@ -964,10 +2707,21 @@ function createTable(el, opts) {
964
2707
  frag.appendChild(top);
965
2708
  }
966
2709
  for (let i = start; i < end; i++) {
967
- const row = rows[i];
968
- const key = keyOfRow(row);
969
- frag.appendChild(makeRow(row, i, key, offsets));
970
- if (expandable && expanded.has(key)) frag.appendChild(makeExpandRow(row));
2710
+ if (entries) {
2711
+ const entry = entries[i];
2712
+ if (entry.kind === "group") {
2713
+ frag.appendChild(makeGroupRow(entry));
2714
+ continue;
2715
+ }
2716
+ const key = keyOfRow(entry.row);
2717
+ frag.appendChild(makeRow(entry.row, i, entry.pipeIndex, key, offsets));
2718
+ if (expandable && expanded.has(key)) frag.appendChild(makeExpandRow(entry.row));
2719
+ } else {
2720
+ const row = rows[i];
2721
+ const key = keyOfRow(row);
2722
+ frag.appendChild(makeRow(row, i, i, key, offsets));
2723
+ if (expandable && expanded.has(key)) frag.appendChild(makeExpandRow(row));
2724
+ }
971
2725
  }
972
2726
  if (virtual && end < total) {
973
2727
  const bottom = document.createElement("div");
@@ -976,22 +2730,24 @@ function createTable(el, opts) {
976
2730
  }
977
2731
  body.appendChild(frag);
978
2732
  if (virtual) scroll.scrollTop = keepTop;
979
- renderFoot(total);
2733
+ syncNavFocus();
2734
+ renderFoot(total, rows.length);
2735
+ renderSummary();
980
2736
  }
981
- function renderFoot(total) {
2737
+ function renderFoot(total, dataCount = total) {
982
2738
  foot.textContent = "";
983
2739
  const stat = document.createElement("span");
984
- stat.className = "dt-stat";
985
- stat.textContent = `\u5171 ${total} \u6761`;
2740
+ stat.className = "icen-dt-stat";
2741
+ stat.textContent = t("datatable.totalCount", { p0: dataCount });
986
2742
  foot.appendChild(stat);
987
2743
  if (selectable && selected.size > 0) {
988
2744
  const sel = document.createElement("span");
989
- sel.className = "dt-stat dt-stat--sel";
990
- sel.textContent = `\u5DF2\u9009 ${selected.size} \u9879`;
2745
+ sel.className = "icen-dt-stat icen-dt-stat--sel";
2746
+ sel.textContent = t("datatable.selectedCount", { p0: selected.size });
991
2747
  const clear = document.createElement("button");
992
2748
  clear.type = "button";
993
- clear.className = "dt-clear-sel";
994
- clear.textContent = "\u6E05\u7A7A";
2749
+ clear.className = "icen-dt-clear-sel";
2750
+ clear.textContent = t("datatable.clear");
995
2751
  clear.addEventListener("click", () => {
996
2752
  selected.clear();
997
2753
  emitSelection();
@@ -1004,15 +2760,25 @@ function createTable(el, opts) {
1004
2760
  if (virtual || opts.pagination === false || total <= pageSize) return;
1005
2761
  const pages = Math.ceil(total / pageSize);
1006
2762
  const pager = document.createElement("nav");
1007
- pager.className = "dt-pager";
1008
- pager.setAttribute("aria-label", "\u5206\u9875");
2763
+ pager.className = "icen-dt-pager";
2764
+ {
2765
+ const base = t("datatable.paginationAria");
2766
+ const used = /* @__PURE__ */ new Set();
2767
+ for (const el2 of document.querySelectorAll(".icen-dt-pager[aria-label]")) {
2768
+ if (!root.contains(el2)) used.add(el2.getAttribute("aria-label") ?? "");
2769
+ }
2770
+ let label = base, n = 2;
2771
+ while (used.has(label)) label = `${base} ${n++}`;
2772
+ pager.setAttribute("aria-label", label);
2773
+ }
1009
2774
  const sizeSel = document.createElement("select");
1010
- sizeSel.className = "dt-page-size";
1011
- sizeSel.setAttribute("aria-label", "\u6BCF\u9875\u6761\u6570");
1012
- for (const s of pageSizes) {
2775
+ sizeSel.className = "icen-dt-page-size";
2776
+ sizeSel.setAttribute("aria-label", t("datatable.pageSizeAria"));
2777
+ const sizeOptions = pageSizes.includes(pageSize) ? pageSizes : [...pageSizes, pageSize].sort((a, b) => a - b);
2778
+ for (const s of sizeOptions) {
1013
2779
  const o = document.createElement("option");
1014
2780
  o.value = String(s);
1015
- o.textContent = `${s} \u6761/\u9875`;
2781
+ o.textContent = t("pagination.pageSize", { p0: s });
1016
2782
  if (s === pageSize) o.selected = true;
1017
2783
  sizeSel.appendChild(o);
1018
2784
  }
@@ -1029,10 +2795,11 @@ function createTable(el, opts) {
1029
2795
  const pageBtn = (label, target, opts2 = {}) => {
1030
2796
  const b = document.createElement("button");
1031
2797
  b.type = "button";
1032
- b.className = "dt-page-btn";
2798
+ b.className = "icen-dt-page-btn";
1033
2799
  if (opts2.active) b.classList.add("is-active");
1034
2800
  b.disabled = opts2.disabled === true;
1035
- b.textContent = label;
2801
+ if (opts2.icon) b.append(createIcon(opts2.icon));
2802
+ else b.textContent = label;
1036
2803
  if (opts2.aria) b.setAttribute("aria-label", opts2.aria);
1037
2804
  b.addEventListener("click", () => {
1038
2805
  page = target;
@@ -1042,7 +2809,7 @@ function createTable(el, opts) {
1042
2809
  });
1043
2810
  return b;
1044
2811
  };
1045
- pager.appendChild(pageBtn("\u2039", page - 1, { disabled: page <= 1, aria: "\u4E0A\u4E00\u9875" }));
2812
+ pager.appendChild(pageBtn("", page - 1, { icon: "chevron-left", disabled: page <= 1, aria: t("pagination.prev") }));
1046
2813
  const win = [];
1047
2814
  for (let p = 1; p <= pages; p++) {
1048
2815
  if (p === 1 || p === pages || Math.abs(p - page) <= 2) win.push(p);
@@ -1051,14 +2818,14 @@ function createTable(el, opts) {
1051
2818
  for (const p of win) {
1052
2819
  if (p - last > 1) {
1053
2820
  const dots = document.createElement("span");
1054
- dots.className = "dt-page-dots";
2821
+ dots.className = "icen-dt-page-dots";
1055
2822
  dots.textContent = "\u2026";
1056
2823
  pager.appendChild(dots);
1057
2824
  }
1058
2825
  pager.appendChild(pageBtn(String(p), p, { active: p === page }));
1059
2826
  last = p;
1060
2827
  }
1061
- pager.appendChild(pageBtn("\u203A", page + 1, { disabled: page >= pages, aria: "\u4E0B\u4E00\u9875" }));
2828
+ pager.appendChild(pageBtn("", page + 1, { icon: "chevron-right", disabled: page >= pages, aria: t("pagination.next") }));
1062
2829
  foot.appendChild(pager);
1063
2830
  }
1064
2831
  let searchTimer = 0;
@@ -1078,10 +2845,12 @@ function createTable(el, opts) {
1078
2845
  renderBody();
1079
2846
  }
1080
2847
  if (virtual) scroll.addEventListener("scroll", onScroll, { passive: true });
2848
+ body.addEventListener("keydown", onBodyKeydown);
2849
+ body.addEventListener("focusin", onBodyFocusIn);
1081
2850
  function onDocPointerDown(ev) {
1082
2851
  if (!openPanel) return;
1083
- const t = ev.target;
1084
- if (t instanceof Node && (openPanel.el.contains(t) || headRow.contains(t) || toolbar?.contains(t))) return;
2852
+ const t2 = ev.target;
2853
+ if (t2 instanceof Node && (openPanel.el.contains(t2) || headRow.contains(t2) || toolbar?.contains(t2))) return;
1085
2854
  closeFilterPanel();
1086
2855
  }
1087
2856
  document.addEventListener("pointerdown", onDocPointerDown, true);
@@ -1098,6 +2867,7 @@ function createTable(el, opts) {
1098
2867
  if (destroyed) return;
1099
2868
  renderHead();
1100
2869
  renderBody();
2870
+ syncFrozenWidths();
1101
2871
  }
1102
2872
  rekey();
1103
2873
  renderAll();
@@ -1118,11 +2888,52 @@ function createTable(el, opts) {
1118
2888
  opts.onPageChange?.(page, pageSize);
1119
2889
  renderAll();
1120
2890
  }
2891
+ function hasFluidFrozen() {
2892
+ return cols().some((c) => frozenSide(c) != null && !/^(\d+(?:\.\d+)?)px/.test(colWidths.get(c.key) ?? c.width ?? ""));
2893
+ }
2894
+ function syncFrozenWidths() {
2895
+ if (!hasFluidFrozen()) return;
2896
+ const visible = cols();
2897
+ const headCells = Array.from(headRow.children);
2898
+ const lead = headCells.length - visible.length;
2899
+ const left = /* @__PURE__ */ new Map();
2900
+ const right = /* @__PURE__ */ new Map();
2901
+ let acc = headCells.slice(0, lead).reduce((s, c) => s + c.offsetWidth, 0);
2902
+ for (let i = 0; i < visible.length; i++) {
2903
+ const c = visible[i];
2904
+ if (frozenSide(c) === "left") left.set(c.key, acc);
2905
+ acc += headCells[lead + i]?.offsetWidth ?? 0;
2906
+ }
2907
+ let accR = 0;
2908
+ for (let i = visible.length - 1; i >= 0; i--) {
2909
+ const c = visible[i];
2910
+ if (frozenSide(c) === "right") right.set(c.key, accR);
2911
+ accR += headCells[lead + i]?.offsetWidth ?? 0;
2912
+ }
2913
+ const rows = [headRow, ...summaryEl ? [summaryEl] : [], ...Array.from(body.querySelectorAll(".icen-dt-row"))];
2914
+ for (const row of rows) {
2915
+ const cells = Array.from(row.children);
2916
+ if (cells.length !== headCells.length) continue;
2917
+ cells.forEach((cell, i) => {
2918
+ const col = i >= lead ? visible[i - lead] : void 0;
2919
+ if (!col) return;
2920
+ const l = left.get(col.key);
2921
+ if (l != null && cell.classList.contains("icen-dt-cell--frozen")) cell.style.left = `${l}px`;
2922
+ const r = right.get(col.key);
2923
+ if (r != null && cell.classList.contains("icen-dt-cell--frozen-right")) cell.style.right = `${r}px`;
2924
+ });
2925
+ }
2926
+ }
1121
2927
  return {
1122
2928
  setPage,
1123
2929
  setPageSize,
1124
2930
  setData(next) {
2931
+ if (editing) cancelEdit(true);
1125
2932
  data = next;
2933
+ if (typeof opts.rowKey !== "function" && typeof opts.rowKey !== "string" && selected.size > 0) {
2934
+ selected.clear();
2935
+ emitSelection();
2936
+ }
1126
2937
  rekey();
1127
2938
  invalidate();
1128
2939
  page = 1;
@@ -1151,12 +2962,16 @@ function createTable(el, opts) {
1151
2962
  renderAll();
1152
2963
  },
1153
2964
  setSort(key, dir = "asc") {
1154
- sortKey = key;
1155
- sortDir = dir;
1156
- invalidate();
1157
- opts.onSortChange?.(sortKey, sortDir);
1158
- renderAll();
2965
+ applySorts(key ? sanitizeSorts([{ key, dir }]) : [], dir, false);
1159
2966
  },
2967
+ getSorts() {
2968
+ return sorts.map((s) => ({ ...s }));
2969
+ },
2970
+ setSorts(next) {
2971
+ applySorts(sanitizeSorts(next ?? []), "asc", false);
2972
+ },
2973
+ moveColumn,
2974
+ updateCell,
1160
2975
  getData() {
1161
2976
  return pipeline();
1162
2977
  },
@@ -1181,6 +2996,11 @@ function createTable(el, opts) {
1181
2996
  destroyed = true;
1182
2997
  window.clearTimeout(searchTimer);
1183
2998
  closeFilterPanel();
2999
+ if (editing) cancelEdit(true);
3000
+ if (drag) {
3001
+ drag.off();
3002
+ drag = null;
3003
+ }
1184
3004
  searchInput?.removeEventListener("input", onSearch);
1185
3005
  if (virtual) scroll.removeEventListener("scroll", onScroll);
1186
3006
  document.removeEventListener("pointerdown", onDocPointerDown, true);
@@ -1190,5 +3010,6 @@ function createTable(el, opts) {
1190
3010
  };
1191
3011
  }
1192
3012
  export {
3013
+ computeAggregates,
1193
3014
  createTable
1194
3015
  };