@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
@@ -0,0 +1,4 @@
1
+ /** 事件委托接入一个作用域(缺省 document,动态插入同样生效)。 */
2
+ declare function initTooltip(root?: ParentNode): () => void;
3
+
4
+ export { initTooltip };
@@ -0,0 +1,378 @@
1
+ // src/behaviors/popover.ts
2
+ var DEFAULT_MIN_WIDTH = 220;
3
+ var DEFAULT_MAX_WIDTH = 420;
4
+ var DEFAULT_MIN_HEIGHT = 120;
5
+ var DEFAULT_MAX_HEIGHT = 420;
6
+ function clamp(value, min, max) {
7
+ if (max < min) return min;
8
+ return Math.min(max, Math.max(min, value));
9
+ }
10
+ function chooseSide(preferredSide, availableTop, availableBottom, desiredHeight) {
11
+ const preferredSpace = preferredSide === "top" ? availableTop : availableBottom;
12
+ const oppositeSpace = preferredSide === "top" ? availableBottom : availableTop;
13
+ if (preferredSpace >= desiredHeight) return preferredSide;
14
+ if (oppositeSpace >= desiredHeight) return preferredSide === "top" ? "bottom" : "top";
15
+ if (preferredSpace >= oppositeSpace) return preferredSide;
16
+ return preferredSide === "top" ? "bottom" : "top";
17
+ }
18
+ function horizontalAnchor(anchor, width, align) {
19
+ if (align === "center") return anchor.left + anchor.width / 2 - width / 2;
20
+ if (align === "end") return anchor.right - width;
21
+ return anchor.left;
22
+ }
23
+ function computePopoverLayout(anchor, viewport, opts = {}) {
24
+ const margin = opts.margin ?? 12;
25
+ const offset = opts.offset ?? 8;
26
+ const preferredSide = opts.side ?? "top";
27
+ const align = opts.align ?? "start";
28
+ if (preferredSide === "left" || preferredSide === "right") {
29
+ const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
30
+ const availableLeft = Math.max(0, anchor.left - margin - offset);
31
+ const availableRight = Math.max(0, viewport.width - anchor.right - margin - offset);
32
+ const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= minWidth2 ? preferredSide : preferredSide === "left" ? "right" : "left";
33
+ const maxWidth2 = Math.min(
34
+ Math.max(opts.maxWidth ?? DEFAULT_MAX_WIDTH, minWidth2),
35
+ side2 === "left" ? availableLeft : availableRight
36
+ );
37
+ const width2 = minWidth2;
38
+ const left2 = clamp(
39
+ side2 === "left" ? anchor.left - offset - width2 : anchor.right + offset,
40
+ margin,
41
+ viewport.width - margin - width2
42
+ );
43
+ const availableHeight2 = Math.max(80, viewport.height - margin * 2);
44
+ const maxHeight2 = Math.min(opts.maxHeight ?? DEFAULT_MAX_HEIGHT, availableHeight2);
45
+ const desired = clamp(opts.contentHeightHint ?? Math.min(anchor.height, maxHeight2), 40, maxHeight2);
46
+ const anchorTop = align === "center" ? anchor.top + anchor.height / 2 - desired / 2 : align === "end" ? anchor.bottom - desired : anchor.top;
47
+ const top2 = clamp(anchorTop, margin, viewport.height - margin - desired);
48
+ return { side: side2, left: left2, top: top2, width: width2, maxHeight: maxHeight2 };
49
+ }
50
+ const availableWidth = Math.max(80, viewport.width - margin * 2);
51
+ const requestedMinWidth = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
52
+ const requestedMaxWidth = Math.max(requestedMinWidth, opts.maxWidth ?? DEFAULT_MAX_WIDTH);
53
+ const maxWidth = Math.min(requestedMaxWidth, availableWidth);
54
+ const minWidth = Math.min(requestedMinWidth, maxWidth);
55
+ const availableTop = Math.max(0, anchor.top - margin - offset);
56
+ const availableBottom = Math.max(0, viewport.height - anchor.bottom - margin - offset);
57
+ const availableHeight = Math.max(80, viewport.height - margin * 2);
58
+ const minHeight = Math.min(Math.max(80, opts.minHeight ?? DEFAULT_MIN_HEIGHT), availableHeight);
59
+ const requestedMaxHeight = Math.max(minHeight, opts.maxHeight ?? DEFAULT_MAX_HEIGHT);
60
+ const fallbackHeight = Math.min(260, requestedMaxHeight);
61
+ const contentHeight = opts.contentHeightHint != null && opts.contentHeightHint > 0 ? opts.contentHeightHint : fallbackHeight;
62
+ const desiredHeight = clamp(contentHeight, minHeight, Math.min(requestedMaxHeight, availableHeight));
63
+ const side = chooseSide(preferredSide, availableTop, availableBottom, desiredHeight);
64
+ const sideSpace = side === "top" ? availableTop : availableBottom;
65
+ const maxHeight = Math.min(
66
+ requestedMaxHeight,
67
+ Math.max(80, sideSpace || Math.max(availableTop, availableBottom)),
68
+ availableHeight
69
+ );
70
+ const positionedHeight = clamp(desiredHeight, 40, maxHeight);
71
+ const width = align === "stretch" ? clamp(anchor.width, minWidth, maxWidth) : maxWidth;
72
+ const left = clamp(horizontalAnchor(anchor, width, align), margin, viewport.width - margin - width);
73
+ const desiredTop = side === "top" ? anchor.top - offset - positionedHeight : anchor.bottom + offset;
74
+ const top = clamp(desiredTop, margin, viewport.height - margin - positionedHeight);
75
+ return { side, left, top, width, maxHeight };
76
+ }
77
+
78
+ // src/behaviors/tooltip.ts
79
+ var HOVER_DELAY_MS = 400;
80
+ var LEAVE_TIMEOUT_MS = 240;
81
+ var POINTER_LEAVE_DELAY_MS = 80;
82
+ var OFFSET_PX = 6;
83
+ var VIEWPORT_MARGIN_PX = 8;
84
+ var WATCHED_ATTRS = ["data-icen-tooltip", "data-icen-tooltip-side", "data-icen-tooltip-align", "data-icen-tooltip-multiline"];
85
+ var scopes = /* @__PURE__ */ new WeakMap();
86
+ var handled = /* @__PURE__ */ new WeakSet();
87
+ var bubble = null;
88
+ var current = null;
89
+ var dismissed = /* @__PURE__ */ new Set();
90
+ var triggerOwners = /* @__PURE__ */ new WeakMap();
91
+ var closeTimer = null;
92
+ var pending = null;
93
+ var leaving = null;
94
+ var observer = null;
95
+ var sequence = 0;
96
+ function textOf(trigger) {
97
+ return trigger.getAttribute("data-icen-tooltip")?.trim() ?? "";
98
+ }
99
+ function sideOf(trigger) {
100
+ const side = trigger.getAttribute("data-icen-tooltip-side");
101
+ return side === "bottom" || side === "left" || side === "right" ? side : "top";
102
+ }
103
+ function alignOf(trigger) {
104
+ const align = trigger.getAttribute("data-icen-tooltip-align");
105
+ return align === "start" || align === "end" ? align : "center";
106
+ }
107
+ function focusVisible(el) {
108
+ try {
109
+ return el.matches(":focus-visible");
110
+ } catch {
111
+ return true;
112
+ }
113
+ }
114
+ function triggerFrom(target) {
115
+ return target instanceof Element ? target.closest("[data-icen-tooltip]") : null;
116
+ }
117
+ function cancelPending() {
118
+ if (!pending) return;
119
+ window.clearTimeout(pending.timer);
120
+ pending.trigger.removeAttribute("data-icen-tooltip-live");
121
+ pending = null;
122
+ }
123
+ function cancelLeaving() {
124
+ if (!leaving) return;
125
+ window.clearTimeout(leaving.timer);
126
+ leaving.node.classList.add("is-open");
127
+ leaving = null;
128
+ }
129
+ function release(trigger) {
130
+ trigger.removeAttribute("data-icen-tooltip-live");
131
+ const tokens = (trigger.getAttribute("aria-describedby") ?? "").split(/\s+/).filter((id) => id && id !== bubble?.id);
132
+ if (tokens.length) trigger.setAttribute("aria-describedby", tokens.join(" "));
133
+ else trigger.removeAttribute("aria-describedby");
134
+ }
135
+ function cancelClose() {
136
+ if (closeTimer !== null) window.clearTimeout(closeTimer);
137
+ closeTimer = null;
138
+ }
139
+ function clearDismissed(trigger) {
140
+ if (!dismissed.delete(trigger)) return;
141
+ if (current !== trigger && pending?.trigger !== trigger) trigger.removeAttribute("data-icen-tooltip-live");
142
+ }
143
+ function scheduleClose() {
144
+ cancelClose();
145
+ closeTimer = window.setTimeout(() => {
146
+ closeTimer = null;
147
+ if (current && document.activeElement !== current) hide(current);
148
+ }, POINTER_LEAVE_DELAY_MS);
149
+ }
150
+ function unwatch() {
151
+ window.removeEventListener("scroll", onViewportScroll, true);
152
+ window.removeEventListener("resize", onViewportResize);
153
+ observer?.disconnect();
154
+ observer = null;
155
+ }
156
+ function removeBubble(node) {
157
+ node.remove();
158
+ if (bubble === node) bubble = null;
159
+ }
160
+ function hide(trigger, opts) {
161
+ cancelClose();
162
+ const waiting = pending?.trigger;
163
+ cancelPending();
164
+ if (waiting && opts?.suppressFallback) {
165
+ dismissed.add(waiting);
166
+ waiting.setAttribute("data-icen-tooltip-live", "");
167
+ }
168
+ const active = current;
169
+ if (!active || trigger && active !== trigger) return;
170
+ current = null;
171
+ release(active);
172
+ if (opts?.suppressFallback) {
173
+ dismissed.add(active);
174
+ active.setAttribute("data-icen-tooltip-live", "");
175
+ }
176
+ unwatch();
177
+ if (!bubble) return;
178
+ const node = bubble;
179
+ if (opts?.instant) {
180
+ cancelLeaving();
181
+ removeBubble(node);
182
+ return;
183
+ }
184
+ node.classList.remove("is-open");
185
+ leaving = {
186
+ node,
187
+ timer: window.setTimeout(() => {
188
+ if (leaving?.node === node) leaving = null;
189
+ removeBubble(node);
190
+ }, LEAVE_TIMEOUT_MS)
191
+ };
192
+ }
193
+ function layout() {
194
+ if (!current || !bubble) return;
195
+ const anchor = current.getBoundingClientRect();
196
+ const width = bubble.offsetWidth;
197
+ const height = bubble.offsetHeight;
198
+ const out = computePopoverLayout(anchor, { width: window.innerWidth, height: window.innerHeight }, {
199
+ side: sideOf(current),
200
+ align: alignOf(current),
201
+ offset: OFFSET_PX,
202
+ margin: VIEWPORT_MARGIN_PX,
203
+ minWidth: width,
204
+ maxWidth: width,
205
+ minHeight: height,
206
+ maxHeight: height,
207
+ contentHeightHint: height
208
+ });
209
+ bubble.style.left = `${out.left}px`;
210
+ bubble.style.top = `${out.top}px`;
211
+ bubble.dataset.icenSide = out.side;
212
+ bubble.style.visibility = "";
213
+ const node = bubble, trigger = current;
214
+ requestAnimationFrame(() => {
215
+ if (bubble === node && current === trigger) node.classList.add("is-open");
216
+ });
217
+ }
218
+ function watch() {
219
+ unwatch();
220
+ window.addEventListener("scroll", onViewportScroll, { capture: true, passive: true });
221
+ window.addEventListener("resize", onViewportResize, { passive: true });
222
+ observer = new MutationObserver(() => {
223
+ if (!current) return;
224
+ const text = textOf(current);
225
+ if (!current.isConnected || !text) {
226
+ hide(null, { instant: true });
227
+ return;
228
+ }
229
+ if (bubble) {
230
+ if (bubble.textContent !== text) bubble.textContent = text;
231
+ bubble.classList.toggle("is-multiline", current.getAttribute("data-icen-tooltip-multiline") === "true");
232
+ }
233
+ layout();
234
+ });
235
+ observer.observe(document.documentElement, {
236
+ subtree: true,
237
+ childList: true,
238
+ attributes: true,
239
+ attributeFilter: WATCHED_ATTRS
240
+ });
241
+ }
242
+ function onViewportScroll() {
243
+ hide(null, { instant: true, suppressFallback: true });
244
+ }
245
+ function onViewportResize() {
246
+ hide(null, { instant: true, suppressFallback: true });
247
+ }
248
+ function show(trigger) {
249
+ if (!trigger.isConnected) return;
250
+ const text = textOf(trigger);
251
+ if (!text) return;
252
+ cancelPending();
253
+ cancelClose();
254
+ cancelLeaving();
255
+ if (current && current !== trigger) release(current);
256
+ current = trigger;
257
+ trigger.setAttribute("data-icen-tooltip-live", "");
258
+ if (!bubble) {
259
+ bubble = document.createElement("div");
260
+ bubble.className = "icen-tooltip";
261
+ bubble.setAttribute("role", "tooltip");
262
+ bubble.id = `icen-tooltip-${++sequence}`;
263
+ bubble.addEventListener("pointerenter", cancelClose);
264
+ bubble.addEventListener("pointerleave", (event) => {
265
+ if (current && event.relatedTarget instanceof Node && current.contains(event.relatedTarget)) return;
266
+ scheduleClose();
267
+ });
268
+ }
269
+ bubble.textContent = text;
270
+ bubble.classList.toggle("is-multiline", trigger.getAttribute("data-icen-tooltip-multiline") === "true");
271
+ if (!bubble.isConnected) {
272
+ bubble.style.visibility = "hidden";
273
+ document.body.appendChild(bubble);
274
+ }
275
+ const tokens = new Set((trigger.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean));
276
+ tokens.add(bubble.id);
277
+ trigger.setAttribute("aria-describedby", [...tokens].join(" "));
278
+ layout();
279
+ watch();
280
+ }
281
+ function markPending(trigger) {
282
+ for (const stale of dismissed) if (!stale.isConnected) clearDismissed(stale);
283
+ cancelClose();
284
+ cancelPending();
285
+ if (current === trigger) return;
286
+ trigger.setAttribute("data-icen-tooltip-live", "");
287
+ pending = {
288
+ trigger,
289
+ timer: window.setTimeout(() => {
290
+ pending = null;
291
+ show(trigger);
292
+ }, HOVER_DELAY_MS)
293
+ };
294
+ }
295
+ function owns(trigger, scope) {
296
+ if (!trigger) return false;
297
+ return scope instanceof Node ? scope.contains(trigger) || scope === trigger : false;
298
+ }
299
+ function initTooltip(root) {
300
+ if (typeof document === "undefined") return () => {
301
+ };
302
+ const scope = root ?? document;
303
+ const existing = scopes.get(scope);
304
+ if (existing) return existing;
305
+ const onPointerOver = (event) => {
306
+ if (handled.has(event)) return;
307
+ handled.add(event);
308
+ const pointer = event;
309
+ if (pointer.pointerType === "touch") return;
310
+ const trigger = triggerFrom(pointer.target);
311
+ if (!trigger) return;
312
+ if (pointer.relatedTarget instanceof Node && trigger.contains(pointer.relatedTarget)) return;
313
+ if (dismissed.has(trigger)) return;
314
+ if (current === trigger) {
315
+ cancelClose();
316
+ return;
317
+ }
318
+ if (pending?.trigger === trigger) return;
319
+ triggerOwners.set(trigger, scope);
320
+ markPending(trigger);
321
+ };
322
+ const onPointerOut = (event) => {
323
+ const pointer = event;
324
+ const trigger = triggerFrom(pointer.target);
325
+ if (!trigger) return;
326
+ if (pointer.relatedTarget instanceof Node && trigger.contains(pointer.relatedTarget)) return;
327
+ if (document.activeElement !== trigger) clearDismissed(trigger);
328
+ if (pending?.trigger === trigger) cancelPending();
329
+ if (current === trigger && !(pointer.relatedTarget instanceof Node && bubble?.contains(pointer.relatedTarget))) scheduleClose();
330
+ };
331
+ const onFocusIn = (event) => {
332
+ if (handled.has(event)) return;
333
+ handled.add(event);
334
+ const trigger = triggerFrom(event.target);
335
+ if (!trigger || !focusVisible(trigger) || dismissed.has(trigger)) return;
336
+ triggerOwners.set(trigger, scope);
337
+ show(trigger);
338
+ };
339
+ const onFocusOut = (event) => {
340
+ const trigger = triggerFrom(event.target);
341
+ if (!trigger) return;
342
+ if (!trigger.matches(":hover")) clearDismissed(trigger);
343
+ if (pending?.trigger === trigger) cancelPending();
344
+ if (current === trigger && !trigger.matches(":hover")) hide(trigger);
345
+ };
346
+ const onPointerDown = () => {
347
+ hide(null, { suppressFallback: true });
348
+ };
349
+ const onKeyDown = (event) => {
350
+ if (event.key !== "Escape") return;
351
+ hide(null, { suppressFallback: true });
352
+ };
353
+ scope.addEventListener("pointerover", onPointerOver);
354
+ scope.addEventListener("pointerout", onPointerOut);
355
+ scope.addEventListener("focusin", onFocusIn);
356
+ scope.addEventListener("focusout", onFocusOut);
357
+ scope.addEventListener("pointerdown", onPointerDown, true);
358
+ scope.addEventListener("keydown", onKeyDown, true);
359
+ const dispose = () => {
360
+ scope.removeEventListener("pointerover", onPointerOver);
361
+ scope.removeEventListener("pointerout", onPointerOut);
362
+ scope.removeEventListener("focusin", onFocusIn);
363
+ scope.removeEventListener("focusout", onFocusOut);
364
+ scope.removeEventListener("pointerdown", onPointerDown, true);
365
+ scope.removeEventListener("keydown", onKeyDown, true);
366
+ if (owns(pending?.trigger ?? null, scope)) cancelPending();
367
+ if (owns(current, scope)) hide(null, { instant: true });
368
+ for (const trigger of dismissed) {
369
+ if (scope === document || triggerOwners.get(trigger) === scope || owns(trigger, scope)) clearDismissed(trigger);
370
+ }
371
+ scopes.delete(scope);
372
+ };
373
+ scopes.set(scope, dispose);
374
+ return dispose;
375
+ }
376
+ export {
377
+ initTooltip
378
+ };
@@ -0,0 +1,69 @@
1
+ interface TreeNode {
2
+ value: string;
3
+ label: string;
4
+ children?: TreeNode[];
5
+ disabled?: boolean;
6
+ }
7
+ interface TreeSelectOptions {
8
+ /** Accessible field name; defaults to placeholder. */
9
+ label?: string;
10
+ size?: 'sm' | 'md' | 'lg';
11
+ nodes: TreeNode[];
12
+ /** 初值(多选数组;单选取首个有效值) */
13
+ value?: string[];
14
+ multiple?: boolean;
15
+ /** 面板内搜索:过滤命中节点自动展开祖先,命中词 <mark> 高亮 */
16
+ searchable?: boolean;
17
+ /** 多选的三态勾选(父 = 子集并集,混合态);隐含多值语义 */
18
+ checkable?: boolean;
19
+ /** 单选时仅叶子可定值(默认任意级可选) */
20
+ leafOnly?: boolean;
21
+ /** 默认「请选择」 */
22
+ placeholder?: string;
23
+ clearable?: boolean;
24
+ disabled?: boolean;
25
+ /** 搜索无命中文案,默认「无匹配」 */
26
+ emptyLabel?: string;
27
+ /** 搜索框占位,默认「搜索」 */
28
+ searchPlaceholder?: string;
29
+ onChange?: (value: string[], labels: string[]) => void;
30
+ }
31
+ interface TreeSelectHandle {
32
+ getValue(): string[];
33
+ getLabels(): string[];
34
+ setValue(v: string[]): void;
35
+ clear(): void;
36
+ open(): void;
37
+ close(): void;
38
+ expandAll(): void;
39
+ collapseAll(): void;
40
+ destroy(): void;
41
+ }
42
+ interface FlatTreeEntry {
43
+ node: TreeNode;
44
+ depth: number;
45
+ parents: TreeNode[];
46
+ }
47
+ /** 深度优先拍平(文档序):节点 + 深度 + 父链(键盘导航 / chips 序 / 值序共用)。 */
48
+ declare function flattenTreeNodes(nodes: TreeNode[]): FlatTreeEntry[];
49
+ interface TreeFilterResult {
50
+ /** label 命中 query 的节点值集合(大小写不敏感) */
51
+ matched: Set<string>;
52
+ /** 需保留可见的节点值集合 = 命中 ∪ 祖先 ∪ 命中节点的子孙(上下文可见,不高亮) */
53
+ keep: Set<string>;
54
+ /** 命中节点祖先(搜索态自动展开的目标) */
55
+ expand: Set<string>;
56
+ }
57
+ /** 搜索过滤:命中节点 + 其全部祖先 + 其子孙保留可见(子孙是命中上下文,不高亮);
58
+ * 祖先进 expand(搜索态自动展开的目标)。空 query 返回空集。 */
59
+ declare function filterTreeNodes(nodes: TreeNode[], query: string): TreeFilterResult;
60
+ type TreeCheckState = 'checked' | 'unchecked' | 'mixed';
61
+ /**
62
+ * 三态求值:checked 集合(全部选中节点值)下某节点的勾选态。
63
+ * 自身 + 全部子孙都在集合 → checked;全不在 → unchecked;部分在 → mixed
64
+ * (父不在集合但全部子孙在也呈 mixed——诚实呈现部分选择,由 toggle 逻辑保证一致)。
65
+ */
66
+ declare function treeNodeCheckState(node: TreeNode, checked: ReadonlySet<string>): TreeCheckState;
67
+ declare function createTreeSelect(el: HTMLElement, opts: TreeSelectOptions): TreeSelectHandle;
68
+
69
+ export { type FlatTreeEntry, type TreeCheckState, type TreeFilterResult, type TreeNode, type TreeSelectHandle, type TreeSelectOptions, createTreeSelect, filterTreeNodes, flattenTreeNodes, treeNodeCheckState };