@icen.ai/ui 0.5.0 → 0.8.1

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 (151) hide show
  1. package/AGENTS.md +262 -0
  2. package/README.md +52 -13
  3. package/dist/base.css +33 -5
  4. package/dist/behaviors/accordion.d.mts +7 -0
  5. package/dist/behaviors/accordion.mjs +37 -11
  6. package/dist/behaviors/ai-chat.d.mts +59 -0
  7. package/dist/behaviors/ai-chat.mjs +580 -0
  8. package/dist/behaviors/ai-composer.d.mts +137 -0
  9. package/dist/behaviors/ai-composer.mjs +2114 -0
  10. package/dist/behaviors/ai-core.d.mts +156 -0
  11. package/dist/behaviors/ai-core.mjs +504 -0
  12. package/dist/behaviors/ai-diff.d.mts +53 -0
  13. package/dist/behaviors/ai-diff.mjs +413 -0
  14. package/dist/behaviors/ai-panel.d.mts +101 -0
  15. package/dist/behaviors/ai-panel.mjs +1087 -0
  16. package/dist/behaviors/ai-provider.d.mts +198 -0
  17. package/dist/behaviors/ai-provider.mjs +1061 -0
  18. package/dist/behaviors/ai-tool.d.mts +26 -0
  19. package/dist/behaviors/ai-tool.mjs +2173 -0
  20. package/dist/behaviors/ai-tools.d.mts +84 -0
  21. package/dist/behaviors/ai-tools.mjs +1762 -0
  22. package/dist/behaviors/back-top.d.mts +20 -0
  23. package/dist/behaviors/back-top.mjs +64 -32
  24. package/dist/behaviors/carousel.d.mts +7 -0
  25. package/dist/behaviors/carousel.mjs +72 -27
  26. package/dist/behaviors/charts.d.mts +296 -0
  27. package/dist/behaviors/charts.mjs +1364 -440
  28. package/dist/behaviors/command-palette.d.mts +42 -0
  29. package/dist/behaviors/command-palette.mjs +167 -27
  30. package/dist/behaviors/context-menu.d.mts +53 -0
  31. package/dist/behaviors/context-menu.mjs +127 -39
  32. package/dist/behaviors/controls.d.mts +59 -0
  33. package/dist/behaviors/controls.mjs +601 -0
  34. package/dist/behaviors/copy.d.mts +7 -0
  35. package/dist/behaviors/copy.mjs +41 -15
  36. package/dist/behaviors/datatable.d.mts +90 -0
  37. package/dist/behaviors/datatable.mjs +279 -53
  38. package/dist/behaviors/date-picker.d.mts +4 -0
  39. package/dist/behaviors/date-picker.mjs +276 -69
  40. package/dist/behaviors/dropdown.d.mts +8 -0
  41. package/dist/behaviors/dropdown.mjs +171 -28
  42. package/dist/behaviors/events.d.mts +330 -0
  43. package/dist/behaviors/events.mjs +208 -0
  44. package/dist/behaviors/input.d.mts +4 -0
  45. package/dist/behaviors/input.mjs +52 -32
  46. package/dist/behaviors/modal.d.mts +30 -0
  47. package/dist/behaviors/modal.mjs +87 -16
  48. package/dist/behaviors/nav.d.mts +7 -0
  49. package/dist/behaviors/nav.mjs +57 -15
  50. package/dist/behaviors/notification.d.mts +188 -0
  51. package/dist/behaviors/notification.mjs +274 -140
  52. package/dist/behaviors/popover.d.mts +82 -0
  53. package/dist/behaviors/popover.mjs +92 -5
  54. package/dist/behaviors/select.d.mts +6 -0
  55. package/dist/behaviors/select.mjs +287 -45
  56. package/dist/behaviors/sidebar.d.mts +7 -0
  57. package/dist/behaviors/sidebar.mjs +44 -13
  58. package/dist/behaviors/slider.d.mts +7 -0
  59. package/dist/behaviors/slider.mjs +55 -43
  60. package/dist/behaviors/split-pane.d.mts +8 -0
  61. package/dist/behaviors/split-pane.mjs +70 -29
  62. package/dist/behaviors/tabs.d.mts +9 -0
  63. package/dist/behaviors/tabs.mjs +102 -26
  64. package/dist/behaviors/tag-input.d.mts +7 -0
  65. package/dist/behaviors/tag-input.mjs +66 -17
  66. package/dist/behaviors/theme.d.mts +36 -0
  67. package/dist/behaviors/theme.mjs +51 -5
  68. package/dist/behaviors/toast.d.mts +48 -0
  69. package/dist/behaviors/toast.mjs +98 -25
  70. package/dist/behaviors/tree.d.mts +7 -0
  71. package/dist/behaviors/tree.mjs +39 -15
  72. package/dist/behaviors/upload.d.mts +4 -0
  73. package/dist/behaviors/upload.mjs +79 -44
  74. package/dist/cli.mjs +1 -1
  75. package/dist/components/ai-chat.css +1037 -0
  76. package/dist/components/ai-chat.mjs +3 -0
  77. package/dist/components/ai-composer.mjs +3 -0
  78. package/dist/components/ai-context.mjs +2 -0
  79. package/dist/components/ai-diff.css +311 -0
  80. package/dist/components/ai-diff.mjs +3 -0
  81. package/dist/components/ai-files.mjs +3 -0
  82. package/dist/components/ai-message.mjs +3 -0
  83. package/dist/components/ai-panel.css +682 -0
  84. package/dist/components/ai-reasoning.mjs +3 -0
  85. package/dist/components/ai-subagent.mjs +2 -0
  86. package/dist/components/ai-todo.mjs +2 -0
  87. package/dist/components/ai-tool-call.mjs +2 -0
  88. package/dist/components/ai-tool.css +532 -0
  89. package/dist/components/ai-usage.mjs +3 -0
  90. package/dist/components/badge.css +5 -9
  91. package/dist/components/breadcrumb.css +0 -36
  92. package/dist/components/btn.css +4 -7
  93. package/dist/components/card.css +3 -6
  94. package/dist/components/chart-bar.css +10 -0
  95. package/dist/components/chart-calendar.mjs +4 -0
  96. package/dist/components/chart-gauge.css +1 -1
  97. package/dist/components/chart-heatmap.css +40 -0
  98. package/dist/components/chart-pie.css +0 -6
  99. package/dist/components/chart-scatter.css +24 -0
  100. package/dist/components/chart-scatter.mjs +4 -0
  101. package/dist/components/charts.css +87 -2
  102. package/dist/components/charts.mjs +1 -0
  103. package/dist/components/command-palette.css +2 -2
  104. package/dist/components/content.css +11 -25
  105. package/dist/components/copy.css +8 -8
  106. package/dist/components/datatable.css +5 -9
  107. package/dist/components/date-picker.css +4 -8
  108. package/dist/components/empty.css +0 -4
  109. package/dist/components/feedback.css +10 -17
  110. package/dist/components/form.css +13 -14
  111. package/dist/components/input.css +2 -2
  112. package/dist/components/layout.css +36 -36
  113. package/dist/components/media.css +12 -8
  114. package/dist/components/menu.css +2 -2
  115. package/dist/components/modal.css +1 -1
  116. package/dist/components/nav.css +11 -6
  117. package/dist/components/notification.css +27 -28
  118. package/dist/components/pagination.css +4 -2
  119. package/dist/components/pagination.mjs +1 -0
  120. package/dist/components/panel.css +16 -16
  121. package/dist/components/pill.css +15 -15
  122. package/dist/components/rating.mjs +1 -0
  123. package/dist/components/segmented.css +14 -6
  124. package/dist/components/segmented.mjs +1 -0
  125. package/dist/components/select.css +79 -24
  126. package/dist/components/sidebar.css +1 -1
  127. package/dist/components/split-pane.css +0 -1
  128. package/dist/components/stat.css +14 -18
  129. package/dist/components/steps.css +15 -5
  130. package/dist/components/steps.mjs +1 -0
  131. package/dist/components/switch.css +11 -13
  132. package/dist/components/switch.mjs +1 -0
  133. package/dist/components/table.css +46 -47
  134. package/dist/components/table.mjs +1 -0
  135. package/dist/components/tabs.css +57 -45
  136. package/dist/components/tag-input.css +5 -10
  137. package/dist/components/toast.css +16 -13
  138. package/dist/components/tooltip.css +2 -2
  139. package/dist/components/upload.css +0 -15
  140. package/dist/index.d.mts +39 -0
  141. package/dist/index.mjs +11243 -3312
  142. package/dist/registry.json +147 -9
  143. package/dist/retro-effects.css +23 -32
  144. package/dist/tokens/colors.css +4 -1
  145. package/dist/tokens/retro-effects.css +23 -32
  146. package/dist/tokens/style-profiles.css +24 -2
  147. package/dist/tokens/typography.css +2 -0
  148. package/dist/tokens.css +30 -3
  149. package/dist/ui.css +3420 -645
  150. package/docs/spec/ai-native.md +662 -0
  151. package/package.json +15 -5
