@icen.ai/ui 0.9.0 → 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 (281) hide show
  1. package/AGENTS.md +138 -80
  2. package/README.md +66 -91
  3. package/dist/base.css +208 -179
  4. package/dist/behaviors/accordion.mjs +8 -8
  5. package/dist/behaviors/ai-branch.d.mts +1 -1
  6. package/dist/behaviors/ai-branch.mjs +1010 -94
  7. package/dist/behaviors/ai-chat.d.mts +7 -7
  8. package/dist/behaviors/ai-chat.mjs +1071 -161
  9. package/dist/behaviors/ai-composer.d.mts +44 -12
  10. package/dist/behaviors/ai-composer.mjs +1997 -524
  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 +1 -1
  15. package/dist/behaviors/ai-feedback.mjs +1035 -126
  16. package/dist/behaviors/ai-panel.d.mts +8 -8
  17. package/dist/behaviors/ai-panel.mjs +1284 -266
  18. package/dist/behaviors/ai-provider.mjs +1003 -101
  19. package/dist/behaviors/ai-threads.d.mts +1 -1
  20. package/dist/behaviors/ai-threads.mjs +1068 -154
  21. package/dist/behaviors/ai-tool.d.mts +2 -2
  22. package/dist/behaviors/ai-tool.mjs +2037 -396
  23. package/dist/behaviors/ai-tools.d.mts +89 -16
  24. package/dist/behaviors/ai-tools.mjs +4448 -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 +72 -8
  34. package/dist/behaviors/charts.mjs +1901 -256
  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 +120 -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 +1 -1
  68. package/dist/behaviors/kb-access.mjs +2129 -239
  69. package/dist/behaviors/kb-acl.d.mts +6 -6
  70. package/dist/behaviors/kb-acl.mjs +1119 -179
  71. package/dist/behaviors/kb-answer.mjs +2070 -418
  72. package/dist/behaviors/kb-audit.d.mts +1 -1
  73. package/dist/behaviors/kb-audit.mjs +1076 -154
  74. package/dist/behaviors/kb-canvas.mjs +1100 -177
  75. package/dist/behaviors/kb-chain.mjs +1022 -100
  76. package/dist/behaviors/kb-checkpoint.d.mts +1 -1
  77. package/dist/behaviors/kb-checkpoint.mjs +1319 -169
  78. package/dist/behaviors/kb-chunks.mjs +1152 -213
  79. package/dist/behaviors/kb-citation.d.mts +1 -1
  80. package/dist/behaviors/kb-citation.mjs +1201 -179
  81. package/dist/behaviors/kb-clarify.mjs +1058 -130
  82. package/dist/behaviors/kb-conflict.mjs +1041 -119
  83. package/dist/behaviors/kb-connector.mjs +1104 -176
  84. package/dist/behaviors/kb-core.d.mts +6 -1
  85. package/dist/behaviors/kb-core.mjs +1077 -162
  86. package/dist/behaviors/kb-eval.mjs +1971 -144
  87. package/dist/behaviors/kb-explain.d.mts +1 -1
  88. package/dist/behaviors/kb-explain.mjs +1024 -102
  89. package/dist/behaviors/kb-filter.mjs +2008 -178
  90. package/dist/behaviors/kb-gap.d.mts +1 -1
  91. package/dist/behaviors/kb-gap.mjs +1043 -121
  92. package/dist/behaviors/kb-hittest.d.mts +1 -1
  93. package/dist/behaviors/kb-hittest.mjs +1093 -150
  94. package/dist/behaviors/kb-metadata.mjs +1052 -130
  95. package/dist/behaviors/kb-passage.d.mts +2 -2
  96. package/dist/behaviors/kb-passage.mjs +1101 -161
  97. package/dist/behaviors/kb-pipeline.d.mts +2 -2
  98. package/dist/behaviors/kb-pipeline.mjs +1082 -162
  99. package/dist/behaviors/kb-qa.mjs +1088 -160
  100. package/dist/behaviors/kb-rerank.mjs +1047 -114
  101. package/dist/behaviors/kb-retrieval.mjs +2063 -224
  102. package/dist/behaviors/kb-review.mjs +1990 -159
  103. package/dist/behaviors/kb-sandbox.d.mts +1 -1
  104. package/dist/behaviors/kb-sandbox.mjs +1026 -104
  105. package/dist/behaviors/kb-segment.mjs +1111 -179
  106. package/dist/behaviors/kb-select.d.mts +24 -0
  107. package/dist/behaviors/kb-select.mjs +1989 -0
  108. package/dist/behaviors/kb-sources.d.mts +1 -1
  109. package/dist/behaviors/kb-sources.mjs +1084 -170
  110. package/dist/behaviors/kb-sql.d.mts +1 -1
  111. package/dist/behaviors/kb-sql.mjs +1143 -226
  112. package/dist/behaviors/kb-trace.d.mts +1 -1
  113. package/dist/behaviors/kb-trace.mjs +1042 -128
  114. package/dist/behaviors/kb-visibility.mjs +1086 -158
  115. package/dist/behaviors/kb-who-can.mjs +1974 -137
  116. package/dist/behaviors/mentions.d.mts +93 -0
  117. package/dist/behaviors/mentions.mjs +2152 -0
  118. package/dist/behaviors/modal.d.mts +4 -3
  119. package/dist/behaviors/modal.mjs +1055 -33
  120. package/dist/behaviors/nav.d.mts +1 -1
  121. package/dist/behaviors/nav.mjs +6 -6
  122. package/dist/behaviors/notification.d.mts +16 -8
  123. package/dist/behaviors/notification.mjs +1615 -265
  124. package/dist/behaviors/panel.d.mts +4 -0
  125. package/dist/behaviors/panel.mjs +994 -0
  126. package/dist/behaviors/popover.d.mts +28 -5
  127. package/dist/behaviors/popover.mjs +225 -24
  128. package/dist/behaviors/select.d.mts +5 -2
  129. package/dist/behaviors/select.mjs +1410 -117
  130. package/dist/behaviors/sidebar.d.mts +1 -1
  131. package/dist/behaviors/sidebar.mjs +13 -13
  132. package/dist/behaviors/slider.d.mts +1 -1
  133. package/dist/behaviors/slider.mjs +9 -9
  134. package/dist/behaviors/split-pane.d.mts +1 -1
  135. package/dist/behaviors/split-pane.mjs +7 -7
  136. package/dist/behaviors/suggestions.d.mts +27 -0
  137. package/dist/behaviors/suggestions.mjs +1089 -0
  138. package/dist/behaviors/svg-parse.d.mts +14 -0
  139. package/dist/behaviors/svg-parse.mjs +37 -0
  140. package/dist/behaviors/tabs.d.mts +2 -2
  141. package/dist/behaviors/tabs.mjs +25 -25
  142. package/dist/behaviors/tag-input.d.mts +23 -5
  143. package/dist/behaviors/tag-input.mjs +1359 -104
  144. package/dist/behaviors/theme-switcher.d.mts +24 -0
  145. package/dist/behaviors/theme-switcher.mjs +1981 -0
  146. package/dist/behaviors/theme.d.mts +15 -8
  147. package/dist/behaviors/theme.mjs +390 -28
  148. package/dist/behaviors/toast.d.mts +24 -25
  149. package/dist/behaviors/toast.mjs +1266 -88
  150. package/dist/behaviors/tooltip.d.mts +4 -0
  151. package/dist/behaviors/tooltip.mjs +378 -0
  152. package/dist/behaviors/tree-select.d.mts +69 -0
  153. package/dist/behaviors/tree-select.mjs +1907 -0
  154. package/dist/behaviors/tree.d.mts +1 -1
  155. package/dist/behaviors/tree.mjs +15 -15
  156. package/dist/behaviors/upload.d.mts +3 -2
  157. package/dist/behaviors/upload.mjs +1076 -66
  158. package/dist/cli.mjs +5 -6
  159. package/dist/components/ai-chat.css +666 -573
  160. package/dist/components/ai-diff.css +153 -132
  161. package/dist/components/ai-panel.css +351 -343
  162. package/dist/components/ai-tool.css +393 -238
  163. package/dist/components/autocomplete.css +61 -0
  164. package/dist/components/autocomplete.mjs +3 -0
  165. package/dist/components/back-top.css +34 -31
  166. package/dist/components/badge.css +44 -41
  167. package/dist/components/breadcrumb.css +67 -46
  168. package/dist/components/btn.css +80 -74
  169. package/dist/components/card.css +117 -106
  170. package/dist/components/cascader.css +311 -0
  171. package/dist/components/cascader.mjs +3 -0
  172. package/dist/components/chart-area.css +8 -2
  173. package/dist/components/chart-bar.css +95 -33
  174. package/dist/components/chart-gauge.css +14 -11
  175. package/dist/components/chart-graph.css +20 -17
  176. package/dist/components/chart-heatmap.css +96 -90
  177. package/dist/components/chart-line.css +8 -3
  178. package/dist/components/chart-pie.css +9 -6
  179. package/dist/components/chart-radar.css +8 -5
  180. package/dist/components/chart-scatter.css +9 -6
  181. package/dist/components/chart-sparkline.css +5 -2
  182. package/dist/components/chart-stack.css +14 -11
  183. package/dist/components/charts.css +164 -73
  184. package/dist/components/code-block.css +418 -0
  185. package/dist/components/code-block.mjs +4 -0
  186. package/dist/components/command-palette.css +138 -117
  187. package/dist/components/content.css +257 -251
  188. package/dist/components/copy.css +72 -44
  189. package/dist/components/datatable.css +423 -181
  190. package/dist/components/date-picker.css +135 -104
  191. package/dist/components/empty.css +68 -65
  192. package/dist/components/feedback.css +201 -183
  193. package/dist/components/form-validate.css +120 -0
  194. package/dist/components/form-validate.mjs +3 -0
  195. package/dist/components/form.css +150 -127
  196. package/dist/components/icon.css +102 -0
  197. package/dist/components/icon.mjs +3 -0
  198. package/dist/components/input.css +159 -104
  199. package/dist/components/kb-agent.css +188 -173
  200. package/dist/components/kb-data.css +257 -253
  201. package/dist/components/kb-ground.css +197 -185
  202. package/dist/components/kb-ingest.css +334 -350
  203. package/dist/components/kb-ops.css +265 -259
  204. package/dist/components/kb-perm.css +260 -271
  205. package/dist/components/kb-search.css +317 -360
  206. package/dist/components/kb.css +120 -109
  207. package/dist/components/layout.css +85 -82
  208. package/dist/components/material-chinese.css +73 -0
  209. package/dist/components/material-soviet.css +76 -0
  210. package/dist/components/material.css +275 -0
  211. package/dist/components/media.css +220 -166
  212. package/dist/components/mentions.css +189 -0
  213. package/dist/components/mentions.mjs +3 -0
  214. package/dist/components/menu.css +113 -105
  215. package/dist/components/modal.css +107 -112
  216. package/dist/components/nav.css +118 -115
  217. package/dist/components/notification.css +238 -174
  218. package/dist/components/pagination.css +56 -53
  219. package/dist/components/panel.css +66 -63
  220. package/dist/components/panel.mjs +1 -0
  221. package/dist/components/pill.css +81 -71
  222. package/dist/components/popover.css +67 -53
  223. package/dist/components/scroll-area.css +113 -110
  224. package/dist/components/segmented.css +146 -143
  225. package/dist/components/select.css +206 -186
  226. package/dist/components/sidebar.css +137 -127
  227. package/dist/components/slider.css +117 -114
  228. package/dist/components/split-pane.css +112 -109
  229. package/dist/components/stat.css +112 -106
  230. package/dist/components/steps.css +109 -103
  231. package/dist/components/switch.css +138 -134
  232. package/dist/components/table.css +131 -107
  233. package/dist/components/tabs.css +114 -108
  234. package/dist/components/tag-input.css +48 -133
  235. package/dist/components/tag.css +81 -71
  236. package/dist/components/theme-switcher.css +105 -0
  237. package/dist/components/theme-switcher.mjs +3 -0
  238. package/dist/components/toast.css +100 -86
  239. package/dist/components/toolbar.css +45 -42
  240. package/dist/components/tooltip.css +102 -43
  241. package/dist/components/tooltip.mjs +1 -0
  242. package/dist/components/tree-select.css +416 -0
  243. package/dist/components/tree-select.mjs +3 -0
  244. package/dist/components/upload.css +135 -92
  245. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  246. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  247. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  248. package/dist/fonts/OFL.txt +96 -0
  249. package/dist/fonts/README.md +14 -0
  250. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  251. package/dist/index.d.mts +28 -14
  252. package/dist/index.mjs +20705 -9601
  253. package/dist/react.d.mts +91 -0
  254. package/dist/react.mjs +8208 -0
  255. package/dist/registry.json +130 -13
  256. package/dist/tokens/chinese.css +44 -0
  257. package/dist/tokens/colors.css +365 -1222
  258. package/dist/tokens/design.css +109 -0
  259. package/dist/tokens/dtcg.json +11198 -0
  260. package/dist/tokens/figma.variables.json +7017 -0
  261. package/dist/tokens/icon-masks.css +78 -0
  262. package/dist/tokens/pixel.css +50 -0
  263. package/dist/tokens/soviet.css +44 -0
  264. package/dist/tokens/style-profiles.css +36 -547
  265. package/dist/tokens/themes.json +308 -0
  266. package/dist/tokens/tokens-studio.json +6728 -0
  267. package/dist/tokens/typography.css +21 -18
  268. package/dist/tokens.css +1555 -1801
  269. package/dist/ui.css +11975 -9831
  270. package/dist/vue.d.mts +344 -0
  271. package/dist/vue.mjs +7781 -0
  272. package/docs/spec/ai-input-experience.md +75 -0
  273. package/docs/spec/ai-native.md +238 -147
  274. package/docs/spec/design-philosophy.md +189 -0
  275. package/docs/spec/design-primitives.md +196 -0
  276. package/docs/spec/kb-family.md +147 -115
  277. package/package.json +43 -8
  278. package/dist/retro-effects.css +0 -255
  279. package/dist/tokens/retro-effects.css +0 -255
  280. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  281. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -0,0 +1,189 @@
