@icen.ai/ui 0.5.0 → 0.8.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 (138) hide show
  1. package/AGENTS.md +256 -0
  2. package/README.md +47 -13
  3. package/dist/base.css +31 -4
  4. package/dist/behaviors/accordion.d.mts +4 -0
  5. package/dist/behaviors/accordion.mjs +4 -3
  6. package/dist/behaviors/ai-chat.d.mts +57 -0
  7. package/dist/behaviors/ai-chat.mjs +557 -0
  8. package/dist/behaviors/ai-composer.d.mts +112 -0
  9. package/dist/behaviors/ai-composer.mjs +2032 -0
  10. package/dist/behaviors/ai-core.d.mts +151 -0
  11. package/dist/behaviors/ai-core.mjs +491 -0
  12. package/dist/behaviors/ai-diff.d.mts +53 -0
  13. package/dist/behaviors/ai-diff.mjs +282 -0
  14. package/dist/behaviors/ai-panel.d.mts +98 -0
  15. package/dist/behaviors/ai-panel.mjs +1012 -0
  16. package/dist/behaviors/ai-provider.d.mts +198 -0
  17. package/dist/behaviors/ai-provider.mjs +1055 -0
  18. package/dist/behaviors/ai-tool.d.mts +18 -0
  19. package/dist/behaviors/ai-tool.mjs +2125 -0
  20. package/dist/behaviors/ai-tools.d.mts +81 -0
  21. package/dist/behaviors/ai-tools.mjs +1658 -0
  22. package/dist/behaviors/back-top.d.mts +20 -0
  23. package/dist/behaviors/back-top.mjs +49 -32
  24. package/dist/behaviors/carousel.d.mts +4 -0
  25. package/dist/behaviors/carousel.mjs +34 -16
  26. package/dist/behaviors/charts.d.mts +250 -0
  27. package/dist/behaviors/charts.mjs +1301 -448
  28. package/dist/behaviors/command-palette.d.mts +8 -0
  29. package/dist/behaviors/command-palette.mjs +24 -12
  30. package/dist/behaviors/context-menu.d.mts +36 -0
  31. package/dist/behaviors/context-menu.mjs +6 -2
  32. package/dist/behaviors/copy.d.mts +4 -0
  33. package/dist/behaviors/copy.mjs +7 -6
  34. package/dist/behaviors/datatable.d.mts +78 -0
  35. package/dist/behaviors/datatable.mjs +54 -11
  36. package/dist/behaviors/date-picker.d.mts +4 -0
  37. package/dist/behaviors/date-picker.mjs +104 -36
  38. package/dist/behaviors/dropdown.d.mts +4 -0
  39. package/dist/behaviors/dropdown.mjs +7 -3
  40. package/dist/behaviors/input.d.mts +4 -0
  41. package/dist/behaviors/input.mjs +29 -22
  42. package/dist/behaviors/modal.d.mts +11 -0
  43. package/dist/behaviors/modal.mjs +11 -6
  44. package/dist/behaviors/nav.d.mts +7 -0
  45. package/dist/behaviors/nav.mjs +25 -9
  46. package/dist/behaviors/notification.d.mts +172 -0
  47. package/dist/behaviors/notification.mjs +243 -89
  48. package/dist/behaviors/popover.d.mts +46 -0
  49. package/dist/behaviors/popover.mjs +2 -1
  50. package/dist/behaviors/select.d.mts +4 -0
  51. package/dist/behaviors/select.mjs +131 -26
  52. package/dist/behaviors/sidebar.d.mts +4 -0
  53. package/dist/behaviors/sidebar.mjs +4 -3
  54. package/dist/behaviors/slider.d.mts +4 -0
  55. package/dist/behaviors/slider.mjs +4 -3
  56. package/dist/behaviors/split-pane.d.mts +4 -0
  57. package/dist/behaviors/split-pane.mjs +13 -13
  58. package/dist/behaviors/tabs.d.mts +8 -0
  59. package/dist/behaviors/tabs.mjs +44 -19
  60. package/dist/behaviors/tag-input.d.mts +4 -0
  61. package/dist/behaviors/tag-input.mjs +12 -3
  62. package/dist/behaviors/theme.d.mts +25 -0
  63. package/dist/behaviors/theme.mjs +3 -1
  64. package/dist/behaviors/toast.d.mts +26 -0
  65. package/dist/behaviors/toast.mjs +24 -18
  66. package/dist/behaviors/tree.d.mts +4 -0
  67. package/dist/behaviors/tree.mjs +4 -3
  68. package/dist/behaviors/upload.d.mts +4 -0
  69. package/dist/behaviors/upload.mjs +63 -26
  70. package/dist/components/ai-chat.css +1037 -0
  71. package/dist/components/ai-chat.mjs +3 -0
  72. package/dist/components/ai-composer.mjs +3 -0
  73. package/dist/components/ai-context.mjs +2 -0
  74. package/dist/components/ai-diff.css +311 -0
  75. package/dist/components/ai-diff.mjs +3 -0
  76. package/dist/components/ai-files.mjs +3 -0
  77. package/dist/components/ai-message.mjs +3 -0
  78. package/dist/components/ai-panel.css +682 -0
  79. package/dist/components/ai-reasoning.mjs +3 -0
  80. package/dist/components/ai-subagent.mjs +2 -0
  81. package/dist/components/ai-todo.mjs +2 -0
  82. package/dist/components/ai-tool-call.mjs +2 -0
  83. package/dist/components/ai-tool.css +532 -0
  84. package/dist/components/ai-usage.mjs +3 -0
  85. package/dist/components/badge.css +4 -8
  86. package/dist/components/breadcrumb.css +1 -5
  87. package/dist/components/btn.css +4 -7
  88. package/dist/components/card.css +3 -6
  89. package/dist/components/chart-bar.css +10 -0
  90. package/dist/components/chart-calendar.mjs +5 -0
  91. package/dist/components/chart-gauge.css +1 -1
  92. package/dist/components/chart-heatmap.css +40 -0
  93. package/dist/components/chart-scatter.css +24 -0
  94. package/dist/components/chart-scatter.mjs +4 -0
  95. package/dist/components/charts.css +86 -1
  96. package/dist/components/charts.mjs +1 -0
  97. package/dist/components/command-palette.css +2 -2
  98. package/dist/components/content.css +8 -9
  99. package/dist/components/copy.css +8 -8
  100. package/dist/components/datatable.css +4 -8
  101. package/dist/components/date-picker.css +3 -7
  102. package/dist/components/empty.css +0 -4
  103. package/dist/components/feedback.css +10 -17
  104. package/dist/components/form.css +13 -14
  105. package/dist/components/input.css +2 -2
  106. package/dist/components/layout.css +36 -36
  107. package/dist/components/media.css +12 -8
  108. package/dist/components/menu.css +2 -2
  109. package/dist/components/modal.css +1 -1
  110. package/dist/components/nav.css +11 -6
  111. package/dist/components/notification.css +28 -28
  112. package/dist/components/pagination.css +1 -1
  113. package/dist/components/panel.css +16 -16
  114. package/dist/components/pill.css +15 -15
  115. package/dist/components/segmented.css +5 -5
  116. package/dist/components/segmented.mjs +1 -0
  117. package/dist/components/select.css +12 -20
  118. package/dist/components/sidebar.css +1 -1
  119. package/dist/components/split-pane.css +0 -1
  120. package/dist/components/stat.css +14 -18
  121. package/dist/components/steps.css +2 -2
  122. package/dist/components/switch.css +8 -12
  123. package/dist/components/table.css +46 -47
  124. package/dist/components/tabs.css +35 -46
  125. package/dist/components/tag-input.css +4 -4
  126. package/dist/components/toast.css +16 -13
  127. package/dist/components/tooltip.css +2 -2
  128. package/dist/index.d.mts +37 -0
  129. package/dist/index.mjs +7890 -1199
  130. package/dist/registry.json +113 -4
  131. package/dist/retro-effects.css +21 -17
  132. package/dist/tokens/colors.css +4 -1
  133. package/dist/tokens/retro-effects.css +21 -17
  134. package/dist/tokens/style-profiles.css +21 -0
  135. package/dist/tokens.css +25 -1
  136. package/dist/ui.css +3168 -433
  137. package/docs/spec/ai-native.md +659 -0
  138. 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';