@@ -0,0 +1,532 @@
1
+ /*
2
+ * @icen.ai/ui — Component: ai-tool(AI 工具调用卡 + 子智能体卡;含 .ai-item 条目基元完整定义)
3
+ *
4
+ * 完整契约:
5
+ * ── 条目基元 .ai-item(规格 §2 骨架:所有行式 AI 条目的"基类",todo/panel 亦复用)──
6
+ * <div class="ai-item is-running" style="--ai-item-tint: var(--token-accent)">
7
+ * <span class="ai-item-icon"><!-- svg --></span>
8
+ * <div class="ai-item-main">
9
+ * <div class="ai-item-title">一行摘要</div>
10
+ * <div class="ai-item-sub">次要信息(路径/参数)</div>
11
+ * </div>
12
+ * <div class="ai-item-side">
13
+ * <span class="ai-item-status"></span> ← 状态点,纯 CSS 由 .is-* 驱动
14
+ * <span class="ai-item-meta">1.2s</span>
15
+ * </div>
16
+ * <div class="ai-item-detail" hidden>展开详情</div>
17
+ * </div>
18
+ *
19
+ * ── 工具调用卡(.ai-tool-head 复用 .ai-item-* 零件,不带 .ai-item 壳)──
20
+ * <div class="ai-tool ai-tool--shell is-done" data-ai-id="…" data-ai-kind="shell">
21
+ * <button class="ai-tool-head" type="button" aria-expanded="false">
22
+ * <span class="ai-item-icon" aria-hidden="true">…svg…</span>
23
+ * <span class="ai-item-main">
24
+ * <span class="ai-item-title">Read</span>
25
+ * <span class="ai-item-sub">src/foo.ts:1-50</span>
26
+ * </span>
27
+ * <span class="ai-item-status" role="img" aria-label="完成"></span>
28
+ * <span class="ai-item-meta">0.4s</span>
29
+ * </button>
30
+ * <div class="ai-tool-body" hidden>
31
+ * <div class="ai-tool-io"><div class="ai-tool-io-label">输入</div><pre class="ai-tool-io-content">…</pre></div>
32
+ * <div class="ai-tool-io"><div class="ai-tool-io-label">输出</div><pre class="ai-tool-io-content">…</pre></div>
33
+ * <div class="ai-tool-approval"> ← 仅 .is-approval 显示(纯 CSS 驱动)
34
+ * <div class="ai-tool-approval-reason" hidden>审批原因</div> ← 可选(model.approval.reason)
35
+ * <button class="btn btn-sm btn-primary" data-ai-approve type="button">允许</button>
36
+ * <button class="btn btn-sm" data-ai-reject type="button">拒绝</button>
37
+ * </div>
38
+ * </div>
39
+ * </div>
40
+ *
41
+ * ── 子智能体卡 ──
42
+ * <div class="ai-subagent is-running" data-ai-id="…" data-ai-kind="subagent">
43
+ * <button class="ai-subagent-head" type="button" aria-expanded="false">…head 结构同上…</button>
44
+ * <div class="ai-subagent-body" hidden>
45
+ * <div class="ai-subagent-stream"> ← 嵌套 .ai-tool / .ai-subagent;
46
+ * … 行间 style="--ai-activity-index:i" 驱动渐入 stagger
47
+ * </div>
48
+ * <div class="ai-subagent-result">完成回执摘要</div>
49
+ * </div>
50
+ * </div>
51
+ *
52
+ * 状态机 7 态(全条目共享,规格 §1):
53
+ * .is-pending faint 空心点
54
+ * .is-running tint 脉冲点(--ai-item-pulse-duration 变量化时长)
55
+ * .is-streaming ▍流式光标(colors.css blink keyframes,--ai-item-blink-duration 变量化)
56
+ * .is-approval warning 点 + 外环;卡片边框 warning;显示审批按钮
57
+ * .is-done success 纯 CSS 对勾
58
+ * .is-error error 点 + 外环;失败条目由 behavior 首次渲染自动展开
59
+ * .is-cancelled faint 点 + 标题删除线
60
+ *
61
+ * kind 修饰类 ai-tool--<kind> 只覆盖 --ai-item-tint(继承 = 变量级联,不改结构):
62
+ * read/search/grep/glob=info · edit/write=accent · rm=error · shell=muted · mcp/skill=success
63
+ * browser/fetch/todo/plan/subagent/note = 默认 accent(不写规则)
64
+ * 第三方 registerAiKind 的 tint 由 behavior 内联 --ai-item-tint 兜底。
65
+ */
66
+
67
+ /* ══════════════════════════════════════════════════════════════
68
+ 条目基元 .ai-item(行式条目"基类")
69
+ ══════════════════════════════════════════════════════════════ */
70
+
71
+ .ai-item {
72
+ /* 局部变量槽:kind/变体只覆盖这些变量(--btn-* 同款继承模式) */
73
+ --ai-item-tint: var(--token-accent);
74
+ --ai-item-pulse-duration: 1.5s; /* running 脉冲(pill --pill-pulse-duration 同款变量化) */
75
+ --ai-item-blink-duration: 1s; /* streaming 光标闪烁 */
76
+
77
+ display: flex;
78
+ flex-wrap: wrap;
79
+ align-items: center;
80
+ gap: var(--density-space-sm);
81
+ min-width: 0;
82
+ align-self: stretch; /* 宽度自稳定:宿主 flex/grid 居中时不 shrink-wrap(width:100% 会塌成 min-content,禁用) */
83
+ }
84
+
85
+ .ai-item-icon {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ flex-shrink: 0;
90
+ width: 20px;
91
+ height: 20px;
92
+ color: var(--ai-item-tint);
93
+ transition: color var(--icen-tx-fast);
94
+ }
95
+ .ai-item-icon > svg {
96
+ width: 16px;
97
+ height: 16px;
98
+ }
99
+
100
+ .ai-item-main {
101
+ flex: 1 1 auto;
102
+ min-width: 0;
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 1px;
106
+ }
107
+ .ai-item-title {
108
+ font-size: var(--density-font-size-md);
109
+ line-height: 1.4;
110
+ color: var(--token-text);
111
+ overflow: hidden;
112
+ text-overflow: ellipsis;
113
+ white-space: nowrap;
114
+ }
115
+ .ai-item-sub {
116
+ font-size: var(--density-font-size-xs);
117
+ line-height: 1.4;
118
+ color: var(--token-text-muted);
119
+ overflow: hidden;
120
+ text-overflow: ellipsis;
121
+ white-space: nowrap;
122
+ }
123
+ .ai-item-side {
124
+ display: inline-flex;
125
+ align-items: center;
126
+ gap: var(--density-space-xs);
127
+ margin-left: auto;
128
+ flex-shrink: 0;
129
+ }
130
+ /* head 直排结构(无 .ai-item-side 包裹)时,状态点顶到右侧 */
131
+ .ai-tool-head > .ai-item-status,
132
+ .ai-subagent-head > .ai-item-status {
133
+ margin-left: auto;
134
+ }
135
+
136
+ .ai-item-meta {
137
+ font-size: var(--density-font-size-xs);
138
+ color: var(--token-text-faint);
139
+ font-variant-numeric: tabular-nums;
140
+ flex-shrink: 0;
141
+ }
142
+
143
+ .ai-item-detail {
144
+ flex-basis: 100%;
145
+ min-width: 100%;
146
+ }
147
+
148
+ /* ── 状态点 .ai-item-status(纯 CSS 圆点,由 .is-* 决定颜色与动效) ── */
149
+ .ai-item-status {
150
+ position: relative;
151
+ flex-shrink: 0;
152
+ width: 8px;
153
+ height: 8px;
154
+ border-radius: 50%;
155
+ }
156
+
157
+ /* 等待:faint 空心点(.ai-subagent 与 .ai-item 共享同一状态语言) */
158
+ :is(.ai-item, .ai-tool, .ai-subagent).is-pending .ai-item-status {
159
+ border: 1.5px solid var(--token-text-faint);
160
+ }
161
+
162
+ /* 执行中:tint 脉冲点 */
163
+ :is(.ai-item, .ai-tool, .ai-subagent).is-running .ai-item-status {
164
+ background: var(--ai-item-tint);
165
+ animation: ai-item-pulse var(--ai-item-pulse-duration) ease-in-out infinite;
166
+ }
167
+ @keyframes ai-item-pulse {
168
+ 0%, 100% { opacity: 1; transform: scale(1); }
169
+ 50% { opacity: 0.4; transform: scale(0.7); }
170
+ }
171
+
172
+ /* 流式中:▍光标闪烁(复用 colors.css 的 blink keyframes,animate-blink 同款) */
173
+ :is(.ai-item, .ai-tool, .ai-subagent).is-streaming .ai-item-status {
174
+ width: 3px;
175
+ height: 12px;
176
+ border-radius: 1px;
177
+ background: var(--ai-item-tint);
178
+ animation: blink var(--ai-item-blink-duration) step-end infinite;
179
+ }
180
+
181
+ /* 待人确认:warning 点 + 外环 */
182
+ :is(.ai-item, .ai-tool, .ai-subagent).is-approval .ai-item-status {
183
+ background: var(--token-warning);
184
+ box-shadow: 0 0 0 3px var(--token-warning-muted);
185
+ }
186
+
187
+ /* 完成:success 对勾(纯 CSS,无 SVG) */
188
+ :is(.ai-item, .ai-tool, .ai-subagent).is-done .ai-item-status::after {
189
+ content: "";
190
+ position: absolute;
191
+ left: 1px;
192
+ top: -1px;
193
+ width: 5px;
194
+ height: 9px;
195
+ border-right: 1.5px solid var(--token-success);
196
+ border-bottom: 1.5px solid var(--token-success);
197
+ transform: rotate(45deg);
198
+ }
199
+
200
+ /* 失败:error 点 + 外环 */
201
+ :is(.ai-item, .ai-tool, .ai-subagent).is-error .ai-item-status {
202
+ background: var(--token-error);
203
+ box-shadow: 0 0 0 3px var(--token-error-muted);
204
+ }
205
+
206
+ /* 已取消:faint 点 + 标题删除线 */
207
+ :is(.ai-item, .ai-tool, .ai-subagent).is-cancelled .ai-item-status {
208
+ background: var(--token-text-faint);
209
+ opacity: 0.6;
210
+ }
211
+ :is(.ai-item, .ai-tool, .ai-subagent).is-cancelled .ai-item-title {
212
+ color: var(--token-text-faint);
213
+ text-decoration: line-through;
214
+ }
215
+
216
+ /* ══════════════════════════════════════════════════════════════
217
+ 工具调用卡 .ai-tool
218
+ ══════════════════════════════════════════════════════════════ */
219
+
220
+ .ai-tool {
221
+ --ai-item-tint: var(--token-accent);
222
+ align-self: stretch; /* 宽度自稳定:宿主 flex/grid 居中时不 shrink-wrap */
223
+ border: 1px solid var(--token-line-soft);
224
+ border-radius: var(--radius-md);
225
+ background: var(--token-surface);
226
+ }
227
+
228
+ /* ── kind 修饰类:只覆盖 --ai-item-tint ──
229
+ browser/fetch/todo/plan/subagent/note 用默认 accent,不写规则 */
230
+ .ai-tool--read,
231
+ .ai-tool--search,
232
+ .ai-tool--grep,
233
+ .ai-tool--glob {
234
+ --ai-item-tint: var(--token-info);
235
+ }
236
+ .ai-tool--edit,
237
+ .ai-tool--write {
238
+ --ai-item-tint: var(--token-accent);
239
+ }
240
+ .ai-tool--rm {
241
+ --ai-item-tint: var(--token-error);
242
+ }
243
+ .ai-tool--shell {
244
+ --ai-item-tint: var(--token-text-muted);
245
+ }
246
+ .ai-tool--mcp,
247
+ .ai-tool--skill {
248
+ --ai-item-tint: var(--token-success);
249
+ }
250
+
251
+ /* ── head ── */
252
+ .ai-tool-head,
253
+ .ai-subagent-head {
254
+ display: flex;
255
+ align-items: center;
256
+ gap: var(--density-space-sm);
257
+ width: 100%;
258
+ padding: var(--density-space-xs) var(--density-space-sm);
259
+ border: none;
260
+ border-radius: inherit; /* hover 底色不戳破卡片圆角 */
261
+ background: transparent;
262
+ color: inherit;
263
+ font: inherit;
264
+ text-align: left;
265
+ cursor: pointer;
266
+ -webkit-tap-highlight-color: transparent;
267
+ transition: background-color var(--icen-tx-fast);
268
+ }
269
+ .ai-tool-head:hover,
270
+ .ai-subagent-head:hover {
271
+ background: var(--token-fill-1);
272
+ }
273
+ .ai-tool-head:focus-visible,
274
+ .ai-subagent-head:focus-visible {
275
+ outline: none;
276
+ box-shadow: var(--icen-ring);
277
+ }
278
+
279
+ /* ── body ── */
280
+ .ai-tool-body {
281
+ display: flex;
282
+ flex-direction: column;
283
+ gap: var(--density-space-sm);
284
+ padding: var(--density-space-sm);
285
+ border-top: 1px solid var(--token-line-soft);
286
+ animation: icen-pop-in var(--icen-tx-fast);
287
+ }
288
+ .ai-tool-body[hidden],
289
+ .ai-subagent-body[hidden],
290
+ .ai-tool-io[hidden],
291
+ .ai-subagent-result[hidden] {
292
+ display: none;
293
+ }
294
+
295
+ /* ── 输入/输出区块(pre 等宽、可滚、max-height 收敛) ── */
296
+ .ai-tool-io {
297
+ display: flex;
298
+ flex-direction: column;
299
+ gap: 4px;
300
+ min-width: 0;
301
+ }
302
+ .ai-tool-io-label {
303
+ font-size: var(--density-font-size-2xs);
304
+ font-weight: 600;
305
+ letter-spacing: 0.08em;
306
+ text-transform: uppercase;
307
+ color: var(--token-text-faint);
308
+ }
309
+ .ai-tool-io-content {
310
+ --ai-tool-io-max: 12rem; /* 收敛上限(组件局部变量) */
311
+ margin: 0;
312
+ padding: var(--density-space-xs) var(--density-space-sm);
313
+ max-height: var(--ai-tool-io-max);
314
+ overflow: auto;
315
+ background: var(--token-bg-soft);
316
+ border: 1px solid var(--token-line-soft);
317
+ border-radius: var(--radius-sm);
318
+ font-family: var(--font-mono);
319
+ font-size: var(--density-font-size-sm);
320
+ line-height: 1.5;
321
+ color: var(--token-text);
322
+ white-space: pre-wrap;
323
+ word-break: break-word;
324
+ }
325
+
326
+ /* 多模态回执(MCP content 数组 → 媒体/链接,spec §10.3):
327
+ 容器纵向排布;媒体本体复用 ai-chat.css 的 .ai-msg-media 全局样式 */
328
+ .ai-tool-io-media {
329
+ display: flex;
330
+ flex-direction: column;
331
+ gap: var(--density-space-xs);
332
+ min-width: 0;
333
+ }
334
+
335
+ /* ── 审批区(仅 .is-approval 显示,纯 CSS 驱动) ── */
336
+ .ai-tool-approval {
337
+ display: none;
338
+ align-items: center;
339
+ gap: var(--density-space-sm);
340
+ padding-top: var(--density-space-xs);
341
+ border-top: 1px dashed var(--token-line-soft);
342
+ }
343
+ .ai-tool.is-approval .ai-tool-approval {
344
+ display: flex;
345
+ }
346
+ .ai-tool-approval-reason {
347
+ flex: 1 1 auto;
348
+ min-width: 0;
349
+ font-size: var(--density-font-size-xs);
350
+ line-height: 1.5;
351
+ color: var(--token-text-muted);
352
+ }
353
+ .ai-tool.is-approval {
354
+ border-color: color-mix(in srgb, var(--token-warning) 40%, transparent);
355
+ }
356
+ .ai-tool.is-error {
357
+ border-color: color-mix(in srgb, var(--token-error) 40%, transparent);
358
+ }
359
+
360
+ /* ══════════════════════════════════════════════════════════════
361
+ 子智能体卡 .ai-subagent(嵌套活动流 = 缩进 + 左侧引导线,可递归)
362
+ ══════════════════════════════════════════════════════════════ */
363
+
364
+ .ai-subagent {
365
+ --ai-item-tint: var(--token-accent);
366
+ align-self: stretch; /* 宽度自稳定:宿主 flex/grid 居中时不 shrink-wrap */
367
+ border: 1px solid var(--token-line-soft);
368
+ border-left: 3px solid var(--ai-item-tint); /* 代理卡身份:tint 左边条 */
369
+ border-radius: var(--radius-md);
370
+ background: var(--token-surface);
371
+ }
372
+ .ai-subagent.is-error {
373
+ border-left-color: var(--token-error);
374
+ }
375
+ .ai-subagent.is-done {
376
+ border-left-color: var(--token-success);
377
+ }
378
+
379
+ .ai-subagent-body {
380
+ display: flex;
381
+ flex-direction: column;
382
+ gap: var(--density-space-sm);
383
+ padding: var(--density-space-sm);
384
+ border-top: 1px solid var(--token-line-soft);
385
+ }
386
+
387
+ /* 嵌套流:缩进 + 引导线;行间渐入 stagger 由 --ai-activity-index(render 写入)驱动 */
388
+ .ai-subagent-stream {
389
+ --ai-stagger-step: 40ms; /* 活动项渐入步长(组件局部变量) */
390
+ position: relative;
391
+ display: flex;
392
+ flex-direction: column;
393
+ gap: var(--density-space-xs);
394
+ padding-left: var(--density-space-md);
395
+ }
396
+ .ai-subagent-stream::before {
397
+ content: "";
398
+ position: absolute;
399
+ left: 5px;
400
+ top: var(--density-space-xs);
401
+ bottom: var(--density-space-xs);
402
+ width: 1px;
403
+ background: var(--token-line-soft);
404
+ }
405
+ /* 展开(body 从 hidden 解除)时,活动项逐条 icen-pop-in 渐入 */
406
+ .ai-subagent-stream > * {
407
+ animation: icen-pop-in var(--icen-tx-fast) backwards;
408
+ animation-delay: calc(var(--ai-activity-index, 0) * var(--ai-stagger-step));
409
+ }
410
+
411
+ /* 完成回执 */
412
+ .ai-subagent-result {
413
+ padding: var(--density-space-xs) var(--density-space-sm);
414
+ background: var(--token-bg-soft);
415
+ border: 1px solid var(--token-line-soft);
416
+ border-radius: var(--radius-sm);
417
+ font-size: var(--density-font-size-sm);
418
+ line-height: 1.5;
419
+ color: var(--token-text-muted);
420
+ }
421
+ .ai-subagent.is-done .ai-subagent-result {
422
+ color: var(--token-text);
423
+ border-color: color-mix(in srgb, var(--token-success) 30%, transparent);
424
+ }
425
+
426
+ /* ══════════════════════════════════════════════════════════════
427
+ 动效守卫
428
+ ══════════════════════════════════════════════════════════════ */
429
+ @media (prefers-reduced-motion: reduce) {
430
+ :is(.ai-item, .ai-tool, .ai-subagent).is-running .ai-item-status,
431
+ :is(.ai-item, .ai-tool, .ai-subagent).is-streaming .ai-item-status {
432
+ animation: none;
433
+ }
434
+ .ai-tool-body,
435
+ .ai-subagent-stream > * {
436
+ animation: none;
437
+ }
438
+ .ai-tool-head,
439
+ .ai-subagent-head {
440
+ transition: none;
441
+ }
442
+ }
443
+
444
+ /* ═══ 工具卡内嵌图表(回执 = ChartSpec 时 setIo 走 renderChart,§13)═══ */
445
+ .ai-tool-io-chart {
446
+ width: 100%;
447
+ min-width: 0;
448
+ }
449
+
450
+ /* ═══ AI 工具挂载区(ai-tools.ts 的 createAiToolArea,§13)═══
451
+ * .ai-tools-mount > .ai-tools-item > head(名/时间/×)+ body(工具自渲染) */
452
+ .ai-tools-mount {
453
+ display: grid;
454
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
455
+ gap: var(--density-space-md);
456
+ align-items: start;
457
+ }
458
+ .ai-tools-item {
459
+ display: flex;
460
+ flex-direction: column;
461
+ min-width: 0;
462
+ border: 1px solid var(--token-line-soft);
463
+ border-radius: var(--radius-md);
464
+ background: var(--token-surface);
465
+ animation: icen-pop-in var(--duration-normal) var(--ease-out);
466
+ }
467
+ .ai-tools-item-head {
468
+ display: flex;
469
+ align-items: center;
470
+ gap: var(--density-space-sm);
471
+ padding: var(--density-space-xs) var(--density-space-sm);
472
+ border-bottom: 1px solid var(--token-line-soft);
473
+ }
474
+ .ai-tools-item-name {
475
+ font-family: var(--font-mono);
476
+ font-size: var(--density-font-size-xs);
477
+ color: var(--token-text);
478
+ }
479
+ .ai-tools-item-meta {
480
+ flex: 1;
481
+ font-family: var(--font-mono);
482
+ font-size: var(--density-font-size-2xs);
483
+ color: var(--token-text-faint);
484
+ font-variant-numeric: tabular-nums;
485
+ }
486
+ .ai-tools-item-remove {
487
+ border: 0;
488
+ background: transparent;
489
+ color: var(--token-text-faint);
490
+ cursor: pointer;
491
+ border-radius: var(--radius-xs);
492
+ font-size: var(--density-font-size-sm);
493
+ line-height: 1;
494
+ padding: 2px 6px;
495
+ transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast);
496
+ }
497
+ .ai-tools-item-remove:hover { color: var(--token-error); background: var(--token-fill-1); }
498
+ .ai-tools-item-remove:focus-visible { outline: none; box-shadow: var(--icen-ring); }
499
+ .ai-tools-item-body {
500
+ padding: var(--density-space-sm);
501
+ min-width: 0;
502
+ }
503
+
504
+ @media (prefers-reduced-motion: reduce) {
505
+ .ai-tools-item { animation: none; }
506
+ }
507
+
508
+ /* 挂载项折叠态:head 为 button(chevron + 名/时间 + ×) */
509
+ .ai-tools-item-head {
510
+ cursor: pointer;
511
+ border: 0;
512
+ background: transparent;
513
+ text-align: left;
514
+ width: 100%;
515
+ font: inherit;
516
+ }
517
+ .ai-tools-item-chevron {
518
+ flex-shrink: 0;
519
+ color: var(--token-text-faint);
520
+ font-size: var(--density-font-size-xs);
521
+ transition: transform var(--icen-tx-fast);
522
+ }
523
+ .ai-tools-item-head[aria-expanded='false'] .ai-tools-item-chevron {
524
+ transform: rotate(-90deg);
525
+ }
526
+ .ai-tools-item.is-collapsed .ai-tools-item-body {
527
+ display: none;
528
+ }
529
+ .ai-tools-item-head:focus-visible {
530
+ outline: none;
531
+ box-shadow: var(--icen-ring);
532
+ }
@@ -0,0 +1,3 @@
1
+ // @icen.ai/ui — kit: ai-usage(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './ai-panel.css';
3
+ export { renderAiUsage, renderAiUsageRing, renderAiAudit } from '../behaviors/ai-panel.mjs';
@@ -22,7 +22,7 @@
22
22
  * </span>
