@icen.ai/ui 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/AGENTS.md +82 -254
  2. package/LICENSE +21 -0
  3. package/README.md +60 -96
  4. package/dist/base.css +258 -188
  5. package/dist/behaviors/accordion.mjs +8 -8
  6. package/dist/behaviors/ai-branch.d.mts +1 -1
  7. package/dist/behaviors/ai-branch.mjs +1011 -94
  8. package/dist/behaviors/ai-chat.d.mts +9 -9
  9. package/dist/behaviors/ai-chat.mjs +1122 -169
  10. package/dist/behaviors/ai-composer.d.mts +47 -15
  11. package/dist/behaviors/ai-composer.mjs +2018 -534
  12. package/dist/behaviors/ai-core.d.mts +1 -1
  13. package/dist/behaviors/ai-core.mjs +1017 -107
  14. package/dist/behaviors/ai-diff.mjs +1020 -127
  15. package/dist/behaviors/ai-feedback.d.mts +1 -1
  16. package/dist/behaviors/ai-feedback.mjs +1036 -126
  17. package/dist/behaviors/ai-panel.d.mts +10 -10
  18. package/dist/behaviors/ai-panel.mjs +1285 -266
  19. package/dist/behaviors/ai-provider.d.mts +1 -1
  20. package/dist/behaviors/ai-provider.mjs +1004 -101
  21. package/dist/behaviors/ai-threads.d.mts +1 -1
  22. package/dist/behaviors/ai-threads.mjs +1069 -154
  23. package/dist/behaviors/ai-tool.d.mts +3 -3
  24. package/dist/behaviors/ai-tool.mjs +2087 -413
  25. package/dist/behaviors/ai-tools.d.mts +89 -16
  26. package/dist/behaviors/ai-tools.mjs +5365 -380
  27. package/dist/behaviors/autocomplete.d.mts +53 -0
  28. package/dist/behaviors/autocomplete.mjs +1601 -0
  29. package/dist/behaviors/back-top.d.mts +1 -1
  30. package/dist/behaviors/back-top.mjs +952 -14
  31. package/dist/behaviors/carousel.d.mts +1 -1
  32. package/dist/behaviors/carousel.mjs +914 -12
  33. package/dist/behaviors/cascader.d.mts +48 -0
  34. package/dist/behaviors/cascader.mjs +1867 -0
  35. package/dist/behaviors/charts.d.mts +72 -8
  36. package/dist/behaviors/charts.mjs +1953 -272
  37. package/dist/behaviors/code-block.d.mts +36 -0
  38. package/dist/behaviors/code-block.mjs +1619 -0
  39. package/dist/behaviors/command-palette.d.mts +9 -6
  40. package/dist/behaviors/command-palette.mjs +164 -62
  41. package/dist/behaviors/context-menu.d.mts +10 -9
  42. package/dist/behaviors/context-menu.mjs +1113 -44
  43. package/dist/behaviors/controls.d.mts +21 -21
  44. package/dist/behaviors/controls.mjs +1024 -134
  45. package/dist/behaviors/copy.d.mts +21 -2
  46. package/dist/behaviors/copy.mjs +1207 -42
  47. package/dist/behaviors/datatable.d.mts +55 -5
  48. package/dist/behaviors/datatable.mjs +2033 -212
  49. package/dist/behaviors/date-picker.d.mts +0 -1
  50. package/dist/behaviors/date-picker.mjs +1341 -293
  51. package/dist/behaviors/design.d.mts +54 -0
  52. package/dist/behaviors/design.mjs +109 -0
  53. package/dist/behaviors/dropdown.d.mts +5 -6
  54. package/dist/behaviors/dropdown.mjs +262 -110
  55. package/dist/behaviors/events.d.mts +127 -10
  56. package/dist/behaviors/events.mjs +58 -3
  57. package/dist/behaviors/feedback.d.mts +30 -0
  58. package/dist/behaviors/feedback.mjs +296 -0
  59. package/dist/behaviors/focus.d.mts +8 -0
  60. package/dist/behaviors/focus.mjs +24 -0
  61. package/dist/behaviors/form-validate.d.mts +111 -0
  62. package/dist/behaviors/form-validate.mjs +1746 -0
  63. package/dist/behaviors/i18n.d.mts +790 -0
  64. package/dist/behaviors/i18n.mjs +1713 -0
  65. package/dist/behaviors/icons.d.mts +93 -0
  66. package/dist/behaviors/icons.mjs +113 -0
  67. package/dist/behaviors/input.d.mts +9 -1
  68. package/dist/behaviors/input.mjs +1059 -60
  69. package/dist/behaviors/kb-access.d.mts +3 -3
  70. package/dist/behaviors/kb-access.mjs +2135 -239
  71. package/dist/behaviors/kb-acl.d.mts +8 -8
  72. package/dist/behaviors/kb-acl.mjs +1120 -179
  73. package/dist/behaviors/kb-answer.d.mts +2 -2
  74. package/dist/behaviors/kb-answer.mjs +2120 -435
  75. package/dist/behaviors/kb-audit.d.mts +3 -3
  76. package/dist/behaviors/kb-audit.mjs +1077 -154
  77. package/dist/behaviors/kb-canvas.d.mts +3 -3
  78. package/dist/behaviors/kb-canvas.mjs +1101 -177
  79. package/dist/behaviors/kb-chain.d.mts +2 -2
  80. package/dist/behaviors/kb-chain.mjs +1023 -100
  81. package/dist/behaviors/kb-checkpoint.d.mts +3 -3
  82. package/dist/behaviors/kb-checkpoint.mjs +1320 -169
  83. package/dist/behaviors/kb-chunks.d.mts +2 -2
  84. package/dist/behaviors/kb-chunks.mjs +1153 -213
  85. package/dist/behaviors/kb-citation.d.mts +3 -3
  86. package/dist/behaviors/kb-citation.mjs +1221 -185
  87. package/dist/behaviors/kb-clarify.d.mts +2 -2
  88. package/dist/behaviors/kb-clarify.mjs +1059 -130
  89. package/dist/behaviors/kb-conflict.d.mts +2 -2
  90. package/dist/behaviors/kb-conflict.mjs +1042 -119
  91. package/dist/behaviors/kb-connector.d.mts +2 -2
  92. package/dist/behaviors/kb-connector.mjs +1105 -176
  93. package/dist/behaviors/kb-core.d.mts +7 -2
  94. package/dist/behaviors/kb-core.mjs +1078 -162
  95. package/dist/behaviors/kb-eval.d.mts +2 -2
  96. package/dist/behaviors/kb-eval.mjs +1977 -144
  97. package/dist/behaviors/kb-explain.d.mts +3 -3
  98. package/dist/behaviors/kb-explain.mjs +1037 -104
  99. package/dist/behaviors/kb-filter.d.mts +2 -2
  100. package/dist/behaviors/kb-filter.mjs +2014 -178
  101. package/dist/behaviors/kb-gap.d.mts +3 -3
  102. package/dist/behaviors/kb-gap.mjs +1044 -121
  103. package/dist/behaviors/kb-hittest.d.mts +3 -3
  104. package/dist/behaviors/kb-hittest.mjs +1095 -151
  105. package/dist/behaviors/kb-metadata.mjs +1058 -130
  106. package/dist/behaviors/kb-passage.d.mts +4 -4
  107. package/dist/behaviors/kb-passage.mjs +1102 -161
  108. package/dist/behaviors/kb-pipeline.d.mts +4 -4
  109. package/dist/behaviors/kb-pipeline.mjs +1083 -162
  110. package/dist/behaviors/kb-qa.mjs +1089 -160
  111. package/dist/behaviors/kb-rerank.d.mts +2 -2
  112. package/dist/behaviors/kb-rerank.mjs +1048 -114
  113. package/dist/behaviors/kb-retrieval.d.mts +2 -2
  114. package/dist/behaviors/kb-retrieval.mjs +2079 -226
  115. package/dist/behaviors/kb-review.d.mts +2 -2
  116. package/dist/behaviors/kb-review.mjs +1996 -159
  117. package/dist/behaviors/kb-sandbox.d.mts +3 -3
  118. package/dist/behaviors/kb-sandbox.mjs +1033 -105
  119. package/dist/behaviors/kb-segment.d.mts +2 -2
  120. package/dist/behaviors/kb-segment.mjs +1112 -179
  121. package/dist/behaviors/kb-select.d.mts +24 -0
  122. package/dist/behaviors/kb-select.mjs +1995 -0
  123. package/dist/behaviors/kb-sources.d.mts +3 -3
  124. package/dist/behaviors/kb-sources.mjs +1085 -170
  125. package/dist/behaviors/kb-sql.d.mts +3 -3
  126. package/dist/behaviors/kb-sql.mjs +1144 -226
  127. package/dist/behaviors/kb-trace.d.mts +3 -3
  128. package/dist/behaviors/kb-trace.mjs +1051 -131
  129. package/dist/behaviors/kb-visibility.d.mts +2 -2
  130. package/dist/behaviors/kb-visibility.mjs +1087 -158
  131. package/dist/behaviors/kb-who-can.d.mts +2 -2
  132. package/dist/behaviors/kb-who-can.mjs +1980 -137
  133. package/dist/behaviors/mentions.d.mts +93 -0
  134. package/dist/behaviors/mentions.mjs +2153 -0
  135. package/dist/behaviors/modal.d.mts +4 -3
  136. package/dist/behaviors/modal.mjs +1056 -33
  137. package/dist/behaviors/nav.d.mts +1 -1
  138. package/dist/behaviors/nav.mjs +6 -6
  139. package/dist/behaviors/notification.d.mts +16 -8
  140. package/dist/behaviors/notification.mjs +1629 -268
  141. package/dist/behaviors/panel.d.mts +4 -0
  142. package/dist/behaviors/panel.mjs +995 -0
  143. package/dist/behaviors/popover.d.mts +28 -5
  144. package/dist/behaviors/popover.mjs +225 -24
  145. package/dist/behaviors/scroll-area.d.mts +17 -0
  146. package/dist/behaviors/scroll-area.mjs +59 -0
  147. package/dist/behaviors/select.d.mts +5 -2
  148. package/dist/behaviors/select.mjs +1416 -117
  149. package/dist/behaviors/sidebar.d.mts +1 -1
  150. package/dist/behaviors/sidebar.mjs +13 -13
  151. package/dist/behaviors/slider.d.mts +1 -1
  152. package/dist/behaviors/slider.mjs +12 -12
  153. package/dist/behaviors/split-pane.d.mts +1 -1
  154. package/dist/behaviors/split-pane.mjs +9 -7
  155. package/dist/behaviors/suggestions.d.mts +27 -0
  156. package/dist/behaviors/suggestions.mjs +1090 -0
  157. package/dist/behaviors/svg-parse.d.mts +14 -0
  158. package/dist/behaviors/svg-parse.mjs +37 -0
  159. package/dist/behaviors/tabs.d.mts +2 -2
  160. package/dist/behaviors/tabs.mjs +35 -25
  161. package/dist/behaviors/tag-input.d.mts +23 -5
  162. package/dist/behaviors/tag-input.mjs +1360 -104
  163. package/dist/behaviors/theme-switcher.d.mts +24 -0
  164. package/dist/behaviors/theme-switcher.mjs +1996 -0
  165. package/dist/behaviors/theme.d.mts +15 -8
  166. package/dist/behaviors/theme.mjs +406 -30
  167. package/dist/behaviors/toast.d.mts +24 -25
  168. package/dist/behaviors/toast.mjs +1267 -88
  169. package/dist/behaviors/tooltip.d.mts +4 -0
  170. package/dist/behaviors/tooltip.mjs +378 -0
  171. package/dist/behaviors/tree-select.d.mts +69 -0
  172. package/dist/behaviors/tree-select.mjs +1921 -0
  173. package/dist/behaviors/tree.d.mts +1 -1
  174. package/dist/behaviors/tree.mjs +18 -18
  175. package/dist/behaviors/upload.d.mts +3 -2
  176. package/dist/behaviors/upload.mjs +1077 -66
  177. package/dist/behaviors/url-safety.d.mts +8 -0
  178. package/dist/behaviors/url-safety.mjs +11 -0
  179. package/dist/cli.mjs +5 -6
  180. package/dist/components/accordion.d.mts +2 -0
  181. package/dist/components/ai-branch.d.mts +2 -0
  182. package/dist/components/ai-chat.css +682 -582
  183. package/dist/components/ai-chat.d.mts +2 -0
  184. package/dist/components/ai-composer.d.mts +2 -0
  185. package/dist/components/ai-context.d.mts +2 -0
  186. package/dist/components/ai-context.mjs +1 -0
  187. package/dist/components/ai-diff.css +153 -132
  188. package/dist/components/ai-diff.d.mts +2 -0
  189. package/dist/components/ai-feedback.d.mts +2 -0
  190. package/dist/components/ai-files.d.mts +2 -0
  191. package/dist/components/ai-message.d.mts +2 -0
  192. package/dist/components/ai-panel.css +353 -343
  193. package/dist/components/ai-reasoning.d.mts +2 -0
  194. package/dist/components/ai-subagent.d.mts +2 -0
  195. package/dist/components/ai-subagent.mjs +1 -0
  196. package/dist/components/ai-threads.d.mts +2 -0
  197. package/dist/components/ai-todo.d.mts +2 -0
  198. package/dist/components/ai-todo.mjs +1 -0
  199. package/dist/components/ai-tool-call.d.mts +2 -0
  200. package/dist/components/ai-tool-call.mjs +1 -0
  201. package/dist/components/ai-tool.css +397 -242
  202. package/dist/components/ai-usage.d.mts +2 -0
  203. package/dist/components/alert.d.mts +2 -0
  204. package/dist/components/autocomplete.css +61 -0
  205. package/dist/components/autocomplete.d.mts +2 -0
  206. package/dist/components/autocomplete.mjs +3 -0
  207. package/dist/components/avatar.d.mts +2 -0
  208. package/dist/components/back-top.css +74 -40
  209. package/dist/components/back-top.d.mts +2 -0
  210. package/dist/components/badge.css +44 -41
  211. package/dist/components/badge.d.mts +2 -0
  212. package/dist/components/breadcrumb.css +85 -46
  213. package/dist/components/breadcrumb.d.mts +2 -0
  214. package/dist/components/btn.css +105 -94
  215. package/dist/components/btn.d.mts +2 -0
  216. package/dist/components/card.css +124 -113
  217. package/dist/components/card.d.mts +2 -0
  218. package/dist/components/carousel.d.mts +2 -0
  219. package/dist/components/cascader.css +332 -0
  220. package/dist/components/cascader.d.mts +2 -0
  221. package/dist/components/cascader.mjs +3 -0
  222. package/dist/components/chart-area.css +54 -2
  223. package/dist/components/chart-area.d.mts +2 -0
  224. package/dist/components/chart-bar.css +147 -38
  225. package/dist/components/chart-bar.d.mts +2 -0
  226. package/dist/components/chart-calendar.d.mts +2 -0
  227. package/dist/components/chart-gauge.css +36 -13
  228. package/dist/components/chart-gauge.d.mts +2 -0
  229. package/dist/components/chart-graph.css +35 -20
  230. package/dist/components/chart-graph.d.mts +2 -0
  231. package/dist/components/chart-heatmap.css +67 -39
  232. package/dist/components/chart-heatmap.d.mts +2 -0
  233. package/dist/components/chart-line.css +62 -3
  234. package/dist/components/chart-line.d.mts +2 -0
  235. package/dist/components/chart-map.d.mts +2 -0
  236. package/dist/components/chart-pie.css +38 -6
  237. package/dist/components/chart-pie.d.mts +2 -0
  238. package/dist/components/chart-radar.css +57 -5
  239. package/dist/components/chart-radar.d.mts +2 -0
  240. package/dist/components/chart-scatter.css +47 -7
  241. package/dist/components/chart-scatter.d.mts +2 -0
  242. package/dist/components/chart-sparkline.css +25 -2
  243. package/dist/components/chart-sparkline.d.mts +2 -0
  244. package/dist/components/chart-stack.css +27 -13
  245. package/dist/components/chart-stack.d.mts +2 -0
  246. package/dist/components/charts.css +220 -84
  247. package/dist/components/charts.d.mts +2 -0
  248. package/dist/components/code-block.css +420 -0
  249. package/dist/components/code-block.d.mts +2 -0
  250. package/dist/components/code-block.mjs +4 -0
  251. package/dist/components/command-palette.css +150 -122
  252. package/dist/components/command-palette.d.mts +2 -0
  253. package/dist/components/content.css +274 -263
  254. package/dist/components/context-menu.d.mts +2 -0
  255. package/dist/components/copy.css +73 -45
  256. package/dist/components/copy.d.mts +2 -0
  257. package/dist/components/datatable.css +457 -202
  258. package/dist/components/datatable.d.mts +2 -0
  259. package/dist/components/date-picker.css +136 -105
  260. package/dist/components/date-picker.d.mts +2 -0
  261. package/dist/components/desc.d.mts +2 -0
  262. package/dist/components/dropdown.d.mts +2 -0
  263. package/dist/components/empty.css +72 -69
  264. package/dist/components/empty.d.mts +2 -0
  265. package/dist/components/feedback.css +211 -191
  266. package/dist/components/form-validate.css +134 -0
  267. package/dist/components/form-validate.d.mts +2 -0
  268. package/dist/components/form-validate.mjs +3 -0
  269. package/dist/components/form.css +157 -131
  270. package/dist/components/form.d.mts +2 -0
  271. package/dist/components/icon.css +113 -0
  272. package/dist/components/icon.d.mts +2 -0
  273. package/dist/components/icon.mjs +3 -0
  274. package/dist/components/input.css +163 -108
  275. package/dist/components/input.d.mts +2 -0
  276. package/dist/components/kb-access.d.mts +2 -0
  277. package/dist/components/kb-acl.d.mts +2 -0
  278. package/dist/components/kb-agent.css +300 -206
  279. package/dist/components/kb-answer.d.mts +2 -0
  280. package/dist/components/kb-audit.d.mts +2 -0
  281. package/dist/components/kb-canvas.d.mts +2 -0
  282. package/dist/components/kb-chain.d.mts +2 -0
  283. package/dist/components/kb-checkpoint.d.mts +2 -0
  284. package/dist/components/kb-chunks.d.mts +2 -0
  285. package/dist/components/kb-citation.d.mts +2 -0
  286. package/dist/components/kb-clarify.d.mts +2 -0
  287. package/dist/components/kb-conflict.d.mts +2 -0
  288. package/dist/components/kb-connector.d.mts +2 -0
  289. package/dist/components/kb-data.css +431 -315
  290. package/dist/components/kb-eval.d.mts +2 -0
  291. package/dist/components/kb-explain.d.mts +2 -0
  292. package/dist/components/kb-filter.d.mts +2 -0
  293. package/dist/components/kb-gap.d.mts +2 -0
  294. package/dist/components/kb-ground.css +333 -229
  295. package/dist/components/kb-hittest.d.mts +2 -0
  296. package/dist/components/kb-ingest.css +613 -434
  297. package/dist/components/kb-metadata.d.mts +2 -0
  298. package/dist/components/kb-ops.css +422 -302
  299. package/dist/components/kb-passage.d.mts +2 -0
  300. package/dist/components/kb-perm.css +374 -314
  301. package/dist/components/kb-pipeline.d.mts +2 -0
  302. package/dist/components/kb-qa.d.mts +2 -0
  303. package/dist/components/kb-rerank.d.mts +2 -0
  304. package/dist/components/kb-retrieval.d.mts +2 -0
  305. package/dist/components/kb-review.d.mts +2 -0
  306. package/dist/components/kb-sandbox.d.mts +2 -0
  307. package/dist/components/kb-search.css +653 -459
  308. package/dist/components/kb-segment.d.mts +2 -0
  309. package/dist/components/kb-sources.d.mts +2 -0
  310. package/dist/components/kb-sql.d.mts +2 -0
  311. package/dist/components/kb-trace.d.mts +2 -0
  312. package/dist/components/kb-visibility.d.mts +2 -0
  313. package/dist/components/kb-who-can.d.mts +2 -0
  314. package/dist/components/kb.css +170 -135
  315. package/dist/components/kb.d.mts +2 -0
  316. package/dist/components/kbd.d.mts +2 -0
  317. package/dist/components/layout.css +86 -83
  318. package/dist/components/layout.d.mts +2 -0
  319. package/dist/components/list.d.mts +2 -0
  320. package/dist/components/material-chinese.css +83 -0
  321. package/dist/components/material-soviet.css +86 -0
  322. package/dist/components/material.css +318 -0
  323. package/dist/components/media-card.d.mts +2 -0
  324. package/dist/components/media.css +225 -176
  325. package/dist/components/mentions.css +190 -0
  326. package/dist/components/mentions.d.mts +2 -0
  327. package/dist/components/mentions.mjs +3 -0
  328. package/dist/components/menu.css +121 -109
  329. package/dist/components/modal.css +116 -118
  330. package/dist/components/modal.d.mts +2 -0
  331. package/dist/components/nav.css +136 -129
  332. package/dist/components/nav.d.mts +2 -0
  333. package/dist/components/notification.css +247 -177
  334. package/dist/components/notification.d.mts +2 -0
  335. package/dist/components/pagination.css +62 -57
  336. package/dist/components/pagination.d.mts +2 -0
  337. package/dist/components/panel.css +70 -68
  338. package/dist/components/panel.d.mts +2 -0
  339. package/dist/components/panel.mjs +1 -0
  340. package/dist/components/pill.css +83 -72
  341. package/dist/components/pill.d.mts +2 -0
  342. package/dist/components/popover.css +80 -57
  343. package/dist/components/popover.d.mts +2 -0
  344. package/dist/components/progress.d.mts +2 -0
  345. package/dist/components/rating.d.mts +2 -0
  346. package/dist/components/result.d.mts +2 -0
  347. package/dist/components/scroll-area.css +29 -54
  348. package/dist/components/scroll-area.d.mts +2 -0
  349. package/dist/components/scroll-area.mjs +1 -0
  350. package/dist/components/segmented.css +167 -146
  351. package/dist/components/segmented.d.mts +2 -0
  352. package/dist/components/select.css +250 -191
  353. package/dist/components/select.d.mts +2 -0
  354. package/dist/components/sidebar.css +157 -143
  355. package/dist/components/sidebar.d.mts +2 -0
  356. package/dist/components/skeleton.d.mts +2 -0
  357. package/dist/components/slider.css +135 -128
  358. package/dist/components/slider.d.mts +2 -0
  359. package/dist/components/spinner.d.mts +2 -0
  360. package/dist/components/split-pane.css +120 -108
  361. package/dist/components/split-pane.d.mts +2 -0
  362. package/dist/components/stat.css +116 -109
  363. package/dist/components/stat.d.mts +2 -0
  364. package/dist/components/steps.css +114 -108
  365. package/dist/components/steps.d.mts +2 -0
  366. package/dist/components/switch.css +192 -149
  367. package/dist/components/switch.d.mts +2 -0
  368. package/dist/components/table.css +158 -112
  369. package/dist/components/table.d.mts +2 -0
  370. package/dist/components/tabs.css +143 -116
  371. package/dist/components/tabs.d.mts +2 -0
  372. package/dist/components/tag-input.css +52 -133
  373. package/dist/components/tag-input.d.mts +2 -0
  374. package/dist/components/tag.css +90 -72
  375. package/dist/components/tag.d.mts +2 -0
  376. package/dist/components/theme-switcher.css +105 -0
  377. package/dist/components/theme-switcher.d.mts +2 -0
  378. package/dist/components/theme-switcher.mjs +3 -0
  379. package/dist/components/timeline.d.mts +2 -0
  380. package/dist/components/toast.css +115 -97
  381. package/dist/components/toast.d.mts +2 -0
  382. package/dist/components/toolbar.css +47 -43
  383. package/dist/components/toolbar.d.mts +2 -0
  384. package/dist/components/tooltip.css +103 -43
  385. package/dist/components/tooltip.d.mts +2 -0
  386. package/dist/components/tooltip.mjs +1 -0
  387. package/dist/components/tree-select.css +439 -0
  388. package/dist/components/tree-select.d.mts +2 -0
  389. package/dist/components/tree-select.mjs +3 -0
  390. package/dist/components/tree.d.mts +2 -0
  391. package/dist/components/upload.css +138 -97
  392. package/dist/components/upload.d.mts +2 -0
  393. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  394. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  395. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  396. package/dist/fonts/OFL.txt +96 -0
  397. package/dist/fonts/README.md +14 -0
  398. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  399. package/dist/index.d.mts +85 -70
  400. package/dist/index.mjs +17330 -5773
  401. package/dist/react.d.mts +91 -0
  402. package/dist/react.mjs +8307 -0
  403. package/dist/registry.json +918 -70
  404. package/dist/tokens/chinese.css +44 -0
  405. package/dist/tokens/colors.css +371 -1222
  406. package/dist/tokens/design.css +209 -0
  407. package/dist/tokens/dtcg.json +15926 -0
  408. package/dist/tokens/figma.variables.json +10779 -0
  409. package/dist/tokens/icon-masks.css +78 -0
  410. package/dist/tokens/pixel.css +53 -0
  411. package/dist/tokens/scrollbars.css +40 -0
  412. package/dist/tokens/soviet.css +44 -0
  413. package/dist/tokens/style-profiles.css +36 -547
  414. package/dist/tokens/themes.json +308 -0
  415. package/dist/tokens/tokens-studio.json +11648 -0
  416. package/dist/tokens/typography.css +21 -18
  417. package/dist/tokens.css +1783 -1806
  418. package/dist/ui.css +14796 -10750
  419. package/dist/vue.d.mts +344 -0
  420. package/dist/vue.mjs +7876 -0
  421. package/docs/spec/ai-input-experience.md +75 -0
  422. package/docs/spec/ai-native.md +238 -147
  423. package/docs/spec/design-philosophy.md +189 -0
  424. package/docs/spec/design-primitives.md +196 -0
  425. package/docs/spec/kb-family.md +147 -115
  426. package/docs/spec/scrollbars.md +46 -0
  427. package/package.json +56 -8
  428. package/dist/retro-effects.css +0 -255
  429. package/dist/tokens/retro-effects.css +0 -255
  430. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  431. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -0,0 +1,54 @@
