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