@@ -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
- }
@@ -120,7 +120,7 @@
120
120
  border-radius: var(--radius-md);
121
121
  box-shadow: var(--token-shadow-overlay);
122
122
  z-index: var(--z-popover);
123
- animation: breadcrumb-drop-in var(--icen-tx-fast);
123
+ animation: icen-pop-in var(--icen-tx-fast);
124
124
  }
125
125
  .breadcrumb-dropdown-menu[hidden] { display: none; }
126
126
  .breadcrumb-dropdown-menu a {
@@ -136,10 +136,6 @@
136
136
  background: var(--token-fill-1);
137
137
  color: var(--token-text);
138
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
139
 
144
140
  /* ── 面包屑分隔符变体 ── */
145
141
  .breadcrumb--slash .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; }
@@ -77,3 +77,13 @@
77
77
  @media (prefers-reduced-motion: reduce) {
78
78
  .chart-vbar-bar, .chart-hbar-bar { transition: none; }
79
79
  }
80
+
81
+ /* ── 多系列:分组(簇内并排)与堆叠(列内向上叠)── */
82
+ .chart-vbar-track--multi { gap: 2px; }
83
+ .chart-vbar-track--multi > .chart-vbar-bar { flex: 1; min-width: 0; width: auto; }
84
+ .chart-vbar-track--multi.chart-vbar-track--stacked {
85
+ flex-direction: column;
86
+ justify-content: flex-end;
87
+ gap: 0;
88
+ }
89
+ .chart-vbar-track--multi.chart-vbar-track--stacked > .chart-vbar-bar { flex: none; width: 100%; }
@@ -0,0 +1,5 @@
1
+ // @icen.ai/ui — kit: chart-calendar(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './chart-calendar.css';
3
+ import './charts.css';
4
+ import './chart-heatmap.css';
5
+ export { renderCalendar } from '../behaviors/charts.mjs';