1
+ /** Complete visual recipes share CSS, while each brand only supplies seeds.
2
+ * CSS is compiled without a DOM for SSR/static builds. Import tokens.css first.
3
+ * Mount a compiled recipe once, then put data-icen-preset on documentElement.
4
+ * Appearance belongs on html so body-portalled menus inherit the same tokens.
5
+ */
6
+ interface DesignPalette {
7
+ canvas: string;
8
+ surface: string;
9
+ ink: string;
10
+ muted: string;
11
+ accent: string;
12
+ onAccent: string;
13
+ success?: string;
14
+ warning?: string;
15
+ error?: string;
16
+ info?: string;
17
+ }
18
+ interface DesignDefinition {
19
+ /** Lowercase CSS identifier; modern is the built-in 现代 recipe. */
20
+ name: string;
21
+ light: DesignPalette;
22
+ dark: DesignPalette;
23
+ /** CSS px; the shared recipe derives the six geometric roles. */
24
+ radius?: number;
25
+ space?: number;
26
+ controlHeight?: number;
27
+ fontSize?: number;
28
+ font?: string;
29
+ glassOpacity?: number;
30
+ glassBlur?: number;
31
+ motion?: number;
32
+ }
33
+ interface CompiledDesign {
34
+ readonly name: string;
35
+ readonly cssText: string;
36
+ }
37
+ /** WCAG sRGB contrast; six-digit opaque hex only, to keep compilation auditable. */
38
+ declare function designContrast(a: string, b: string): number;
39
+ /** Compile an independent brand with light AND dark palettes; never injects CSS.
40
+ * Validation covers body/muted/accent text on both surfaces and button labels.
41
+ * Translucent materials still need visual checks over representative content.
42
+ */
43
+ declare function createDesign(definition: DesignDefinition): CompiledDesign;
44
+ /** Attach trusted, compiled author CSS; safe on the server. CSP sites can write
45
+ * cssText into a static stylesheet instead, or provide the page's nonce. */
46
+ declare function mountDesign(design: CompiledDesign, nonce?: string): () => void;
47
+ /** Finish palette changes without crossfading text through unreadable midtones.
48
+ * Call before changing design/theme attributes; hover feedback resumes next frame.
49
+ */
50
+ declare function prepareDesignChange(): void;
51
+ /** Set a compiled brand theme. null restores the 现代 theme; primitives remain independent. */
52
+ declare function setDesign(name: string | null): void;
53
+
54
+ export { type CompiledDesign, type DesignDefinition, type DesignPalette, createDesign, designContrast, mountDesign, prepareDesignChange, setDesign };
@@ -0,0 +1,109 @@
1
+ // src/behaviors/design.ts
2
+ var NAME = /^[a-z][a-z0-9-]{1,30}$/;
3
+ var HEX = /^#[\da-f]{6}$/i;
4
+ var paletteKeys = ["canvas", "surface", "ink", "muted", "accent", "onAccent", "success", "warning", "error", "info"];
5
+ var seedName = (name) => name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
6
+ function luminance(hex) {
7
+ const rgb = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((c) => c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
8
+ return rgb[0] * 0.2126 + rgb[1] * 0.7152 + rgb[2] * 0.0722;
9
+ }
10
+ function designContrast(a, b) {
11
+ if (!HEX.test(a) || !HEX.test(b)) throw new Error("Design colors must use #rrggbb.");
12
+ const x = luminance(a), y = luminance(b);
13
+ return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
14
+ }
15
+ function compilePalette(palette, mode) {
16
+ const required = ["canvas", "surface", "ink", "muted", "accent", "onAccent"];
17
+ for (const key of required) {
18
+ if (typeof palette[key] !== "string" || !HEX.test(palette[key])) throw new Error(`${mode}.${key} must use #rrggbb.`);
19
+ }
20
+ for (const key of paletteKeys) {
21
+ const color = palette[key];
22
+ if (color !== void 0 && !HEX.test(color)) throw new Error(`${mode}.${key} must use #rrggbb.`);
23
+ }
24
+ for (const bg of ["canvas", "surface"]) {
25
+ for (const fg of ["ink", "muted", "accent"]) {
26
+ if (designContrast(palette[bg], palette[fg]) < 4.5) throw new Error(`${mode}.${fg} on ${bg} must reach 4.5:1 contrast.`);
27
+ }
28
+ }
29
+ if (designContrast(palette.accent, palette.onAccent) < 4.5) throw new Error(`${mode}.onAccent must reach 4.5:1 contrast.`);
30
+ return paletteKeys.filter((key) => palette[key] !== void 0).map((key) => ` --icen-design-${seedName(key)}: ${palette[key]};`).join("\n") + `
31
+ --icen-design-accent-strong: ${palette.accent};
32
+ --icen-design-accent-text: ${palette.accent};
33
+ --icen-design-faint: ${palette.muted};
34
+ --icen-design-raised: color-mix(in srgb, ${palette.surface} 96%, ${palette.ink});`;
35
+ }
36
+ function createDesign(definition) {
37
+ if (!NAME.test(definition.name)) throw new Error("Invalid design name.");
38
+ const knobs = [];
39
+ const ranges = {
40
+ radius: [0, 32, "px"],
41
+ space: [2, 8, "px"],
42
+ controlHeight: [32, 56, "px"],
43
+ fontSize: [12, 24, "px"],
44
+ glassOpacity: [70, 100, "%"],
45
+ glassBlur: [0, 40, "px"],
46
+ motion: [0, 1, ""]
47
+ };
48
+ for (const key of Object.keys(ranges)) {
49
+ const value = definition[key];
50
+ if (value === void 0) continue;
51
+ const [min, max, unit] = ranges[key];
52
+ if (typeof value !== "number" || !Number.isFinite(value) || value < min || value > max) throw new Error(`${key} must be between ${min} and ${max}.`);
53
+ knobs.push(` --icen-design-${seedName(key)}: ${value}${unit};`);
54
+ }
55
+ if (definition.font !== void 0) {
56
+ if (!definition.font.trim() || /[;{}<>\\\n\r]|\/\*/.test(definition.font)) throw new Error("Invalid font stack.");
57
+ knobs.push(` --icen-design-font: ${definition.font};`);
58
+ }
59
+ const selector = `:root[data-icen-preset="${definition.name}"]`;
60
+ const cssText = `${selector} {
61
+ ${compilePalette(definition.light, "light")}
62
+ ${knobs.join("\n")}
63
+ }
64
+ ${selector}[data-icen-theme="dark"] {
65
+ ${compilePalette(definition.dark, "dark")}
66
+ ${knobs.join("\n")}
67
+ }
68
+ `;
69
+ return Object.freeze({ name: definition.name, cssText });
70
+ }
71
+ function mountDesign(design, nonce) {
72
+ if (typeof document === "undefined") return () => {
73
+ };
74
+ const style = document.createElement("style");
75
+ if (nonce) style.nonce = nonce;
76
+ style.textContent = design.cssText;
77
+ document.head.append(style);
78
+ return () => style.remove();
79
+ }
80
+ var appearanceFrame;
81
+ function prepareDesignChange() {
82
+ if (typeof document === "undefined" || typeof window.requestAnimationFrame !== "function") return;
83
+ const root = document.documentElement;
84
+ root.setAttribute("data-icen-design-changing", "");
85
+ void root.offsetWidth;
86
+ if (appearanceFrame !== void 0) window.cancelAnimationFrame(appearanceFrame);
87
+ appearanceFrame = window.requestAnimationFrame(() => {
88
+ appearanceFrame = window.requestAnimationFrame(() => {
89
+ void root.offsetWidth;
90
+ root.removeAttribute("data-icen-design-changing");
91
+ appearanceFrame = void 0;
92
+ });
93
+ });
94
+ }
95
+ function setDesign(name) {
96
+ if (name !== null && !NAME.test(name)) throw new Error("Invalid design name.");
97
+ if (typeof document === "undefined") return;
98
+ prepareDesignChange();
99
+ document.documentElement.setAttribute("data-icen-preset", name ?? "modern");
100
+ if (!document.documentElement.hasAttribute("data-icen-style")) document.documentElement.setAttribute("data-icen-style", "modern");
101
+ document.documentElement.removeAttribute("data-icen-design");
102
+ }
103
+ export {
104
+ createDesign,
105
+ designContrast,
106
+ mountDesign,
107
+ prepareDesignChange,
108
+ setDesign
109
+ };
@@ -1,8 +1,7 @@
1
- /**
2
- * 绑定全部 [data-dropdown-trigger](document 级委托,重复调用安全)。
3
- * 返回销毁函数:摘除 document 委托并复位幂等标记(销毁后可重新 init);
4
- * 销毁时若有面板开着会顺带收起。SSR 下返回 no-op。
5
- */
1
+ /** Open an authored menu and focus its first/last available action. */
2
+ declare function openDropdown(trigger: HTMLElement, edge?: 'first' | 'last'): void;
3
+ /** Closing is interruptible: reopening/destroying first restores template nodes. */
4
+ declare function closeDropdown(restoreFocus?: boolean): void;
6
5
  declare function initDropdown(root?: ParentNode): () => void;
7
6
 
8
- export { initDropdown };
7
+ export { closeDropdown, initDropdown, openDropdown };
@@ -1,10 +1,32 @@
1
1
  // src/behaviors/popover.ts
2
+ function revealPopoverItem(item, scrollport, opts = {}) {
3
+ if (typeof document === "undefined") return;
4
+ if (opts.focus) item.focus({ preventScroll: true });
5
+ const rect = item.getBoundingClientRect(), bounds = scrollport.getBoundingClientRect();
6
+ const style = getComputedStyle(scrollport);
7
+ const inset = (value, extent) => {
8
+ const amount = Number.parseFloat(value) || 0;
9
+ return value.endsWith("%") ? amount * extent / 100 : amount;
10
+ };
11
+ if (opts.axis !== "inline") {
12
+ const top = bounds.top + scrollport.clientTop + inset(style.scrollPaddingTop, scrollport.clientHeight);
13
+ const bottom = bounds.top + scrollport.clientTop + scrollport.clientHeight - inset(style.scrollPaddingBottom, scrollport.clientHeight);
14
+ if (rect.top < top) scrollport.scrollTop -= top - rect.top;
15
+ else if (rect.bottom > bottom) scrollport.scrollTop += rect.bottom - bottom;
16
+ }
17
+ if (opts.axis === "inline" || opts.axis === "both") {
18
+ const left = bounds.left + scrollport.clientLeft + inset(style.scrollPaddingLeft, scrollport.clientWidth);
19
+ const right = bounds.left + scrollport.clientLeft + scrollport.clientWidth - inset(style.scrollPaddingRight, scrollport.clientWidth);
20
+ if (rect.left < left) scrollport.scrollLeft -= left - rect.left;
21
+ else if (rect.right > right) scrollport.scrollLeft += rect.right - right;
22
+ }
23
+ }
2
24
  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"
25
+ width: "data-icen-panel-width",
26
+ minWidth: "data-icen-panel-min",
27
+ maxWidth: "data-icen-panel-max",
28
+ minHeight: "data-icen-panel-min-height",
29
+ maxHeight: "data-icen-panel-max-height"
8
30
  };
