@cianfrani/ai-ui 0.1.0-alpha.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.
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/dist/ai-ui.js +3218 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/lib/has-slot-controller.d.ts +21 -0
- package/dist/types/lib/tool-tone.d.ts +2 -0
- package/dist/types/native-styles.d.ts +5 -0
- package/dist/types/semantic/ai-conversation.d.ts +28 -0
- package/dist/types/semantic/ai-event.d.ts +91 -0
- package/dist/types/semantic/ai-message.d.ts +45 -0
- package/dist/types/semantic/ai-thinking.d.ts +41 -0
- package/dist/types/semantic/ai-tool-call.d.ts +59 -0
- package/dist/types/semantic/ai-tool-result.d.ts +44 -0
- package/dist/types/semantic/index.d.ts +6 -0
- package/dist/types/visual/avatar.d.ts +34 -0
- package/dist/types/visual/badge.d.ts +32 -0
- package/dist/types/visual/divider.d.ts +26 -0
- package/dist/types/visual/icon.d.ts +24 -0
- package/dist/types/visual/index.d.ts +9 -0
- package/dist/types/visual/markdown.d.ts +52 -0
- package/dist/types/visual/stack.d.ts +32 -0
- package/dist/types/visual/status.d.ts +33 -0
- package/dist/types/visual/surface.d.ts +34 -0
- package/dist/types/visual/text.d.ts +37 -0
- package/package.json +67 -0
- package/src/custom-elements.json +3741 -0
- package/src/index.ts +8 -0
- package/src/lib/has-slot-controller.ts +61 -0
- package/src/lib/tool-tone.ts +18 -0
- package/src/native-styles.ts +29 -0
- package/src/semantic/ai-conversation.ts +84 -0
- package/src/semantic/ai-event.ts +452 -0
- package/src/semantic/ai-message.ts +235 -0
- package/src/semantic/ai-thinking.ts +190 -0
- package/src/semantic/ai-tool-call.ts +513 -0
- package/src/semantic/ai-tool-result.ts +239 -0
- package/src/semantic/index.ts +6 -0
- package/src/visual/avatar.ts +163 -0
- package/src/visual/badge.ts +141 -0
- package/src/visual/divider.ts +97 -0
- package/src/visual/icon.ts +97 -0
- package/src/visual/index.ts +9 -0
- package/src/visual/markdown.ts +888 -0
- package/src/visual/stack.ts +115 -0
- package/src/visual/status.ts +170 -0
- package/src/visual/surface.ts +150 -0
- package/src/visual/text.ts +141 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
import { LitElement, css, html, nothing, svg } from "lit";
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
|
+
import { getToolTone } from "../lib/tool-tone";
|
|
4
|
+
import { HasSlotController } from "../lib/has-slot-controller";
|
|
5
|
+
import type { AiShowHideDetail } from "./ai-event";
|
|
6
|
+
|
|
7
|
+
export type ToolCallKind =
|
|
8
|
+
| "tool"
|
|
9
|
+
| "shell"
|
|
10
|
+
| "file"
|
|
11
|
+
| "search"
|
|
12
|
+
| "delegate"
|
|
13
|
+
| "network"
|
|
14
|
+
| "custom"
|
|
15
|
+
| "unknown";
|
|
16
|
+
|
|
17
|
+
export type ToolCallEffect = "read" | "write" | "mixed" | "unknown";
|
|
18
|
+
|
|
19
|
+
export type ToolCallStatus = "pending" | "running" | "success" | "error" | "cancelled" | "unknown";
|
|
20
|
+
|
|
21
|
+
function renderGlyph(tone: ReturnType<typeof getToolTone>) {
|
|
22
|
+
switch (tone) {
|
|
23
|
+
case "read":
|
|
24
|
+
return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 1 2-2h12"></path><path d="M14 3v6h6"></path><path d="M8 13h8"></path><path d="M8 17h5"></path><path d="M14 3l6 6v10a2 2 0 0 1-2 2H6"></path></svg>`;
|
|
25
|
+
case "write":
|
|
26
|
+
return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20h9"></path><path d="M16.5 3.5a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4Z"></path></svg>`;
|
|
27
|
+
case "edit":
|
|
28
|
+
return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20h9"></path><path d="M4 13.5V20h6.5L19 11.5 12.5 5 4 13.5Z"></path></svg>`;
|
|
29
|
+
case "bash":
|
|
30
|
+
return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m4 17 6-5-6-5"></path><path d="M12 19h8"></path></svg>`;
|
|
31
|
+
default:
|
|
32
|
+
return nothing;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Specialized assistant content block for a tool call.
|
|
38
|
+
*
|
|
39
|
+
* @slot summary - Custom summary row/header
|
|
40
|
+
* @slot input - Tool input/arguments; native <pre><code> is recommended.
|
|
41
|
+
* @slot - Result/details content, commonly nested ai-tool-result.
|
|
42
|
+
*
|
|
43
|
+
* @fires ai-show - Emitted when disclosure opens. Bubbles, composed.
|
|
44
|
+
* @fires ai-hide - Emitted when disclosure closes. Bubbles, composed.
|
|
45
|
+
*
|
|
46
|
+
* @cssprop --ai-tool-call-background - Tool call background.
|
|
47
|
+
* @cssprop --ai-tool-call-color - Tool call text color.
|
|
48
|
+
* @cssprop --ai-tool-call-border-color - Tool call border color.
|
|
49
|
+
* @cssprop --ai-tool-call-summary-background - Summary row background.
|
|
50
|
+
* @cssprop --ai-tool-call-input-background - Input slot background.
|
|
51
|
+
* @cssprop --ai-tool-call-status-color - Generic status color.
|
|
52
|
+
* @cssprop --ai-tool-call-success-color - Success status color.
|
|
53
|
+
* @cssprop --ai-tool-call-error-color - Error status color.
|
|
54
|
+
* @cssprop --ai-tool-call-running-color - Running status color.
|
|
55
|
+
*/
|
|
56
|
+
@customElement("ai-tool-call")
|
|
57
|
+
export class AiToolCall extends LitElement {
|
|
58
|
+
static override styles = css`
|
|
59
|
+
*,
|
|
60
|
+
*::before,
|
|
61
|
+
*::after {
|
|
62
|
+
box-sizing: border-box;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:host {
|
|
66
|
+
display: block;
|
|
67
|
+
margin: 0;
|
|
68
|
+
padding: 0;
|
|
69
|
+
width: 100%;
|
|
70
|
+
max-width: 100%;
|
|
71
|
+
min-width: 0;
|
|
72
|
+
color: var(--ai-tool-call-color, var(--text, var(--ai-color-text, inherit)));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.row {
|
|
76
|
+
--accent: color-mix(
|
|
77
|
+
in oklch,
|
|
78
|
+
var(--ai-tool-call-status-color, var(--text-muted, var(--ai-color-text-muted, #888))) 82%,
|
|
79
|
+
var(--ai-tool-call-border-color, var(--border, var(--ai-color-border, #333)))
|
|
80
|
+
);
|
|
81
|
+
--surface-hover: color-mix(in oklch, var(--accent) 8%, transparent);
|
|
82
|
+
--surface-open: color-mix(in oklch, var(--accent) 5%, transparent);
|
|
83
|
+
display: block;
|
|
84
|
+
min-width: 0;
|
|
85
|
+
max-width: 100%;
|
|
86
|
+
background: var(--ai-tool-call-background, var(--background-color, transparent));
|
|
87
|
+
color: inherit;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.row[data-tone="read"] {
|
|
91
|
+
--accent: oklch(74% 0.12 190);
|
|
92
|
+
}
|
|
93
|
+
.row[data-tone="write"] {
|
|
94
|
+
--accent: oklch(78% 0.15 145);
|
|
95
|
+
}
|
|
96
|
+
.row[data-tone="edit"] {
|
|
97
|
+
--accent: oklch(76% 0.17 85);
|
|
98
|
+
}
|
|
99
|
+
.row[data-tone="bash"] {
|
|
100
|
+
--accent: oklch(68% 0.19 25);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.row[data-status="success"] {
|
|
104
|
+
--accent: var(
|
|
105
|
+
--ai-tool-call-success-color,
|
|
106
|
+
var(--success-color, var(--success, var(--ai-color-success, #16a34a)))
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.row[data-status="running"],
|
|
111
|
+
.row[data-status="pending"] {
|
|
112
|
+
--accent: var(
|
|
113
|
+
--ai-tool-call-running-color,
|
|
114
|
+
var(--running-color, var(--accent, var(--ai-color-accent, Highlight)))
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.row[data-status="error"] {
|
|
119
|
+
--accent: var(
|
|
120
|
+
--ai-tool-call-error-color,
|
|
121
|
+
var(--error-color, var(--error, var(--ai-color-error, #dc2626)))
|
|
122
|
+
);
|
|
123
|
+
--surface-hover: color-mix(in oklch, var(--accent) 10%, transparent);
|
|
124
|
+
--surface-open: color-mix(in oklch, var(--accent) 7%, transparent);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.row-header {
|
|
128
|
+
display: grid;
|
|
129
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
130
|
+
align-items: center;
|
|
131
|
+
gap: calc(var(--spacing-xs, 4px) + 2px);
|
|
132
|
+
padding: 2px 4px;
|
|
133
|
+
background: var(
|
|
134
|
+
--ai-tool-call-summary-background,
|
|
135
|
+
var(--summary-background-color, transparent)
|
|
136
|
+
);
|
|
137
|
+
list-style: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.row-header[interactive] {
|
|
141
|
+
cursor: pointer;
|
|
142
|
+
transition: background 0.16s ease;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.row-header[interactive]:hover {
|
|
146
|
+
background: var(--surface-hover);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.row-header[interactive]:focus-visible {
|
|
150
|
+
outline: 2px solid var(--focus, Highlight);
|
|
151
|
+
outline-offset: 2px;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
details[open] > .row-header {
|
|
155
|
+
background: var(--surface-open);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
summary.row-header::marker,
|
|
159
|
+
summary.row-header::-webkit-details-marker {
|
|
160
|
+
display: none;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.header-content {
|
|
164
|
+
display: flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 6px;
|
|
167
|
+
min-width: 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.icon-frame {
|
|
171
|
+
display: inline-flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: center;
|
|
174
|
+
width: 14px;
|
|
175
|
+
height: 14px;
|
|
176
|
+
flex-shrink: 0;
|
|
177
|
+
color: color-mix(in oklch, var(--accent) 62%, var(--text-muted, currentColor));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.icon-frame svg {
|
|
181
|
+
width: 12.5px;
|
|
182
|
+
height: 12.5px;
|
|
183
|
+
stroke: currentColor;
|
|
184
|
+
fill: none;
|
|
185
|
+
stroke-width: 1.8;
|
|
186
|
+
stroke-linecap: round;
|
|
187
|
+
stroke-linejoin: round;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.reasoning-dot {
|
|
191
|
+
width: 5px;
|
|
192
|
+
height: 5px;
|
|
193
|
+
border-radius: 999px;
|
|
194
|
+
background: currentColor;
|
|
195
|
+
opacity: 0.72;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.text-block {
|
|
199
|
+
display: grid;
|
|
200
|
+
gap: 1px;
|
|
201
|
+
min-width: 0;
|
|
202
|
+
padding-block: 1px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.headline {
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: baseline;
|
|
208
|
+
gap: 6px;
|
|
209
|
+
flex-wrap: wrap;
|
|
210
|
+
min-width: 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.badge {
|
|
214
|
+
flex-shrink: 0;
|
|
215
|
+
font-size: var(--font-size-caption, 0.75rem);
|
|
216
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
217
|
+
line-height: var(--line-height-tight, 1.1);
|
|
218
|
+
letter-spacing: var(--tracking-label, 0.04em);
|
|
219
|
+
color: color-mix(in oklch, var(--accent) 52%, var(--text-muted, currentColor));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.headline-text {
|
|
223
|
+
min-width: 0;
|
|
224
|
+
font-size: var(--font-size-meta, 0.8125rem);
|
|
225
|
+
line-height: var(--line-height-snug, 1.25);
|
|
226
|
+
color: color-mix(in oklch, var(--text, currentColor) 88%, var(--text-muted, currentColor));
|
|
227
|
+
overflow: hidden;
|
|
228
|
+
text-overflow: ellipsis;
|
|
229
|
+
white-space: normal;
|
|
230
|
+
display: -webkit-box;
|
|
231
|
+
-webkit-box-orient: vertical;
|
|
232
|
+
-webkit-line-clamp: 2;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.subline {
|
|
236
|
+
font-size: var(--font-size-caption, 0.75rem);
|
|
237
|
+
line-height: var(--line-height-snug, 1.25);
|
|
238
|
+
color: color-mix(in oklch, var(--text-muted, currentColor) 92%, transparent);
|
|
239
|
+
overflow: hidden;
|
|
240
|
+
text-overflow: ellipsis;
|
|
241
|
+
white-space: nowrap;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.row[data-tone="generic"] .badge {
|
|
245
|
+
color: color-mix(in oklch, var(--text-muted, currentColor) 92%, transparent);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.row[data-tone="generic"] .headline-text {
|
|
249
|
+
color: color-mix(in oklch, var(--text, currentColor) 78%, var(--text-muted, currentColor));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.row[data-tone="read"] .headline-text {
|
|
253
|
+
white-space: nowrap;
|
|
254
|
+
display: block;
|
|
255
|
+
-webkit-line-clamp: unset;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.chevron {
|
|
259
|
+
width: 8px;
|
|
260
|
+
height: 8px;
|
|
261
|
+
flex-shrink: 0;
|
|
262
|
+
color: color-mix(in oklch, var(--text-muted, currentColor) 88%, transparent);
|
|
263
|
+
transition: transform 0.16s ease;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
details[open] .chevron {
|
|
267
|
+
transform: rotate(90deg);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.body {
|
|
271
|
+
padding: 1px 4px calc(var(--spacing-xs, 4px) + 1px) 24px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.body::before {
|
|
275
|
+
content: "";
|
|
276
|
+
display: block;
|
|
277
|
+
height: 1px;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.body ::slotted(*) {
|
|
281
|
+
display: block;
|
|
282
|
+
min-width: 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.input-area {
|
|
286
|
+
padding: var(--ai-space-xs, 2px) 4px var(--ai-space-xs, 2px) 24px;
|
|
287
|
+
background: var(--ai-tool-call-input-background, var(--input-background-color, transparent));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.input-area ::slotted(*) {
|
|
291
|
+
display: block;
|
|
292
|
+
min-width: 0;
|
|
293
|
+
margin: 0;
|
|
294
|
+
max-width: 100%;
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
297
|
+
|
|
298
|
+
@property({ reflect: true })
|
|
299
|
+
override id = "";
|
|
300
|
+
|
|
301
|
+
@property({ reflect: true })
|
|
302
|
+
name = "";
|
|
303
|
+
|
|
304
|
+
@property({ reflect: true })
|
|
305
|
+
label = "";
|
|
306
|
+
|
|
307
|
+
@property({ reflect: true })
|
|
308
|
+
kind: "tool" | "shell" | "file" | "search" | "delegate" | "network" | "custom" | "unknown" =
|
|
309
|
+
"unknown";
|
|
310
|
+
|
|
311
|
+
@property({ reflect: true })
|
|
312
|
+
effect: "read" | "write" | "mixed" | "unknown" = "unknown";
|
|
313
|
+
|
|
314
|
+
@property({ reflect: true })
|
|
315
|
+
headline = "";
|
|
316
|
+
|
|
317
|
+
@property({ reflect: true })
|
|
318
|
+
subline = "";
|
|
319
|
+
|
|
320
|
+
@property({ reflect: true })
|
|
321
|
+
status: "pending" | "running" | "success" | "error" | "cancelled" | "unknown" = "unknown";
|
|
322
|
+
|
|
323
|
+
@property({ reflect: true, type: Boolean })
|
|
324
|
+
open = false;
|
|
325
|
+
|
|
326
|
+
private readonly hasSlot = new HasSlotController(this, "[default]", "input", "summary");
|
|
327
|
+
|
|
328
|
+
private get tone() {
|
|
329
|
+
return getToolTone(this.name);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
private get badgeText(): string {
|
|
333
|
+
return this.label || this.name;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private get headlineText(): string {
|
|
337
|
+
return this.headline || this.label || "";
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private get hasBodyContent(): boolean {
|
|
341
|
+
return this.hasSlot.test("[default]");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private get hasInputContent(): boolean {
|
|
345
|
+
return this.hasSlot.test("input");
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private get hasSummaryContent(): boolean {
|
|
349
|
+
return this.hasSlot.test("summary");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private get isExpandable(): boolean {
|
|
353
|
+
return this.hasBodyContent || this.hasInputContent;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private get hasVisibleHeaderContent(): boolean {
|
|
357
|
+
return Boolean(this.badgeText || this.headlineText || this.subline);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
show(): void {
|
|
361
|
+
this.open = true;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
hide(): void {
|
|
365
|
+
this.open = false;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
toggle(force?: boolean): void {
|
|
369
|
+
this.open = force ?? !this.open;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private emitToggle(isOpen: boolean) {
|
|
373
|
+
this.dispatchEvent(
|
|
374
|
+
new CustomEvent<AiShowHideDetail>(isOpen ? "ai-show" : "ai-hide", {
|
|
375
|
+
detail: { source: "tool-call", open: isOpen, id: this.id, name: this.name },
|
|
376
|
+
bubbles: true,
|
|
377
|
+
composed: true,
|
|
378
|
+
}),
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private handleToggle(e: Event) {
|
|
383
|
+
const details = e.currentTarget as HTMLDetailsElement;
|
|
384
|
+
const isOpen = details.open;
|
|
385
|
+
if (this.open !== isOpen) {
|
|
386
|
+
this.open = isOpen;
|
|
387
|
+
}
|
|
388
|
+
this.emitToggle(isOpen);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
protected override updated(changed: Map<string, unknown>) {
|
|
392
|
+
if (changed.has("open") && changed.get("open") !== undefined) {
|
|
393
|
+
const details = this.renderRoot.querySelector("details");
|
|
394
|
+
if (details && details.open !== this.open) {
|
|
395
|
+
details.open = this.open;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private renderIcon() {
|
|
401
|
+
const tone = this.tone;
|
|
402
|
+
if (tone === "generic") {
|
|
403
|
+
return html`
|
|
404
|
+
<span class="icon-frame" aria-hidden="true">
|
|
405
|
+
<span class="reasoning-dot"></span>
|
|
406
|
+
</span>
|
|
407
|
+
`;
|
|
408
|
+
}
|
|
409
|
+
return html`<span class="icon-frame" aria-hidden="true">${renderGlyph(tone)}</span>`;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private renderHeaderContent() {
|
|
413
|
+
return html`
|
|
414
|
+
<span class="header-content">
|
|
415
|
+
${this.renderIcon()}
|
|
416
|
+
<span class="text-block">
|
|
417
|
+
<span class="headline">
|
|
418
|
+
${this.badgeText ? html`<span class="badge">${this.badgeText}</span>` : nothing}
|
|
419
|
+
${
|
|
420
|
+
this.headlineText && this.headlineText !== this.badgeText
|
|
421
|
+
? html`<span class="headline-text">${this.headlineText}</span>`
|
|
422
|
+
: nothing
|
|
423
|
+
}
|
|
424
|
+
</span>
|
|
425
|
+
${this.subline ? html`<span class="subline">${this.subline}</span>` : nothing}
|
|
426
|
+
</span>
|
|
427
|
+
</span>
|
|
428
|
+
${
|
|
429
|
+
this.isExpandable
|
|
430
|
+
? html`
|
|
431
|
+
<svg class="chevron" viewBox="0 0 10 10" aria-hidden="true">
|
|
432
|
+
<path
|
|
433
|
+
d="M3 2.2 6.8 5 3 7.8"
|
|
434
|
+
fill="none"
|
|
435
|
+
stroke="currentColor"
|
|
436
|
+
stroke-width="1.4"
|
|
437
|
+
stroke-linecap="round"
|
|
438
|
+
stroke-linejoin="round"
|
|
439
|
+
></path>
|
|
440
|
+
</svg>
|
|
441
|
+
`
|
|
442
|
+
: nothing
|
|
443
|
+
}
|
|
444
|
+
`;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
override render() {
|
|
448
|
+
const tone = this.tone;
|
|
449
|
+
const status = this.status;
|
|
450
|
+
|
|
451
|
+
if (this.hasSummaryContent) {
|
|
452
|
+
return html`
|
|
453
|
+
<div class="row" data-tone=${tone} data-status=${status}>
|
|
454
|
+
<slot name="summary"></slot>
|
|
455
|
+
${
|
|
456
|
+
this.isExpandable
|
|
457
|
+
? html`
|
|
458
|
+
<div class="body">
|
|
459
|
+
${
|
|
460
|
+
this.hasInputContent
|
|
461
|
+
? html`
|
|
462
|
+
<div class="input-area"><slot name="input"></slot></div>
|
|
463
|
+
`
|
|
464
|
+
: nothing
|
|
465
|
+
}
|
|
466
|
+
<slot></slot>
|
|
467
|
+
</div>
|
|
468
|
+
`
|
|
469
|
+
: nothing
|
|
470
|
+
}
|
|
471
|
+
</div>
|
|
472
|
+
`;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (!this.isExpandable) {
|
|
476
|
+
if (!this.hasVisibleHeaderContent) {
|
|
477
|
+
return nothing;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return html`
|
|
481
|
+
<div class="row" data-tone=${tone} data-status=${status}>
|
|
482
|
+
<div class="row-header">${this.renderHeaderContent()}</div>
|
|
483
|
+
</div>
|
|
484
|
+
`;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return html`
|
|
488
|
+
<details
|
|
489
|
+
class="row"
|
|
490
|
+
data-tone=${tone}
|
|
491
|
+
data-status=${status}
|
|
492
|
+
?open=${this.open}
|
|
493
|
+
@toggle=${this.handleToggle}
|
|
494
|
+
>
|
|
495
|
+
<summary class="row-header" interactive>${this.renderHeaderContent()}</summary>
|
|
496
|
+
${
|
|
497
|
+
this.hasInputContent
|
|
498
|
+
? html`
|
|
499
|
+
<div class="input-area"><slot name="input"></slot></div>
|
|
500
|
+
`
|
|
501
|
+
: nothing
|
|
502
|
+
}
|
|
503
|
+
<div class="body"><slot></slot></div>
|
|
504
|
+
</details>
|
|
505
|
+
`;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
declare global {
|
|
510
|
+
interface HTMLElementTagNameMap {
|
|
511
|
+
"ai-tool-call": AiToolCall;
|
|
512
|
+
}
|
|
513
|
+
}
|