1
+ @layer icen.components {
2
+ /*
3
+ * @icen.ai/ui — Component: mentions
4
+ * 声明式宿主不变:<div class="icen-mentions"><textarea class="icen-input"></textarea></div>;
5
+ * createMentions 把 textarea 替换为富文本编辑区
6
+ * <div class="icen-input icen-mentions-editor" contenteditable="true" role="textbox"
7
+ * aria-multiline="true" tabindex="0" data-icen-placeholder="…" [.is-empty]>
8
+ * id/class/aria-label/rows 转移到编辑区;有 name 的 textarea 生成同名 hidden input 承载纯文本;
9
+ * destroy 时恢复 textarea 并回填纯文本。提及是对象单元:
10
+ * <span class="icen-mention-token is-directory|is-custom" contenteditable="false"
11
+ * data-icen-mention-id="…"><bdi>@名称</bdi>[<span class="icen-mention-badge">自定义</span>]</span>
12
+ * token 光标不可进入(原子),Backspace/Delete 整体删除;自定义提及 = 虚线边 + 徽标。
13
+ * 弹层 .icen-mentions-panel portal 到 body:.icen-mentions-list 是 named listbox(只含
14
+ * .icen-mentions-option,custom 模式的「创建 …」项带 .icen-mentions-option-badge),
15
+ * loading/empty/error-retry 状态是 listbox 的并列兄弟。多行 textbox 语义不带 aria-expanded。
16
+ */
17
+
18
+ /* 宿主壳:输入框视觉自治(不套 .icen-input-wrap——那是单行固定高控件壳,多行会被压爆) */
19
+ .icen-mentions {
20
+ display: block;
21
+ width: 100%;
22
+ padding: var(--icen-density-space-xs) var(--icen-density-space-sm);
23
+ background: var(--icen-token-control);
24
+ border: 1px solid var(--icen-token-outline-soft);
25
+ border-radius: var(--icen-radius-md);
26
+ box-shadow: var(--icen-token-shadow-inset);
27
+ cursor: text;
28
+ transition: border-color var(--icen-tx-fast), box-shadow var(--icen-tx-fast);
29
+ }
30
+ .icen-mentions:hover { border-color: var(--icen-hover-border); }
31
+ .icen-mentions:focus-within {
32
+ border-color: var(--icen-control-focus-border);
33
+ box-shadow: var(--icen-control-focus-shadow);
34
+ }
35
+ .icen-mentions > .icen-input { display: block; width: 100%; }
36
+
37
+ /* 富文本编辑区:多行输入壳视觉沿用宿主,排版 pre-wrap 随内容纵向生长 */
38
+ .icen-mentions > .icen-mentions-editor {
39
+ display: block;
40
+ inline-size: 100%;
41
+ min-block-size: calc(var(--icen-mentions-rows, 3) * 1lh);
42
+ white-space: pre-wrap;
43
+ overflow-wrap: break-word;
44
+ word-break: break-word;
45
+ outline: none;
46
+ cursor: text;
47
+ }
48
+ /* 占位文本走数据属性 + ::before,不进值(.is-empty 由行为层按纯文本是否为空切换) */
49
+ .icen-mentions > .icen-mentions-editor.is-empty::before {
50
+ content: attr(data-icen-placeholder);
51
+ color: var(--icen-token-text-faint);
52
+ pointer-events: none;
53
+ }
54
+ .icen-mentions > .icen-mentions-editor[aria-disabled='true'] {
55
+ opacity: var(--icen-disabled-opacity);
56
+ cursor: not-allowed;
57
+ user-select: none;
58
+ }
59
+
60
+ /* 提及 token:文本流中的 inline pill(原子单元,光标不可进入,整体删除) */
61
+ .icen-mention-token {
62
+ display: inline-block;
63
+ padding-inline: var(--icen-density-space-xs);
64
+ border: 1px solid color-mix(in srgb, var(--icen-token-accent) 40%, transparent);
65
+ border-radius: var(--icen-radius-full);
66
+ background: var(--icen-token-accent-subtle);
67
+ color: var(--icen-token-accent-text);
68
+ font-size: var(--icen-density-font-size-sm);
69
+ line-height: var(--icen-line-height-body);
70
+ white-space: nowrap;
71
+ cursor: default;
72
+ transition: background-color var(--icen-tx-fast), border-color var(--icen-tx-fast);
73
+ }
74
+ .icen-mention-token:hover {
75
+ background: var(--icen-token-accent-glow);
76
+ border-color: var(--icen-token-accent);
77
+ }
78
+ /* 自定义提及:虚线边 + 中性浅底 + 「自定义」徽标(i18n 注入),与目录提及一眼区分 */
79
+ .icen-mention-token.is-custom {
80
+ border-style: dashed;
81
+ border-color: var(--icen-token-outline-strong);
82
+ background: var(--icen-token-fill-1);
83
+ color: var(--icen-token-text);
84
+ }
85
+ .icen-mention-token.is-custom:hover {
86
+ background: var(--icen-token-fill-2);
87
+ border-color: var(--icen-token-text-muted);
88
+ }
89
+ .icen-mention-badge {
90
+ margin-inline-start: var(--icen-density-space-xs);
91
+ padding-inline: var(--icen-density-space-xs);
92
+ border-radius: var(--icen-radius-full);
93
+ background: var(--icen-token-accent-strong);
94
+ color: var(--icen-token-on-accent);
95
+ font-size: var(--icen-density-font-size-sm);
96
+ }
97
+
98
+ .icen-mentions-panel {
99
+ position: fixed;
100
+ z-index: var(--icen-z-popover);
101
+ overflow-y: auto;
102
+ overscroll-behavior: contain;
103
+ padding: 4px;
104
+ background: var(--icen-token-card-strong);
105
+ border: 1px solid var(--icen-token-outline);
106
+ border-radius: var(--icen-radius-md);
107
+ box-shadow: var(--icen-token-shadow-overlay);
108
+ transform-origin: top center;
109
+ animation: icen-pop-in var(--icen-tx-fast);
110
+ }
111
+ .icen-mentions-panel[data-icen-side='top'] { transform-origin: bottom center; }
112
+
113
+ /* 异步加载态(role=status,screen reader 播报) */
114
+ .icen-mentions-status {
115
+ padding: var(--icen-density-space-sm);
116
+ font-size: var(--icen-density-font-size-sm);
117
+ color: var(--icen-token-text-muted);
118
+ }
119
+
120
+ .icen-mentions-option {
121
+ display: flex;
122
+ align-items: center;
123
+ gap: var(--icen-density-space-xs);
124
+ padding: 6px var(--icen-density-space-sm);
125
+ font-size: var(--icen-density-font-size-sm);
126
+ color: var(--icen-token-text);
127
+ border-radius: var(--icen-radius-sm);
128
+ cursor: pointer;
129
+ min-block-size: var(--icen-density-input-height-sm);
130
+ transition:
131
+ background-color var(--icen-tx-fast),
132
+ color var(--icen-tx-fast);
133
+ }
134
+ .icen-mentions-empty { padding: var(--icen-density-space-sm); font-size: var(--icen-density-font-size-sm); color: var(--icen-token-text-muted); text-align: center; }
135
+ @media (pointer: coarse) { .icen-mentions-option { min-block-size: 44px; } }
136
+ @media (prefers-reduced-motion: reduce) {
137
+ .icen-mentions-panel { animation: none; }
138
+ .icen-mentions-option,
139
+ .icen-mention-token { transition: none; }
140
+ }
141
+ .icen-mentions-option:hover:not(.is-disabled) { background: var(--icen-token-fill-1); }
142
+ .icen-mentions-option.is-active { background: var(--icen-token-fill-2); }
143
+ .icen-mentions-option.is-disabled {
144
+ opacity: var(--icen-disabled-opacity);
145
+ cursor: not-allowed;
146
+ }
147
+
148
+ /* custom 模式的「创建 …」项:accent 文案 + 自定义徽标 */
149
+ .icen-mentions-option--create .icen-mentions-option-label { color: var(--icen-token-accent-text); }
150
+ .icen-mentions-option-badge {
151
+ flex: 0 0 auto;
152
+ display: inline-flex;
153
+ align-items: center;
154
+ padding-inline: var(--icen-density-space-xs);
155
+ border-radius: var(--icen-radius-full);
156
+ background: var(--icen-token-accent-strong);
157
+ color: var(--icen-token-on-accent);
158
+ font-size: var(--icen-density-font-size-sm);
159
+ line-height: var(--icen-line-height-body);
160
+ }
161
+
162
+ .icen-mentions-option-label {
163
+ flex: 1;
164
+ min-width: 0;
165
+ overflow: hidden;
166
+ text-overflow: ellipsis;
167
+ white-space: nowrap;
168
+ }
169
+
170
+ /* 强制对比度模式:token 失去彩色底,但边界与文字必须仍可辨认 */
171
+ @media (forced-colors: active) {
172
+ .icen-mention-token {
173
+ border-color: Highlight;
174
+ background: transparent;
175
+ color: Highlight;
176
+ }
177
+ .icen-mention-token.is-custom {
178
+ border-color: CanvasText;
179
+ color: CanvasText;
180
+ }
181
+ .icen-mention-badge,
182
+ .icen-mentions-option-badge {
183
+ border: 1px solid CanvasText;
184
+ background: transparent;
185
+ color: CanvasText;
186
+ }
187
+ }
188
+
189
+ }
@@ -0,0 +1,3 @@
1
+ // @icen.ai/ui — kit: mentions(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './mentions.css';
3
+ export * from '../behaviors/mentions.mjs';
@@ -1,212 +1,220 @@
1
+ @layer icen.components {
1
2
  /*
2
3
  * @icen.ai/ui — Component: menu(菜单面板,与 behaviors/dropdown、context-menu 配套)
3
4
  *
4
- * 面板由 JS portal 到 document.body 并按 fixed 定位;data-side 决定进场位移方向。
5
+ * 面板由 JS portal 到 document.body 并按 fixed 定位;data-icen-side 决定进场位移方向。
5
6
  * 规格源自 opengal overlay/dropdown + overlay/context-menu。
6
7
  *
7
8
  * 完整契约(dropdown):
8
- * <button class="menu-trigger pressable" data-menu-target="id" aria-haspopup="menu" aria-expanded="false">…</button>
9
- * <div class="menu" id="id" role="menu" data-side="bottom" hidden>
10
- * <div class="menu-label">组标题(可选)</div>
11
- * <button class="menu-item [.is-highlighted] [.is-disabled] [.menu-item--danger]" role="menuitem">
12
- * <span class="menu-item-icon">…svg…</span>
13
- * <span class="menu-item-label">文本</span>
14
- * <span class="menu-item-sub">副标题</span>
15
- * <span class="menu-item-shortcut">⌘S</span>
9
+ * <button class="menu-trigger icen-pressable" data-icen-dropdown-trigger aria-haspopup="menu" aria-expanded="false">…</button>
10
+ * <div class="icen-menu" id="id" role="menu" data-icen-side="bottom" hidden>
11
+ * <div class="icen-menu-label">组标题(可选)</div>
12
+ * <button class="icen-menu-item [.is-highlighted] [.is-disabled] [.icen-menu-item--danger]" role="menuitem">
13
+ * <span class="icen-menu-item-icon">…svg…</span>
14
+ * <span class="icen-menu-item-label">文本</span>
15
+ * <span class="icen-menu-item-sub">副标题</span>
16
+ * <span class="icen-menu-item-shortcut">⌘S</span>
16
17
  * </button>
17
- * <div class="menu-separator"></div>
18
- * <button class="menu-item menu-item--checked">
19
- * <span class="menu-item-check">✓</span>
20
- * <span class="menu-item-label">已选项</span>
18
+ * <div class="icen-menu-separator"></div>
19
+ * <button class="icen-menu-item icen-menu-item--checked">
20
+ * <span class="icen-menu-item-label">已选项</span>
21
21
  * </button>
22
22
  * </div>
23
23
  *
24
- * context-menu:附加 .menu--context(更窄宽度、更高 z-index)。
24
+ * context-menu:附加 .icen-menu--context(更窄宽度、更高 z-index)。
25
25
  * behavior 维护:键盘箭头导航 + .is-highlighted 跟随、Enter 触发、ESC 关闭、外部点击关闭。
26
26
  */
27
27
 
28
- .menu {
28
+ .icen-menu {
29
29
  position: fixed;
30
- z-index: var(--z-popover);
31
- min-width: 180px;
32
- max-width: 320px;
33
- max-height: min(70vh, 420px);
30
+ z-index: var(--icen-z-popover);
31
+ min-inline-size: 180px;
32
+ max-inline-size: 320px;
33
+ max-block-size: min(70vh, 420px);
34
34
  overflow-y: auto;
35
35
  overscroll-behavior: contain;
36
36
  margin: 0;
37
- padding: var(--density-space-xs);
38
- background: color-mix(in srgb, var(--token-card-strong) 92%, transparent);
37
+ padding: var(--icen-density-space-xs);
38
+ background: color-mix(in srgb, var(--icen-token-card-strong) 92%, transparent);
39
39
  backdrop-filter: blur(24px);
40
40
  -webkit-backdrop-filter: blur(24px);
41
- border: 1px solid var(--token-outline);
42
- box-shadow: var(--token-shadow-overlay);
43
- border-radius: var(--radius-lg);
44
- animation: icen-menu-in var(--menu-in-duration, var(--icen-tx-fast));
45
- }
46
- .menu[data-side='top'] { animation-name: icen-menu-in-top; }
47
- .menu[data-side='left'] { animation-name: icen-menu-in-left; }
48
- .menu[data-side='right'] { animation-name: icen-menu-in-right; }
41
+ border: 1px solid var(--icen-token-outline);
42
+ box-shadow: var(--icen-token-shadow-overlay);
43
+ border-radius: var(--icen-radius-lg);
44
+ transform-origin: top center;
45
+ animation: icen-menu-in var(--menu-in-duration, var(--icen-duration-fast)) var(--icen-ease-out);
46
+ }
47
+ .icen-menu[data-icen-state='closing'] { pointer-events: none; }
48
+ .icen-menu[data-icen-side='top'] { transform-origin: bottom center; }
49
+ .icen-menu[data-icen-side='top'] { animation-name: icen-menu-in-top; }
50
+ .icen-menu[data-icen-side='left'] { animation-name: icen-menu-in-left; }
51
+ .icen-menu[data-icen-side='right'] { animation-name: icen-menu-in-right; }
49
52
 
50
53
  /* 右键菜单:opengal context-menu 规格沿用 */
51
- .menu--context {
52
- min-width: 218px;
53
- max-width: 286px;
54
- z-index: var(--z-tooltip); /* 上下文菜单高于普通 popover,与 tooltip 平齐 */
54
+ .icen-menu--context {
55
+ min-inline-size: 218px;
56
+ max-inline-size: 286px;
57
+ z-index: var(--icen-z-tooltip); /* 上下文菜单高于普通 popover,与 tooltip 平齐 */
55
58
  --menu-in-duration: 100ms;
56
59
  }
57
60
 
58
61
  /* ── 分组标签 / 头(context-menu 的 header 项) ── */
59
- .menu-label {
60
- padding: var(--density-space-xs) var(--density-space-sm);
61
- font-size: var(--density-font-size-xs);
62
+ .icen-menu-label {
63
+ padding: var(--icen-density-space-xs) var(--icen-density-space-sm);
64
+ font-size: var(--icen-density-font-size-xs);
62
65
  font-weight: 600;
63
- text-transform: uppercase;
64
- letter-spacing: 0.08em;
65
- color: var(--token-text-faint);
66
+ color: var(--icen-token-text-faint);
66
67
  }
67
- .menu-header {
68
- padding: var(--density-space-sm) calc(var(--density-space-sm) + 2px) var(--density-space-xs);
68
+ .icen-menu-header {
69
+ padding: var(--icen-density-space-sm) calc(var(--icen-density-space-sm) + 2px) var(--icen-density-space-xs);
69
70
  }
70
- .menu-header-label {
71
+ .icen-menu-header-label {
71
72
  display: block;
72
73
  overflow: hidden;
73
74
  text-overflow: ellipsis;
74
75
  white-space: nowrap;
75
- font-size: var(--density-font-size-sm);
76
+ font-size: var(--icen-density-font-size-sm);
76
77
  font-weight: 500;
77
78
  line-height: 1.4;
78
- color: var(--token-text);
79
+ color: var(--icen-token-text);
79
80
  }
80
- .menu-header-desc {
81
+ .icen-menu-header-desc {
81
82
  display: block;
82
83
  overflow: hidden;
83
84
  text-overflow: ellipsis;
84
85
  white-space: nowrap;
85
- font-size: var(--density-font-size-xs);
86
+ font-size: var(--icen-density-font-size-xs);
86
87
  line-height: 1.4;
87
- color: var(--token-text-faint);
88
+ color: var(--icen-token-text-faint);
88
89
  }
89
90
 
90
91
  /* ── 菜单项 ── */
91
- .menu-item {
92
+ .icen-menu-item {
92
93
  position: relative;
93
94
  display: flex;
94
95
  align-items: center;
95
- gap: var(--density-space-xs);
96
+ gap: var(--icen-density-space-xs);
97
+ min-block-size: var(--icen-density-input-height-sm);
96
98
  width: 100%;
97
- padding: 6px var(--density-space-sm);
99
+ padding: 6px var(--icen-density-space-sm);
98
100
  background: none;
99
101
  border: 0;
100
102
  font: inherit;
101
- font-size: var(--density-font-size-sm);
102
- text-align: left;
103
- color: var(--token-text);
104
- border-radius: var(--radius-sm);
103
+ font-size: var(--icen-density-font-size-sm);
104
+ text-align: start;
105
+ color: var(--icen-token-text);
106
+ border-radius: var(--icen-radius-sm);
105
107
  cursor: pointer;
106
108
  user-select: none;
107
109
  transition:
108
110
  background-color var(--icen-tx-fast),
109
111
  color var(--icen-tx-fast);
110
112
  }
111
- .menu-item:hover:not(.is-disabled) {
112
- background: var(--token-fill-1);
113
+ .icen-menu-item:hover:not(.is-disabled) {
114
+ background: var(--icen-token-fill-1);
113
115
  }
114
- .menu-item.is-highlighted,
115
- .menu-item:focus-visible {
116
- background: var(--token-surface-hover);
117
- color: var(--token-accent);
116
+ .icen-menu-item.is-highlighted,
117
+ .icen-menu-item:focus-visible {
118
+ background: var(--icen-token-surface-hover);
119
+ color: var(--icen-token-accent);
118
120
  outline: none;
119
121
  }
120
- .menu-item--danger { color: var(--token-error); }
121
- .menu-item--danger.is-highlighted,
122
- .menu-item--danger:focus-visible {
123
- background: var(--token-error-muted);
124
- color: var(--token-error);
125
- }
126
- .menu-item.is-disabled,
127
- .menu-item:disabled,
128
- .menu-item[aria-disabled='true'] {
122
+ .icen-menu-item:focus-visible { outline: 2px solid var(--icen-token-accent); outline-offset: -2px; box-shadow: none; }
123
+ .icen-menu-item--danger { color: var(--icen-token-error); }
124
+ .icen-menu-item--danger.is-highlighted,
125
+ .icen-menu-item--danger:focus-visible {
126
+ background: var(--icen-token-error-muted);
127
+ color: var(--icen-token-error);
128
+ }
129
+ .icen-menu-item--danger:hover:not(.is-disabled):not(:disabled) { background: var(--icen-token-error-muted); }
130
+ .icen-menu-item.is-disabled,
131
+ .icen-menu-item:disabled,
132
+ .icen-menu-item[aria-disabled='true'] {
129
133
  opacity: var(--icen-disabled-opacity);
130
134
  pointer-events: none;
131
135
  }
132
136
 
133
- .menu-item-icon {
137
+ .icen-menu-item-icon {
134
138
  display: inline-flex;
135
139
  align-items: center;
136
140
  justify-content: center;
137
- width: 14px;
138
- height: 14px;
141
+ inline-size: 20px;
142
+ block-size: 20px;
139
143
  flex-shrink: 0;
140
144
  }
141
- .menu-item-icon:empty { width: 14px; height: auto; } /* 无图标时占位 */
142
- .menu-item-label {
145
+ .icen-menu-item-icon > svg { inline-size: 16px; block-size: 16px; }
146
+ .icen-menu:has(.icen-menu-item-icon) .icen-menu-item:not(:has(> .icen-menu-item-icon))::before {
147
+ content: '';
148
+ inline-size: 20px;
149
+ flex: none;
150
+ }
151
+ .icen-menu-item-label {
143
152
  flex: 1;
144
153
  min-width: 0;
145
154
  overflow: hidden;
146
155
  text-overflow: ellipsis;
147
156
  white-space: nowrap;
148
157
  }
149
- .menu-item-sub {
158
+ .icen-menu-item-sub {
150
159
  display: block;
151
- font-size: var(--density-font-size-xs);
160
+ font-size: var(--icen-density-font-size-xs);
152
161
  line-height: 1.3;
153
- color: var(--token-text-faint);
162
+ color: var(--icen-token-text-faint);
154
163
  margin-top: 2px;
155
164
  }
156
- .menu-item-shortcut {
157
- font-size: var(--density-font-size-xs);
158
- color: var(--token-text-faint);
159
- font-family: var(--font-mono);
160
- margin-left: var(--density-space-sm);
165
+ .icen-menu-item-shortcut {
166
+ font-size: var(--icen-density-font-size-xs);
167
+ color: var(--icen-token-text-faint);
168
+ font-family: var(--icen-font-mono);
169
+ margin-inline-start: var(--icen-density-space-sm);
170
+ white-space: nowrap;
171
+ flex: none;
161
172
  }
162
- .menu-item-chevron {
173
+ .icen-menu-item-chevron {
163
174
  width: 12px;
164
175
  height: 12px;
165
176
  flex-shrink: 0;
166
- color: var(--token-text-faint);
177
+ color: var(--icen-token-text-faint);
167
178
  }
168
179
 
169
- /* 勾选项:左勾 ✓ + 缩进 */
170
- .menu-item-check {
171
- position: absolute;
172
- left: var(--density-space-sm);
173
- top: 50%;
174
- transform: translateY(-50%);
175
- color: var(--token-accent);
176
- font-size: var(--density-font-size-md);
177
- line-height: 1;
178
- }
179
- .menu-item--checked { padding-left: 28px; }
180
+ /* Check slots are removed visually; checked items use the shared selected surface. */
181
+ .icen-menu-item-check { display: none; }
180
182
 
181
- .menu-separator {
182
- margin: var(--density-space-xs) calc(var(--density-space-sm) + 2px);
183
+ .icen-menu-separator {
184
+ margin: var(--icen-density-space-xs) calc(var(--icen-density-space-sm) + 2px);
183
185
  height: 1px;
184
- background: var(--token-line-soft);
186
+ background: var(--icen-token-line-soft);
185
187
  }
186
188
 
187
- /* ── 进场:fade + scale(.95→1),按侧别反向位移 8px ── */
189
+ /* ── 进场:fade + scale(.985→1),按侧别反向位移 3px(浮层统一收敛配方) ── */
188
190
  @keyframes icen-menu-in {
189
- from { opacity: 0; transform: scale(0.95) translateY(-8px); }
191
+ from { opacity: 0; transform: scale(0.985) translateY(-3px); }
190
192
  to { opacity: 1; transform: scale(1) translateY(0); }
191
193
  }
192
194
  @keyframes icen-menu-in-top {
193
- from { opacity: 0; transform: scale(0.95) translateY(8px); }
195
+ from { opacity: 0; transform: scale(0.985) translateY(3px); }
194
196
  to { opacity: 1; transform: scale(1) translateY(0); }
195
197
  }
196
198
  @keyframes icen-menu-in-left {
197
- from { opacity: 0; transform: scale(0.95) translateX(8px); }
199
+ from { opacity: 0; transform: scale(0.985) translateX(3px); }
198
200
  to { opacity: 1; transform: scale(1) translateX(0); }
199
201
  }
200
202
  @keyframes icen-menu-in-right {
201
- from { opacity: 0; transform: scale(0.95) translateX(-8px); }
203
+ from { opacity: 0; transform: scale(0.985) translateX(-3px); }
202
204
  to { opacity: 1; transform: scale(1) translateX(0); }
203
205
  }
204
206
 
205
207
  @media (prefers-reduced-motion: reduce) {
206
- .menu, .menu--context { animation: none; }
208
+ .icen-menu, .icen-menu--context { animation: none; }
207
209
  }
208
210
 
209
211
  /* 触屏:hover 永久开启(替代 hover 设备的悬停反馈) */
210
212
  @media (hover: none) {
211
- .menu-item:hover:not(.is-disabled) { background: transparent; }
213
+ .icen-menu-item:hover:not(.is-disabled) { background: transparent; }
214
+ }
215
+ @media (pointer: coarse) {
216
+ .icen-menu-item { min-block-size: 44px; }
217
+ }
218
+ [dir='rtl'] .icen-menu-item-chevron { transform: scaleX(-1); }
219
+
212
220
  }