9
31
  function readPanelSizing(el) {
10
32
  const out = {};
@@ -65,10 +87,10 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
65
87
  const preferredSide = opts.side ?? "top";
66
88
  const align = opts.align ?? "start";
67
89
  if (preferredSide === "left" || preferredSide === "right") {
90
+ const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
68
91
  const availableLeft = Math.max(0, anchor.left - margin - offset);
69
92
  const availableRight = Math.max(0, viewport.width - anchor.right - margin - offset);
70
- const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= DEFAULT_MIN_WIDTH ? preferredSide : preferredSide === "left" ? "right" : "left";
71
- const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
93
+ const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= minWidth2 ? preferredSide : preferredSide === "left" ? "right" : "left";
72
94
  const maxWidth2 = Math.min(
73
95
  Math.max(opts.maxWidth ?? DEFAULT_MAX_WIDTH, minWidth2),
74
96
  side2 === "left" ? availableLeft : availableRight
@@ -97,7 +119,7 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
97
119
  const minHeight = Math.min(Math.max(80, opts.minHeight ?? DEFAULT_MIN_HEIGHT), availableHeight);
98
120
  const requestedMaxHeight = Math.max(minHeight, opts.maxHeight ?? DEFAULT_MAX_HEIGHT);
99
121
  const fallbackHeight = Math.min(260, requestedMaxHeight);
100
- const contentHeight = Math.max(opts.contentHeightHint ?? 0, fallbackHeight);
122
+ const contentHeight = opts.contentHeightHint != null && opts.contentHeightHint > 0 ? opts.contentHeightHint : fallbackHeight;
101
123
  const desiredHeight = clamp(contentHeight, minHeight, Math.min(requestedMaxHeight, availableHeight));
102
124
  const side = chooseSide(preferredSide, availableTop, availableBottom, desiredHeight);
103
125
  const sideSpace = side === "top" ? availableTop : availableBottom;
@@ -113,6 +135,14 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
113
135
  const top = clamp(desiredTop, margin, viewport.height - margin - positionedHeight);
114
136
  return { side, left, top, width, maxHeight };
115
137
  }
138
+ var menuCloser = null;
139
+ function claimMenuFocus(close) {
140
+ menuCloser?.();
141
+ menuCloser = close;
142
+ return () => {
143
+ if (menuCloser === close) menuCloser = null;
144
+ };
145
+ }
116
146
 
117
147
  // src/behaviors/events.ts
118
148
  function emitIcen(source, type, detail) {
@@ -126,154 +156,276 @@ function emitMenuSelect(source, item) {
126
156
  emitIcen(item, "icen:menu-select", {
127
157
  source,
128
158
  item,
129
- value: item.dataset.value ?? "",
159
+ value: item.dataset.icenValue ?? "",
130
160
  /* 优先专用 label 子元素(避开快捷键/图标文本混入),无则退整项文本 */
131
- label: (item.querySelector(".menu-item-label, .command-item-label")?.textContent ?? item.textContent ?? "").trim().slice(0, 80)
161
+ label: (item.querySelector(".icen-menu-item-label, .command-item-label")?.textContent ?? item.textContent ?? "").trim().slice(0, 80)
132
162
  });
133
163
  }
134
164
 
135
165
  // src/behaviors/dropdown.ts
136
- var VIEWPORT_MARGIN = 12;
137
- var SIDE_OFFSET = 4;
138
166
  var active = null;
139
- var initialized = false;
140
- function menuItems(panel) {
141
- return Array.from(panel.querySelectorAll(".menu-item:not(.is-disabled):not(:disabled)"));
142
- }
143
- function setHighlight(next) {
167
+ var sequence = 0;
168
+ var scopes = /* @__PURE__ */ new Map();
169
+ var finishClosing = null;
170
+ var releaseMenu = null;
171
+ var classDisabled = /* @__PURE__ */ new WeakSet();
172
+ var unavailable = (item) => item.matches(".is-disabled,:disabled") || Boolean(item.closest('[aria-disabled="true"],[hidden],[inert],[data-icen-disabled]'));
173
+ var items = (menu) => Array.from(menu.querySelectorAll(".icen-menu-item")).filter((item) => !unavailable(item));
174
+ var within = (scope, node) => scope === node || scope instanceof Node && scope.contains(node);
175
+ function setHighlight(index, focus = true) {
144
176
  if (!active) return;
145
- active.items.forEach((el, i) => el.classList.toggle("is-highlighted", i === next));
146
- active.highlight = next;
177
+ const rows = items(active.panel);
178
+ active.highlight = index;
179
+ active.panel.querySelectorAll(".icen-menu-item").forEach((item) => {
180
+ const selected = item === rows[index];
181
+ item.classList.toggle("is-highlighted", selected);
182
+ item.tabIndex = selected ? 0 : -1;
183
+ });
184
+ if (rows[index]) revealPopoverItem(rows[index], active.panel, { focus });
147
185
  }
148
186
  function place() {
149
187
  if (!active) return;
150
188
  const { trigger, panel } = active;
151
- const rect = trigger.getBoundingClientRect();
152
- const layout = computePopoverLayout(
153
- rect,
154
- { width: window.innerWidth, height: window.innerHeight },
155
- { side: "bottom", offset: SIDE_OFFSET, margin: VIEWPORT_MARGIN }
156
- );
189
+ if (!trigger.isConnected) {
190
+ closeDropdown(false);
191
+ return;
192
+ }
193
+ const sizing = readPanelSizing(trigger.closest("[data-icen-dropdown]"));
194
+ applyPanelSizing(panel, null);
195
+ applyPanelSizing(panel, sizing);
196
+ const width = panel.offsetWidth || panel.getBoundingClientRect().width || 180;
197
+ const height = panel.scrollHeight || panel.offsetHeight;
198
+ const cssMax = parseFloat(getComputedStyle(panel).maxHeight);
199
+ const layout = computePopoverLayout(trigger.getBoundingClientRect(), { width: window.innerWidth, height: window.innerHeight }, {
200
+ side: "bottom",
201
+ align: getComputedStyle(trigger).direction === "rtl" ? "end" : "start",
202
+ offset: 4,
203
+ margin: 12,
204
+ minWidth: width,
205
+ maxWidth: width,
206
+ minHeight: 40,
207
+ maxHeight: sizing.maxHeight ?? (Number.isFinite(cssMax) ? cssMax : 420),
208
+ contentHeightHint: height
209
+ });
157
210
  panel.style.left = `${layout.left}px`;
158
211
  panel.style.top = `${layout.top}px`;
159
- panel.dataset.side = layout.side;
212
+ panel.style.width = `${layout.width}px`;
213
+ panel.style.minWidth = `${layout.width}px`;
214
+ panel.style.maxHeight = `${layout.maxHeight}px`;
215
+ panel.dataset.icenSide = layout.side;
160
216
  }
161
- function openDropdown(trigger, highlightFirst = false) {
162
- closeDropdown();
163
- const root = trigger.closest("[data-dropdown]");
164
- const template = root?.querySelector("[data-dropdown-menu]");
217
+ function openDropdown(trigger, edge = "first") {
218
+ if (typeof document === "undefined" || unavailable(trigger)) return;
219
+ closeDropdown(false);
220
+ finishClosing?.();
221
+ const root = trigger.closest("[data-icen-dropdown]");
222
+ const template = root?.querySelector("[data-icen-dropdown-menu]");
165
223
  if (!root || !template) return;
224
+ releaseMenu = claimMenuFocus(() => closeDropdown(false));
225
+ if (trigger instanceof HTMLButtonElement && !trigger.hasAttribute("type")) trigger.type = "button";
226
+ trigger.setAttribute("aria-haspopup", "menu");
166
227
  const panel = document.createElement("div");
167
- panel.className = "menu";
228
+ panel.className = "icen-menu";
229
+ panel.id = `icen-dropdown-${++sequence}`;
168
230
  panel.setAttribute("role", "menu");
231
+ panel.tabIndex = -1;
169
232
  panel.style.visibility = "hidden";
233
+ trigger.id ||= `icen-dropdown-trigger-${sequence}`;
234
+ panel.setAttribute("aria-labelledby", trigger.id);
235
+ trigger.setAttribute("aria-controls", panel.id);
170
236
  applyPanelSizing(panel, readPanelSizing(root));
171
- while (template.firstChild) panel.appendChild(template.firstChild);
172
- panel.querySelectorAll(".menu-item").forEach((el) => el.setAttribute("role", "menuitem"));
173
- document.body.appendChild(panel);
174
- active = { trigger, template, panel, items: menuItems(panel), highlight: -1 };
237
+ while (template.firstChild) panel.append(template.firstChild);
238
+ panel.querySelectorAll(".icen-menu-item").forEach((item) => {
239
+ if (item instanceof HTMLButtonElement && !item.hasAttribute("type")) item.type = "button";
240
+ if (!item.hasAttribute("role")) item.setAttribute("role", item.hasAttribute("aria-checked") || item.classList.contains("icen-menu-item--checked") ? "menuitemcheckbox" : "menuitem");
241
+ if (item.getAttribute("role") === "menuitemcheckbox" && !item.hasAttribute("aria-checked")) item.setAttribute("aria-checked", String(item.classList.contains("icen-menu-item--checked")));
242
+ if (classDisabled.has(item)) {
243
+ item.removeAttribute("aria-disabled");
244
+ classDisabled.delete(item);
245
+ }
246
+ if (item.classList.contains("is-disabled") && !item.hasAttribute("aria-disabled")) {
247
+ item.setAttribute("aria-disabled", "true");
248
+ classDisabled.add(item);
249
+ }
250
+ item.tabIndex = -1;
251
+ item.querySelector(".icen-menu-item-check")?.remove();
252
+ item.querySelector(".icen-menu-item-shortcut")?.setAttribute("aria-hidden", "true");
253
+ });
254
+ panel.querySelectorAll(".icen-menu-separator").forEach((separator) => separator.setAttribute("role", "separator"));
255
+ document.body.append(panel);
256
+ active = { trigger, template, panel, highlight: -1, typed: "", typedAt: 0 };
175
257
  trigger.setAttribute("aria-expanded", "true");
176
258
  place();
177
259
  panel.style.visibility = "";
178
- if (highlightFirst && active.items.length > 0) setHighlight(0);
260
+ const rows = items(panel);
261
+ if (rows.length) setHighlight(edge === "last" ? rows.length - 1 : 0);
262
+ else panel.focus({ preventScroll: true });
263
+ panel.addEventListener("pointermove", onPointerMove);
264
+ panel.addEventListener("focusin", (event) => {
265
+ const item = event.target instanceof Element ? event.target.closest(".icen-menu-item") : null;
266
+ if (active?.panel === panel && item) setHighlight(items(panel).indexOf(item), false);
267
+ });
268
+ panel.addEventListener("click", (event) => {
269
+ const item = event.target instanceof Element ? event.target.closest(".icen-menu-item") : null;
270
+ if (item && unavailable(item)) {
271
+ event.preventDefault();
272
+ event.stopImmediatePropagation();
273
+ }
274
+ }, true);
275
+ document.addEventListener("click", onClick);
179
276
  document.addEventListener("pointerdown", onOutsidePointerDown, true);
180
277
  document.addEventListener("scroll", onScroll, true);
181
- window.addEventListener("keydown", onKeyDown);
278
+ window.addEventListener("resize", place);
279
+ window.addEventListener("keydown", onKeyDown, true);
182
280
  }
183
- function closeDropdown(restoreFocus = false) {
281
+ function closeDropdown(restoreFocus = true) {
184
282
  if (!active) return;
185
283
  const { trigger, template, panel } = active;
186
284
  active = null;
285
+ releaseMenu?.();
286
+ releaseMenu = null;
187
287
  trigger.setAttribute("aria-expanded", "false");
188
- while (panel.firstChild) template.appendChild(panel.firstChild);
189
- panel.remove();
288
+ trigger.removeAttribute("aria-controls");
289
+ panel.removeEventListener("pointermove", onPointerMove);
190
290
  document.removeEventListener("pointerdown", onOutsidePointerDown, true);
191
291
  document.removeEventListener("scroll", onScroll, true);
192
- window.removeEventListener("keydown", onKeyDown);
193
- if (restoreFocus) trigger.focus();
292
+ window.removeEventListener("resize", place);
293
+ window.removeEventListener("keydown", onKeyDown, true);
294
+ if (!scopes.size) document.removeEventListener("click", onClick);
295
+ if (restoreFocus && trigger.isConnected) trigger.focus({ preventScroll: true });
296
+ panel.inert = true;
297
+ panel.setAttribute("aria-hidden", "true");
298
+ panel.dataset.icenState = "closing";
299
+ let done = false;
300
+ let animation;
301
+ const finish = () => {
302
+ if (done) return;
303
+ done = true;
304
+ animation?.cancel();
305
+ while (panel.firstChild) template.append(panel.firstChild);
306
+ panel.remove();
307
+ if (finishClosing === finish) finishClosing = null;
308
+ };
309
+ finishClosing = finish;
310
+ const css = getComputedStyle(panel), duration = parseFloat(css.animationDuration) * (css.animationDuration.endsWith("ms") ? 1 : 1e3);
311
+ if (typeof panel.animate === "function" && trigger.isConnected && duration !== 0 && !window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
312
+ animation = panel.animate([{ opacity: css.opacity, transform: css.transform === "none" ? "scale(1)" : css.transform }, { opacity: 0, transform: "scale(.985)" }], { duration: Number.isFinite(duration) ? Math.min(90, duration * 0.75) : 90, easing: css.getPropertyValue("--icen-ease-out").trim() || "ease-out", fill: "forwards" });
313
+ void animation.finished.then(finish, finish);
314
+ } else finish();
194
315
  }
195
- function onOutsidePointerDown(e) {
196
- if (!active) return;
197
- const target = e.target;
198
- if (!(target instanceof Node)) return;
199
- if (active.panel.contains(target) || active.trigger.contains(target)) return;
200
- closeDropdown();
316
+ function onOutsidePointerDown(event) {
317
+ if (active && event.target instanceof Node && !active.panel.contains(event.target) && !active.trigger.contains(event.target)) closeDropdown(false);
201
318
  }
202
- function onScroll(e) {
203
- if (!active) return;
204
- const target = e.target;
205
- if (target instanceof Node && active.panel.contains(target)) return;
206
- closeDropdown();
319
+ function onScroll(event) {
320
+ if (active && !(event.target instanceof Node && active.panel.contains(event.target))) closeDropdown(false);
207
321
  }
208
- function onKeyDown(e) {
209
- if (!active) return;
210
- const { items } = active;
211
- if (e.key === "Escape") {
212
- e.preventDefault();
213
- closeDropdown(true);
322
+ function onPointerMove(event) {
323
+ if (!active || event.pointerType === "touch" || !(event.target instanceof Element)) return;
324
+ const item = event.target.closest(".icen-menu-item");
325
+ if (item && active.panel.contains(item)) setHighlight(items(active.panel).indexOf(item), false);
326
+ }
327
+ function onKeyDown(event) {
328
+ if (!active || event.isComposing || event.keyCode === 229) return;
329
+ if (event.key === "Escape") {
330
+ event.preventDefault();
331
+ event.stopPropagation();
332
+ closeDropdown();
214
333
  return;
215
334
  }
216
- if (items.length === 0) return;
217
- if (e.key === "ArrowDown" || e.key === "ArrowUp") {
218
- e.preventDefault();
219
- const offset = e.key === "ArrowDown" ? 1 : -1;
220
- const next = active.highlight < 0 ? offset > 0 ? 0 : items.length - 1 : (active.highlight + offset + items.length) % items.length;
335
+ if (event.key === "Tab") {
336
+ closeDropdown();
337
+ return;
338
+ }
339
+ if (event.target instanceof Element && event.target.matches('input,textarea,[contenteditable="true"]')) return;
340
+ const rows = items(active.panel);
341
+ if (!rows.length) return;
342
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
343
+ event.preventDefault();
344
+ const next = event.key === "Home" ? 0 : event.key === "End" ? rows.length - 1 : (active.highlight + (event.key === "ArrowDown" ? 1 : -1) + rows.length) % rows.length;
221
345
  setHighlight(next);
222
346
  return;
223
347
  }
224
- if (e.key === "Enter" && active.highlight >= 0) {
225
- e.preventDefault();
226
- const item = items[active.highlight];
227
- emitMenuSelect(active.panel, item);
228
- closeDropdown(true);
229
- item.click();
348
+ if (event.key === "Enter" || event.key === " ") {
349
+ event.preventDefault();
350
+ rows[active.highlight]?.click();
351
+ return;
352
+ }
353
+ if (event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey) return;
354
+ event.preventDefault();
355
+ const now = Date.now();
356
+ active.typed = now - active.typedAt < 600 ? active.typed + event.key : event.key;
357
+ active.typedAt = now;
358
+ let query = active.typed.toLocaleLowerCase();
359
+ if ([...query].every((character) => character === query[0])) query = active.typed = query[0];
360
+ for (let step = 1; step <= rows.length; step++) {
361
+ const index = (Math.max(0, active.highlight) + (query.length === 1 ? step : step - 1)) % rows.length;
362
+ const label = rows[index].querySelector(".icen-menu-item-label")?.textContent ?? rows[index].textContent ?? "";
363
+ if (label.trim().toLocaleLowerCase().startsWith(query)) {
364
+ setHighlight(index);
365
+ break;
366
+ }
367
+ }
368
+ }
369
+ function onClick(event) {
370
+ if (!(event.target instanceof Element)) return;
371
+ const item = event.target.closest(".icen-menu-item");
372
+ if (active && item && active.panel.contains(item)) {
373
+ if (unavailable(item)) {
374
+ event.preventDefault();
375
+ event.stopPropagation();
376
+ return;
377
+ }
378
+ const current = active;
379
+ emitMenuSelect(current.panel, item);
380
+ if (active === current && !item.hasAttribute("data-icen-menu-keep-open")) closeDropdown(current.panel.contains(document.activeElement));
381
+ return;
230
382
  }
383
+ const trigger = event.target.closest("[data-icen-dropdown-trigger]");
384
+ if (!trigger || ![...scopes.keys()].some((scope) => within(scope, trigger))) return;
385
+ event.preventDefault();
386
+ if (active?.trigger === trigger) closeDropdown();
387
+ else openDropdown(trigger);
388
+ }
389
+ function onTriggerKey(event) {
390
+ if (active || event.isComposing || !["ArrowDown", "ArrowUp", "Enter", " "].includes(event.key)) return;
391
+ const trigger = event.target instanceof Element ? event.target.closest("[data-icen-dropdown-trigger]") : null;
392
+ if (!trigger || ![...scopes.keys()].some((scope) => within(scope, trigger))) return;
393
+ event.preventDefault();
394
+ openDropdown(trigger, event.key === "ArrowUp" ? "last" : "first");
395
+ event.stopPropagation();
231
396
  }
232
397
  function initDropdown(root) {
233
398
  if (typeof document === "undefined") return () => {
234
399
  };
235
- const scope = root ?? document;
236
- scope.querySelectorAll("[data-dropdown-trigger]").forEach((el) => el.setAttribute("aria-expanded", "false"));
237
- if (initialized) return () => {
238
- };
239
- initialized = true;
240
- const onClick = (e) => {
241
- const target = e.target instanceof Element ? e.target : null;
242
- if (!target) return;
243
- if (active && target.closest(".menu-item") && active.panel.contains(target)) {
244
- const item = target.closest(".menu-item");
245
- if (item) {
246
- if (!item.matches(".is-disabled") && !item.matches(":disabled")) {
247
- emitMenuSelect(active.panel, item);
248
- }
249
- closeDropdown();
250
- return;
251
- }
400
+ const scope = root ?? document, existing = scopes.get(scope);
401
+ if (existing) return existing;
402
+ const triggers = [...scope instanceof HTMLElement && scope.matches("[data-icen-dropdown-trigger]") ? [scope] : [], ...scope.querySelectorAll("[data-icen-dropdown-trigger]")];
403
+ triggers.forEach((trigger) => {
404
+ if (active?.trigger !== trigger) trigger.setAttribute("aria-expanded", "false");
405
+ trigger.setAttribute("aria-haspopup", "menu");
406
+ if (trigger instanceof HTMLButtonElement && !trigger.hasAttribute("type")) trigger.type = "button";
407
+ });
408
+ if (!scopes.size) {
409
+ document.addEventListener("click", onClick);
410
+ document.addEventListener("keydown", onTriggerKey);
411
+ }
412
+ let disposed = false;
413
+ const dispose = () => {
414
+ if (disposed) return;
415
+ disposed = true;
416
+ scopes.delete(scope);
417
+ if (active && within(scope, active.trigger)) closeDropdown(false);
418
+ finishClosing?.();
419
+ if (!scopes.size) {
420
+ if (!active) document.removeEventListener("click", onClick);
421
+ document.removeEventListener("keydown", onTriggerKey);
252
422
  }
253
- const trigger = target.closest("[data-dropdown-trigger]");
254
- if (!trigger) return;
255
- if (active && active.trigger === trigger) closeDropdown();
256
- else openDropdown(trigger);
257
- };
258
- document.addEventListener("click", onClick);
259
- const onKeyDown2 = (e) => {
260
- if (e.key !== "ArrowDown") return;
261
- if (active) return;
262
- const target = e.target instanceof Element ? e.target : null;
263
- const trigger = target?.closest("[data-dropdown-trigger]");
264
- if (!trigger) return;
265
- e.preventDefault();
266
- openDropdown(trigger, true);
267
- };
268
- document.addEventListener("keydown", onKeyDown2);
269
- const destroy = () => {
270
- document.removeEventListener("click", onClick);
271
- document.removeEventListener("keydown", onKeyDown2);
272
- closeDropdown();
273
- initialized = false;
274
423
  };
275
- return destroy;
424
+ scopes.set(scope, dispose);
425
+ return dispose;
276
426
  }
277
427
  export {
278
- initDropdown
428
+ closeDropdown,
429
+ initDropdown,
430
+ openDropdown
279
431
  };