23
23
  *
24
24
  * 变体:--dot 纯圆点 / --sm 小号 / --lg 大号 / --bottom 底部角
25
- * 语义色:--success(在线)/ --warning / --error / --accent
25
+ * 语义色:--success(在线)/ --warning / --error / --info / --accent
26
26
  */
27
27
 
28
28
  .badge-host {
@@ -45,11 +45,11 @@
45
45
  height: 16px;
46
46
  padding: 0 4px;
47
47
  font: inherit;
48
- font-size: 10px;
48
+ font-size: var(--density-font-size-2xs);
49
49
  font-weight: 600;
50
50
  line-height: 1;
51
51
  font-variant-numeric: tabular-nums;
52
- color: var(--token-on-accent, #fff);
52
+ color: var(--token-on-accent);
53
53
  background: var(--token-error);
54
54
  border: 2px solid var(--token-surface);
55
55
  border-radius: var(--radius-full);
@@ -72,7 +72,7 @@
72
72
  .badge--sm {
73
73
  min-width: 14px;
74
74
  height: 14px;
75
- font-size: 9px;
75
+ font-size: var(--density-font-size-2xs);
76
76
  padding: 0 3px;
77
77
  }
78
78
  .badge--sm.badge--dot {
@@ -117,7 +117,7 @@
117
117
  /* 挂在实底色按钮上时用更浅的边框 */
118
118
  .btn-primary .badge,
119
119
  .btn-danger .badge {
120
- border-color: var(--token-on-accent, #fff);
120
+ border-color: var(--token-on-accent);
121
121
  }
122
122
 
123
123
  /* 数字超过 99 显示 99+(消费方决定是否使用,这里只保证宽度容纳) */
@@ -125,7 +125,3 @@
125
125
  min-width: 20px;
126
126
  padding: 0 5px;
127
127
  }
128
-
129
- @media (prefers-reduced-motion: reduce) {
130
- .badge { transition: none; }
131
- }
@@ -105,42 +105,6 @@
105
105
  background: var(--token-fill-1);
106
106
  }
107
107
 
108
- /* ── 溢出下拉(behavior 可选:点击 … 展开被折叠的中间路径) ── */
109
- .breadcrumb-dropdown {
110
- position: relative;
111
- }
112
- .breadcrumb-dropdown-menu {
113
- position: absolute;
114
- top: calc(100% + 4px);
115
- left: 0;
116
- min-width: 160px;
117
- padding: 4px;
118
- background: var(--token-card-strong);
119
- border: 1px solid var(--token-outline);
120
- border-radius: var(--radius-md);
121
- box-shadow: var(--token-shadow-overlay);
122
- z-index: var(--z-popover);
123
- animation: breadcrumb-drop-in var(--icen-tx-fast);
124
- }
125
- .breadcrumb-dropdown-menu[hidden] { display: none; }
126
- .breadcrumb-dropdown-menu a {
127
- display: block;
128
- padding: 4px var(--density-space-sm);
129
- font-size: var(--density-font-size-sm);
130
- color: var(--token-text-muted);
131
- text-decoration: none;
132
- border-radius: var(--radius-sm);
133
- transition: background-color var(--icen-tx-fast), color var(--icen-tx-fast);
134
- }
135
- .breadcrumb-dropdown-menu a:hover {
136
- background: var(--token-fill-1);
137
- color: var(--token-text);
138
- }
139
- @keyframes breadcrumb-drop-in {
140
- from { opacity: 0; transform: scale(0.96) translateY(-4px); }
141
- to { opacity: 1; transform: scale(1) translateY(0); }
142
- }
143
-
144
108
  /* ── 面包屑分隔符变体 ── */
145
109
  .breadcrumb--slash .breadcrumb-sep::after { content: '/'; }
146
110
  .breadcrumb--arrow .breadcrumb-sep::after { content: '→'; }
@@ -75,7 +75,7 @@
75
75
  /* ── 变体 ── */
76
76
  .btn-primary {
77
77
  --btn-bg: var(--token-accent);
78
- --btn-fg: var(--token-on-accent, #fff);
78
+ --btn-fg: var(--token-on-accent);
79
79
  --btn-border: var(--token-accent);
80
80
  --btn-bg-hover: var(--token-accent-deep, color-mix(in srgb, var(--token-accent) 85%, black));
81
81
  --btn-border-hover: var(--token-accent-deep, var(--token-accent));
@@ -91,7 +91,7 @@
91
91
  --btn-bg-hover: var(--token-error);
92
92
  --btn-border-hover: var(--token-error);
93
93
  }
94
- .btn-danger:hover { color: var(--token-on-accent, #fff); }
94
+ .btn-danger:hover { color: var(--token-on-accent); }
95
95
 
96
96
  .btn-ghost {
97
97
  --btn-bg: transparent;
@@ -162,14 +162,11 @@
162
162
  border: 2px solid color-mix(in srgb, currentColor 35%, transparent);
163
163
  border-top-color: currentColor;
164
164
  border-radius: 50%;
165
- animation: btn-spin var(--duration-slow) linear infinite;
165
+ animation: icen-spin var(--btn-spin-duration, var(--duration-slow)) linear infinite;
166
166
  opacity: 1; /* 覆盖 .pressable::after 渐变(若与 .pressable 同用) */
167
167
  background: none;
168
168
  pointer-events: none;
169
169
  }
170
- @keyframes btn-spin {
171
- to { transform: rotate(360deg); }
172
- }
173
170
 
174
171
  /* 图标按钮内部 svg 默认尺寸对齐字号 */
175
172
  .btn-icon-start, .btn-icon-end {
@@ -179,5 +176,5 @@
179
176
  }
180
177
 
181
178
  @media (prefers-reduced-motion: reduce) {
182
- .btn.is-loading::after { animation-duration: 1.2s; }
179
+ .btn.is-loading::after { --btn-spin-duration: 1.2s; }
183
180
  }
@@ -25,6 +25,7 @@
25
25
  */
26
26
 
27
27
  .card {
28
+ position: relative;
28
29
  background: var(--token-card);
29
30
  border: 1px solid var(--token-outline-soft);
30
31
  box-shadow: var(--token-shadow-inset);
@@ -91,14 +92,11 @@
91
92
  transform: scale(1.04);
92
93
  }
93
94
  .card-media > img,
94
- .card-media > video {
95
- transition: transform var(--icen-tx-slow) var(--ease-out);
96
- }
97
- .card-media > img,
98
95
  .card-media > video {
99
96
  width: 100%;
100
97
  height: 100%;
101
98
  object-fit: cover;
99
+ transition: transform var(--icen-tx-slow) var(--ease-out);
102
100
  }
103
101
  .card-tag {
104
102
  position: absolute;
@@ -107,7 +105,7 @@
107
105
  padding: 2px var(--density-space-xs);
108
106
  font-size: var(--density-font-size-xs);
109
107
  font-weight: 600;
110
- color: var(--token-on-accent, #fff);
108
+ color: var(--token-on-accent);
111
109
  background: color-mix(in srgb, var(--token-text) 70%, transparent);
112
110
  border-radius: var(--radius-xs);
113
111
  backdrop-filter: blur(8px);
@@ -221,4 +219,3 @@
221
219
  right: var(--density-space-sm);
222
220
  z-index: 1;
223
221
  }
224
- .card { position: relative; }