@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
@@ -1,36 +1,37 @@
1
+ @layer icen.components {
1
2
  /*
2
3
  * @icen.ai/ui — Component: tabs(分区导航 / 子导航)
3
4
  *
4
5
  * 完整契约:
5
- * <div class="tabs" role="tablist"> ← 页面内分区
6
- * <button class="page-tab [.is-active]" role="tab" [aria-selected="true"]>…</button>
6
+ * <div class="icen-tabs" role="tablist"> ← 页面内分区
7
+ * <button class="icen-page-tab [.is-active]" role="tab" [aria-selected="true"]>…</button>
7
8
  * </div>
8
9
  *
9
- * <nav class="tabs" role="navigation"> ← 顶部子导航(a 链接)
10
+ * <icen-nav class="icen-tabs" role="navigation"> ← 顶部子导航(a 链接)
10
11
  * <a class="[.is-active]" [aria-current="page"] href="…">…</a>
11
- * </nav>
12
+ * </icen-nav>
12
13
  *
13
- * 与 behaviors/tabs 配套:[data-tabs] > [data-tab] + [data-tab-panel],行为层维护 aria。
14
+ * 与 behaviors/tabs 配套:[data-icen-tabs] > [data-icen-tab] + [data-icen-tab-panel],行为层维护 aria。
14
15
  * 窄屏换行不滚动(纪律:tab 条永不出现滚动条,一律 flex-wrap: wrap)。
15
16
  */
16
17
 
17
- .tabs {
18
+ .icen-tabs {
18
19
  display: flex;
19
20
  gap: 2px;
20
21
  flex-wrap: wrap;
21
- border-bottom: 1px solid var(--token-line-soft);
22
- margin-bottom: var(--density-space-lg);
22
+ border-bottom: 1px solid var(--icen-token-line-soft);
23
+ margin-bottom: var(--icen-density-space-lg);
23
24
  }
24
25
 
25
- .page-tab {
26
+ .icen-page-tab {
26
27
  background: none;
27
28
  border: 0;
28
29
  cursor: pointer;
29
- padding: var(--density-space-sm) var(--density-space-md);
30
- font-family: var(--font-mono);
31
- font-size: var(--density-font-size-md);
30
+ padding: var(--icen-density-space-sm) var(--icen-density-space-md);
31
+ font-family: var(--icen-font-mono);
32
+ font-size: var(--icen-density-font-size-md);
32
33
  letter-spacing: 0.05em;
33
- color: var(--token-text-muted);
34
+ color: var(--icen-token-text-muted);
34
35
  border-bottom: 2px solid transparent;
35
36
  margin-bottom: -1px;
36
37
  white-space: nowrap;
@@ -38,25 +39,25 @@
38
39
  color var(--icen-tx-fast),
39
40
  border-color var(--icen-tx-fast);
40
41
  }
41
- .page-tab:hover {
42
- color: var(--token-accent);
42
+ .icen-page-tab:hover {
43
+ color: var(--icen-token-accent);
43
44
  }
44
- .page-tab:focus-visible {
45
+ .icen-page-tab:focus-visible {
45
46
  outline: none;
46
- border-radius: var(--radius-sm);
47
+ border-radius: var(--icen-radius-sm);
47
48
  box-shadow: var(--icen-ring);
48
49
  }
49
- .page-tab.is-active,
50
- .page-tab[aria-selected='true'] {
51
- color: var(--token-accent);
52
- border-bottom-color: var(--token-accent);
50
+ .icen-page-tab.is-active,
51
+ .icen-page-tab[aria-selected='true'] {
52
+ color: var(--icen-token-accent-text, var(--icen-token-accent-deep, var(--icen-token-accent)));
53
+ border-bottom-color: var(--icen-token-accent);
53
54
  font-weight: 700;
54
55
  }
55
56
 
56
- .tabs a {
57
- padding: var(--density-space-sm) var(--density-space-md);
58
- font-size: var(--density-font-size-md);
59
- color: var(--token-text-muted);
57
+ .icen-tabs a {
58
+ padding: var(--icen-density-space-sm) var(--icen-density-space-md);
59
+ font-size: var(--icen-density-font-size-md);
60
+ color: var(--icen-token-text-muted);
60
61
  border-bottom: 2px solid transparent;
61
62
  margin-bottom: -1px;
62
63
  white-space: nowrap;
@@ -65,44 +66,44 @@
65
66
  color var(--icen-tx-fast),
66
67
  border-color var(--icen-tx-fast);
67
68
  }
68
- .tabs a:hover {
69
- color: var(--token-accent);
69
+ .icen-tabs a:hover {
70
+ color: var(--icen-token-accent);
70
71
  text-decoration: none;
71
72
  }
72
- .tabs a:focus-visible {
73
+ .icen-tabs a:focus-visible {
73
74
  outline: none;
74
- border-radius: var(--radius-sm);
75
+ border-radius: var(--icen-radius-sm);
75
76
  box-shadow: var(--icen-ring);
76
77
  }
77
- .tabs a.is-active,
78
- .tabs a[aria-current='page'] {
79
- color: var(--token-accent);
80
- border-bottom-color: var(--token-accent);
78
+ .icen-tabs a.is-active,
79
+ .icen-tabs a[aria-current='page'] {
80
+ color: var(--icen-token-accent);
81
+ border-bottom-color: var(--icen-token-accent);
81
82
  }
82
83
 
83
- /* 卡片变体(可选 .tabs--cards):tab 变成 pill,没有底边线 */
84
- .tabs--cards {
84
+ /* 卡片变体(可选 .icen-tabs--cards):tab 变成 pill,没有底边线 */
85
+ .icen-tabs--cards {
85
86
  border-bottom: 0;
86
- gap: var(--density-space-xs);
87
- margin-bottom: var(--density-space-md);
87
+ gap: var(--icen-density-space-xs);
88
+ margin-bottom: var(--icen-density-space-md);
88
89
  }
89
- .tabs--cards .page-tab {
90
- padding: var(--density-space-xs) var(--density-space-md);
91
- border: 1px solid var(--token-outline-soft);
92
- border-radius: var(--radius-full);
90
+ .icen-tabs--cards .icen-page-tab {
91
+ padding: var(--icen-density-space-xs) var(--icen-density-space-md);
92
+ border: 1px solid var(--icen-token-outline-soft);
93
+ border-radius: var(--icen-radius-full);
93
94
  margin-bottom: 0;
94
95
  }
95
- .tabs--cards .page-tab.is-active,
96
- .tabs--cards .page-tab[aria-selected='true'] {
97
- background: var(--token-accent);
98
- color: var(--token-on-accent);
99
- border-color: var(--token-accent);
96
+ .icen-tabs--cards .icen-page-tab.is-active,
97
+ .icen-tabs--cards .icen-page-tab[aria-selected='true'] {
98
+ background: var(--icen-token-accent-strong);
99
+ color: var(--icen-token-on-accent);
100
+ border-color: var(--icen-token-accent-strong);
100
101
  font-weight: 500;
101
102
  }
102
103
 
103
104
  /* 等宽变体:tab 平均占满容器 */
104
- .tabs--equal .page-tab,
105
- .tabs--equal a {
105
+ .icen-tabs--equal .icen-page-tab,
106
+ .icen-tabs--equal a {
106
107
  flex: 1;
107
108
  text-align: center;
108
109
  }
@@ -110,137 +111,142 @@
110
111
  /* ── 增强 ── */
111
112
 
112
113
  /* 尺寸变体 */
113
- .tabs--sm .page-tab {
114
- padding: var(--density-space-xs) var(--density-space-sm);
115
- font-size: var(--density-font-size-sm);
114
+ .icen-tabs--sm .icen-page-tab {
115
+ padding: var(--icen-density-space-xs) var(--icen-density-space-sm);
116
+ font-size: var(--icen-density-font-size-sm);
116
117
  }
117
- .tabs--lg .page-tab {
118
- padding: var(--density-space-md) calc(var(--density-space-md) + 4px);
119
- font-size: var(--density-font-size-lg);
118
+ .icen-tabs--lg .icen-page-tab {
119
+ padding: var(--icen-density-space-md) calc(var(--icen-density-space-md) + 4px);
120
+ font-size: var(--icen-density-font-size-lg);
120
121
  }
121
122
 
122
123
  /* Tab 带图标 */
123
- .page-tab-icon {
124
+ .icen-page-tab-icon {
124
125
  width: 14px;
125
126
  height: 14px;
126
127
  flex-shrink: 0;
127
- margin-right: 2px;
128
+ margin-inline-end: 2px;
128
129
  }
129
130
 
130
131
  /* Tab 带徽章/计数 */
131
- .page-tab-badge {
132
+ .icen-page-tab-badge {
132
133
  display: inline-flex;
133
134
  align-items: center;
134
135
  justify-content: center;
135
136
  min-width: 18px;
136
137
  height: 18px;
137
138
  padding: 0 5px;
138
- margin-left: var(--density-space-xs);
139
- font-size: var(--density-font-size-2xs);
139
+ margin-inline-start: var(--icen-density-space-xs);
140
+ font-size: var(--icen-density-font-size-2xs);
140
141
  font-weight: 600;
141
- color: var(--token-text-faint);
142
- background: var(--token-fill-2);
143
- border-radius: var(--radius-full);
142
+ color: var(--icen-token-text-faint);
143
+ background: var(--icen-token-fill-2);
144
+ border-radius: var(--icen-radius-full);
144
145
  font-variant-numeric: tabular-nums;
145
146
  line-height: 1;
146
147
  }
147
- .page-tab.is-active .page-tab-badge,
148
- .page-tab[aria-selected='true'] .page-tab-badge {
149
- background: var(--token-accent);
150
- color: var(--token-on-accent);
148
+ .icen-page-tab.is-active .icen-page-tab-badge,
149
+ .icen-page-tab[aria-selected='true'] .icen-page-tab-badge {
150
+ background: var(--icen-token-accent-strong);
151
+ color: var(--icen-token-on-accent);
151
152
  }
152
153
 
153
154
  /* 可关闭 tab */
154
- .page-tab-close {
155
+ .icen-page-tab-close {
155
156
  display: inline-flex;
156
157
  align-items: center;
157
158
  justify-content: center;
158
159
  width: 16px;
159
160
  height: 16px;
160
- margin-left: var(--density-space-xs);
161
- margin-right: -4px;
161
+ margin-inline-start: var(--icen-density-space-xs);
162
+ margin-inline-end: -4px;
162
163
  padding: 0;
163
164
  border: 0;
164
- border-radius: var(--radius-full);
165
+ border-radius: var(--icen-radius-full);
165
166
  background: transparent;
166
- color: var(--token-text-faint);
167
+ color: var(--icen-token-text-faint);
167
168
  cursor: pointer;
168
169
  transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast);
169
170
  }
170
- .page-tab-close:hover {
171
- color: var(--token-error);
172
- background: var(--token-error-muted);
171
+ .icen-page-tab-close:hover {
172
+ color: var(--icen-token-error);
173
+ background: var(--icen-token-error-muted);
173
174
  }
174
- .page-tab-close svg { width: 10px; height: 10px; }
175
+ .icen-page-tab-close svg { width: 10px; height: 10px; }
175
176
 
176
177
  /* 分段式 tab(替代底边线,用 segmented 视觉) */
177
- .tabs--segment {
178
+ .icen-tabs--segment {
178
179
  display: inline-flex;
179
180
  border-bottom: none;
180
181
  gap: 2px;
181
182
  padding: 2px;
182
- background: var(--token-panel);
183
- border: 1px solid var(--token-outline-soft);
184
- border-radius: var(--radius-md);
185
- box-shadow: var(--token-shadow-inset);
183
+ background: var(--icen-token-panel);
184
+ border: 1px solid var(--icen-token-outline-soft);
185
+ border-radius: var(--icen-radius-md);
186
+ box-shadow: var(--icen-token-shadow-inset);
186
187
  }
187
- .tabs--segment .page-tab {
188
+ .icen-tabs--segment .icen-page-tab {
188
189
  border-bottom: none;
189
190
  margin-bottom: 0;
190
- padding: var(--density-space-xs) var(--density-space-md);
191
- border-radius: var(--radius-sm);
191
+ padding: var(--icen-density-space-xs) var(--icen-density-space-md);
192
+ border-radius: var(--icen-radius-sm);
192
193
  }
193
- .tabs--segment .page-tab.is-active,
194
- .tabs--segment .page-tab[aria-selected='true'] {
195
- background: var(--token-accent);
196
- color: var(--token-on-accent);
194
+ .icen-tabs--segment .icen-page-tab.is-active,
195
+ .icen-tabs--segment .icen-page-tab[aria-selected='true'] {
196
+ background: var(--icen-token-accent-strong);
197
+ color: var(--icen-token-on-accent);
197
198
  border-bottom-color: transparent;
198
199
  font-weight: 500;
199
200
  }
200
201
 
201
- /* 垂直 tab(侧栏式) */
202
- .tabs--vertical {
202
+ /* 垂直 tab(侧栏式):轨道与指示条在 inline-end 侧,RTL 自动镜像到左缘 */
203
+ .icen-tabs--vertical {
203
204
  flex-direction: column;
204
205
  border-bottom: none;
205
- border-right: 1px solid var(--token-line-soft);
206
+ border-inline-end: 1px solid var(--icen-token-line-soft);
206
207
  margin-bottom: 0;
207
- min-width: 160px;
208
+ min-inline-size: 160px;
208
209
  }
209
- .tabs--vertical .page-tab {
210
+ .icen-tabs--vertical .icen-page-tab {
210
211
  border-bottom: none;
211
- border-right: 2px solid transparent;
212
+ border-inline-end: 2px solid transparent;
212
213
  margin-bottom: 0;
213
- margin-right: -1px;
214
+ margin-inline-end: -1px;
214
215
  }
215
- .tabs--vertical .page-tab.is-active,
216
- .tabs--vertical .page-tab[aria-selected='true'] {
217
- border-right-color: var(--token-accent);
216
+ .icen-tabs--vertical .icen-page-tab.is-active,
217
+ .icen-tabs--vertical .icen-page-tab[aria-selected='true'] {
218
+ border-inline-end-color: var(--icen-token-accent);
218
219
  border-bottom-color: transparent;
219
220
  }
220
221
 
221
222
  @media (prefers-reduced-motion: reduce) {
222
- .page-tab, .tabs a, .page-tab-close { transition: none; }
223
+ .icen-page-tab, .icen-tabs a, .icen-page-tab-close { transition: none; }
223
224
  }
224
225
 
225
- /* ── 指示条([data-tabs-ink],与 behaviors/tabs 配套;本节为追加)── */
226
- /* tablist(.tabs)挂 data-tabs-ink 时,行为层创建并移动 .tabs-ink:
226
+ /* ── 指示条([data-icen-tabs-ink],与 behaviors/tabs 配套;本节为追加)── */
227
+ /* tablist(.icen-tabs)挂 data-icen-tabs-ink 时,行为层创建并移动 .icen-tabs-ink:
227
228
  宽 / translateX 由 JS 内联写入(布局定位,同 popover 模式);
228
229
  此处只负责视觉(高度 / 圆角 / 背景)与位移过渡(--duration / --ease token)。 */
229
- .tabs[data-tabs-ink] {
230
+ .icen-tabs[data-icen-tabs-ink] {
230
231
  position: relative;
231
232
  }
232
- .tabs-ink {
233
+ /* 挂墨水条时,活动 tab 自身的下划线让位(不双画) */
234
+ .icen-tabs[data-icen-tabs-ink] .icen-page-tab.is-active,
235
+ .icen-tabs[data-icen-tabs-ink] .icen-page-tab[aria-selected='true'] { border-bottom-color: transparent; }
236
+ .icen-tabs-ink {
233
237
  position: absolute;
234
238
  bottom: -1px; /* 盖在容器 1px 底边线上,与活动 tab 的 2px 下划线同高 */
235
- left: 0;
239
+ left: 0; /* guard:allow-physical 指示条由 JS 内联写 width/translateX 定位(popover 同模式),原点取物理左缘由布局函数计算 */
236
240
  height: 2px;
237
- border-radius: var(--radius-full);
238
- background: var(--token-accent);
241
+ border-radius: var(--icen-radius-full);
242
+ background: var(--icen-token-accent);
239
243
  pointer-events: none;
240
244
  transition:
241
- width var(--duration-normal) var(--ease-out),
242
- transform var(--duration-normal) var(--ease-out);
245
+ width var(--icen-duration-normal) var(--icen-ease-out),
246
+ transform var(--icen-duration-normal) var(--icen-ease-out);
243
247
  }
244
248
  @media (prefers-reduced-motion: reduce) {
245
- .tabs-ink { transition: none; }
249
+ .icen-tabs-ink { transition: none; }
250
+ }
251
+
246
252
  }
@@ -1,139 +1,54 @@
1
- /*
2
- * @icen.ai/ui — Component: tag-input(多值标签编辑)
3
- * 规格源自 opengal primitives/advanced-input.tsx 的 TagInput;与 behaviors/tag-input.ts 配套。
4
- *
5
- * 完整契约:
6
- * <div class="tag-input control [.tag-input--sm|.tag-input--lg] [.is-disabled]"
7
- * data-tags="初始,标签" data-max="5" data-duplicate="false|true">
8
- * <input class="tag-input-field" placeholder="…" />
9
- * </div>
10
- *
11
- * behavior 渲染:
12
- * - 解析 data-tags → 渲染 .tag-chip(含 .tag-chip-x 删除钮),input 放在末尾
13
- * - 达到 data-max 时容器加 .is-max(warning 色边框)并拒加
14
- * - data-duplicate="false" 时重复值被拒绝(短暂 .is-shake 抖动反馈)
15
- * - 删除钮 Enter/Space 触发,删后 input 自动聚焦
1
+ @layer icen.components {
2
+ /* Tag editor: native input.icen-tag-input-field inside .icen-tag-input.
3
+ * Behavior adds stable .icen-tag-chip > bdi.icen-tag-chip-label +
4
+ * button.icen-tag-chip-x, an optical .icen-tag-input-count, hidden native form
5
+ * entries, and an adjacent .icen-tag-input-feedback[role=status].
6
+ * --sm / --lg vary density; data-icen-readonly keeps labels without actions.
7
+ * is-max is a capacity state, is-unavailable follows actual disabled state.
16
8
  */
17
-
18
- .tag-input {
9
+ .icen-tag-input {
10
+ --tag-action-size: calc(var(--icen-density-input-height-md) - var(--icen-density-space-xs) * 2 - 2px);
19
11
  display: flex;
20
12
  flex-wrap: wrap;
21
13
  align-items: center;
22
- gap: var(--density-space-xs);
23
- padding: var(--density-space-xs);
24
- min-height: var(--density-input-height-md);
25
- background: var(--token-control);
26
- border: 1px solid var(--token-outline-soft);
27
- border-radius: var(--radius-md);
28
- box-shadow: var(--token-shadow-inset);
29
- transition:
30
- border-color var(--icen-tx-fast),
31
- box-shadow var(--icen-tx-fast);
32
- }
33
- .tag-input:hover {
34
- border-color: var(--icen-hover-border);
35
- }
36
- .tag-input:focus-within {
37
- border-color: var(--icen-control-focus-border);
38
- box-shadow: var(--icen-control-focus-shadow);
39
- }
40
- .tag-input.is-max,
41
- .tag-input.is-max:focus-within {
42
- border-color: color-mix(in srgb, var(--token-warning) 60%, transparent);
43
- box-shadow: var(--icen-ring-warning);
44
- }
45
- .tag-input.is-disabled,
46
- .tag-input[aria-disabled='true'],
47
- .tag-input[data-disabled] {
48
- opacity: var(--icen-disabled-opacity);
49
- background: var(--token-bg-soft);
50
- cursor: not-allowed;
51
- pointer-events: none;
52
- }
53
- .tag-input.is-disabled .tag-input-field { cursor: not-allowed; }
54
- .tag-input.is-disabled .tag-chip-x { pointer-events: none; }
55
-
56
- .tag-input--sm { min-height: var(--density-input-height-sm); }
57
- .tag-input--lg { min-height: var(--density-input-height-lg); }
58
-
59
- .tag-chip {
60
- display: inline-flex;
61
- align-items: center;
62
- gap: 4px;
63
- padding: 2px 4px 2px var(--density-space-xs);
64
- border-radius: var(--radius-full);
65
- background: var(--token-accent-subtle);
66
- color: var(--token-accent);
67
- font-size: var(--density-font-size-xs);
68
- font-weight: 500;
69
- line-height: 1.4;
70
- max-width: 100%;
71
- animation: tag-pop var(--icen-tx-fast);
72
- }
73
- /* readonly 变体(消费方手写标记,behavior 不产出) */
74
- .tag-chip--readonly { background: var(--token-fill-2); color: var(--token-text-muted); }
75
-
76
- @keyframes tag-pop {
77
- from { opacity: 0; transform: scale(0.85); }
78
- to { opacity: 1; transform: scale(1); }
79
- }
80
- @media (prefers-reduced-motion: reduce) {
81
- .tag-chip { animation: none; }
82
- }
83
-
84
- .tag-chip-x {
85
- display: inline-flex;
86
- align-items: center;
87
- justify-content: center;
88
- width: 16px;
89
- height: 16px;
90
- padding: 0;
91
- border: none;
92
- background: transparent;
93
- cursor: pointer;
94
- border-radius: var(--radius-full);
95
- color: inherit;
96
- font-size: var(--density-font-size-xs);
97
- line-height: 1;
98
- opacity: 0.7;
99
- transition:
100
- background-color var(--icen-tx-fast),
101
- opacity var(--icen-tx-fast),
102
- color var(--icen-tx-fast);
103
- }
104
- .tag-chip-x:hover {
105
- opacity: 1;
106
- background: color-mix(in srgb, currentColor 18%, transparent);
107
- color: var(--token-on-accent);
108
- }
109
- .tag-chip-x:focus-visible {
110
- outline: none;
111
- opacity: 1;
112
- box-shadow: var(--icen-ring);
113
- }
114
- .tag-chip-x svg { width: 10px; height: 10px; }
14
+ gap: var(--icen-density-space-xs);
15
+ padding: var(--icen-density-space-xs);
16
+ min-block-size: var(--icen-density-input-height-md);
17
+ background: var(--icen-token-control);
18
+ border: 1px solid var(--icen-token-outline-soft);
19
+ border-radius: var(--icen-radius-md);
20
+ box-shadow: var(--icen-token-shadow-inset);
21
+ transition: border-color var(--icen-tx-fast), box-shadow var(--icen-tx-fast);
22
+ }
23
+ .icen-tag-input:focus-within { border-color: var(--icen-control-focus-border); box-shadow: var(--icen-control-focus-shadow); }
24
+ .icen-tag-input--sm { --tag-action-size: calc(var(--icen-density-input-height-sm) - var(--icen-density-space-xs) * 2 - 2px); min-block-size: var(--icen-density-input-height-sm); }
25
+ .icen-tag-input--lg { --tag-action-size: calc(var(--icen-density-input-height-lg) - var(--icen-density-space-xs) * 2 - 2px); min-block-size: var(--icen-density-input-height-lg); }
26
+ .icen-tag-input:is(.is-disabled,.is-unavailable,[aria-disabled='true'],[data-icen-disabled]) { background: var(--icen-token-bg-soft); cursor: not-allowed; }
27
+ .icen-tag-input.is-unavailable > .icen-tag-chip { background: var(--icen-token-fill-2); color: var(--icen-token-text-muted); }
28
+ .icen-tag-input.is-unavailable .icen-tag-chip-x { visibility: hidden; }
29
+ .icen-tag-input.is-unavailable :is(.icen-tag-input-field,.icen-tag-chip-x) { cursor: not-allowed; }
30
+ .icen-tag-chip { display: inline-flex; align-items: center; gap: var(--icen-density-space-xs); padding-inline-start: var(--icen-density-space-sm); border-radius: var(--icen-radius-full); background: var(--icen-token-accent-subtle); color: var(--icen-token-accent-text,var(--icen-token-text)); font-size: var(--icen-density-font-size-sm); font-weight: 500; line-height: 1.4; max-inline-size: 100%; min-inline-size: 0; animation: icen-pop-in var(--icen-tx-fast); }
31
+ .icen-tag-chip-label { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
32
+ .icen-tag-chip--readonly, .is-readonly > .icen-tag-chip { background: var(--icen-token-fill-2); color: var(--icen-token-text-muted); padding-inline: var(--icen-density-space-sm); min-block-size: var(--tag-action-size); }
33
+ .icen-tag-chip-x { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; inline-size: var(--tag-action-size); block-size: var(--tag-action-size); padding: 0; border: 0; border-radius: var(--icen-radius-full); color: inherit; background: transparent; cursor: pointer; transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast), opacity var(--icen-tx-fast); }
34
+ .icen-tag-chip-x svg { inline-size: 12px; block-size: 12px; pointer-events: none; }
35
+ .icen-tag-chip-x[hidden] { display: none; }
36
+ .icen-tag-chip-x:focus-visible { outline: 2px solid var(--icen-token-accent); outline-offset: -2px; opacity: 1; }
37
+ .icen-tag-input-field { flex: 1 1 6ch; min-inline-size: 6ch; max-inline-size: 100%; padding: var(--icen-density-space-xs); border: 0; background: transparent; outline: none; color: var(--icen-token-text); font: inherit; font-size: var(--icen-density-font-size-sm); }
38
+ .icen-tag-input-field::placeholder { color: var(--icen-token-text-muted); opacity: 1; }
39
+ .icen-tag-input--sm :is(.icen-tag-chip,.icen-tag-input-field) { font-size: var(--icen-density-font-size-xs); }
40
+ .icen-tag-input--lg :is(.icen-tag-chip,.icen-tag-input-field) { font-size: var(--icen-density-font-size-md); }
41
+ .icen-tag-input-count { flex: 0 0 auto; padding-inline: var(--icen-density-space-xs); color: var(--icen-token-text-muted); font-size: var(--icen-density-font-size-xs); font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; }
42
+ .icen-tag-input-feedback { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }
43
+ .icen-tag-input-feedback.is-visible { position: static; display: block; inline-size: auto; block-size: auto; margin-block-start: var(--icen-density-space-xs); overflow: visible; clip-path: none; color: var(--icen-token-text-muted); font-size: var(--icen-density-font-size-sm); }
44
+ @media (hover: hover) and (pointer: fine) {
45
+ .icen-tag-input:not(.is-unavailable):hover { border-color: var(--icen-hover-border); }
46
+ .icen-tag-chip-x { opacity: 0; }
47
+ .icen-tag-chip:is(:hover,:focus-within) .icen-tag-chip-x { opacity: 1; }
48
+ .icen-tag-chip-x:hover { background: var(--icen-token-fill-2); }
49
+ }
50
+ @media (pointer: coarse) { .icen-tag-chip-x { min-inline-size: 44px; min-block-size: 44px; opacity: 1; } .icen-tag-input-field { min-block-size: 44px; } }
51
+ @media (prefers-reduced-motion: reduce) { .icen-tag-chip { animation: none; } .icen-tag-input, .icen-tag-chip-x { transition: none; } }
52
+ @media (forced-colors: active) { .icen-tag-chip { border: 1px solid CanvasText; } .icen-tag-chip-x:focus-visible { outline-color: Highlight; } }
115
53
 
116
- .tag-input-field {
117
- flex: 1;
118
- min-width: 80px;
119
- padding: 2px;
120
- background: transparent;
121
- border: none;
122
- outline: none;
123
- color: var(--token-text);
124
- font: inherit;
125
- font-size: var(--density-font-size-sm);
126
- }
127
- .tag-input-field::placeholder {
128
- color: color-mix(in srgb, var(--token-text-faint) 60%, transparent);
129
- }
130
-
131
- /* 重复值抖动反馈(behavior 短暂挂 is-shake) */
132
- .tag-input.is-shake {
133
- animation: tag-shake var(--tag-shake-duration, 0.32s) var(--ease-out);
134
- }
135
- @keyframes tag-shake {
136
- 0%, 100% { transform: translateX(0); }
137
- 20%, 60% { transform: translateX(-3px); }
138
- 40%, 80% { transform: translateX(3px); }
139
54
  }