@genesislcap/ai-assistant 14.482.2-alpha-397d953.0 → 14.483.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/dist/dts/main/index.d.ts +0 -1
- package/dist/dts/main/index.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/suggestions/chat-suggestions.d.ts +7 -0
- package/dist/dts/suggestions/chat-suggestions.d.ts.map +1 -1
- package/dist/esm/main/index.js +0 -1
- package/dist/esm/main/main.styles.js +78 -2
- package/dist/esm/main/main.template.js +34 -14
- package/dist/esm/suggestions/chat-suggestions.js +23 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/styling.md +132 -0
- package/package.json +17 -17
- package/src/main/index.ts +0 -1
- package/src/main/main.styles.ts +78 -2
- package/src/main/main.template.ts +47 -23
- package/src/suggestions/chat-suggestions.ts +22 -1
- package/dist/dts/styles/index.d.ts +0 -2
- package/dist/dts/styles/index.d.ts.map +0 -1
- package/dist/dts/styles/styles.d.ts +0 -5
- package/dist/dts/styles/styles.d.ts.map +0 -1
- package/dist/esm/styles/index.js +0 -1
- package/dist/esm/styles/styles.js +0 -237
- package/src/styles/index.ts +0 -1
- package/src/styles/styles.ts +0 -238
package/dist/dts/main/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/main/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/main/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"AA4tBA,eAAO,MAAM,MAAM,iDAGlB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,EAAuC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,EAAuC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAsOpD,gBAAgB;AAChB,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CAwapC,CAAC"}
|
|
@@ -2,6 +2,13 @@ import { GenesisElement } from '@genesislcap/web-core';
|
|
|
2
2
|
import type { SuggestionsState } from '../main/main.types';
|
|
3
3
|
export declare class ChatSuggestions extends GenesisElement {
|
|
4
4
|
state: SuggestionsState;
|
|
5
|
+
/**
|
|
6
|
+
* Reflected to a `has-content` attribute so the host can collapse when there is
|
|
7
|
+
* nothing to render. True only while loading or when loaded with at least one
|
|
8
|
+
* suggestion; idle, errored, and empty-loaded states render nothing.
|
|
9
|
+
*/
|
|
10
|
+
hasContent: boolean;
|
|
11
|
+
stateChanged(): void;
|
|
5
12
|
handleSuggestionClick(suggestion: string): void;
|
|
6
13
|
}
|
|
7
14
|
//# sourceMappingURL=chat-suggestions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-suggestions.d.ts","sourceRoot":"","sources":["../../../src/suggestions/chat-suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"chat-suggestions.d.ts","sourceRoot":"","sources":["../../../src/suggestions/chat-suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EAMf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAuJ3D,qBAKa,eAAgB,SAAQ,cAAc;IAEjD,KAAK,EAAE,gBAAgB,CAAsB;IAE7C;;;;OAIG;IACkD,UAAU,UAAS;IAExE,YAAY,IAAI,IAAI;IAKpB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;CAGhD"}
|
package/dist/esm/main/index.js
CHANGED
|
@@ -3,6 +3,13 @@ import { settingsModalStyles } from '../components/settings-modal/settings-modal
|
|
|
3
3
|
import { AI_COLOUR_AMBER, AI_COLOUR_CYAN, AI_COLOUR_PINK, AI_COLOUR_VIOLET, } from '../styles/ai-colours';
|
|
4
4
|
const baseStyles = css `
|
|
5
5
|
:host {
|
|
6
|
+
/* Shared max width for the conversation column and the composer, so they stay
|
|
7
|
+
aligned. Override on the host to change both at once. NOTE: the @container
|
|
8
|
+
threshold that floats the composer can't read this (container queries can't
|
|
9
|
+
use custom properties), so if you override this below the 1500px default the
|
|
10
|
+
float still triggers at 1500px. */
|
|
11
|
+
--ai-conversation-max-width: 1500px;
|
|
12
|
+
|
|
6
13
|
display: flex;
|
|
7
14
|
flex-direction: column;
|
|
8
15
|
height: 100%;
|
|
@@ -81,9 +88,20 @@ const baseStyles = css `
|
|
|
81
88
|
min-height: 0;
|
|
82
89
|
overflow-y: auto;
|
|
83
90
|
padding: 10px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Caps and centres the conversation column inside the (full-width) scroll
|
|
94
|
+
container, so the scrollbar stays at the panel edge while the messages sit
|
|
95
|
+
in a readable-width column. Exposed as part="messages-content" so a host
|
|
96
|
+
can widen it (::part(messages-content) { max-width: none }) or neutralise
|
|
97
|
+
the wrapper entirely (::part(messages-content) { display: contents }). */
|
|
98
|
+
.messages-content {
|
|
84
99
|
display: flex;
|
|
85
100
|
flex-direction: column;
|
|
86
|
-
gap:
|
|
101
|
+
gap: calc(var(--design-unit) * 2.5px);
|
|
102
|
+
width: 100%;
|
|
103
|
+
max-width: var(--ai-conversation-max-width);
|
|
104
|
+
margin-inline: auto;
|
|
87
105
|
}
|
|
88
106
|
|
|
89
107
|
@keyframes slide-in-right {
|
|
@@ -230,11 +248,17 @@ const baseStyles = css `
|
|
|
230
248
|
}
|
|
231
249
|
|
|
232
250
|
.message {
|
|
233
|
-
padding: calc(var(--design-unit) *
|
|
251
|
+
padding: calc(var(--design-unit) * 2.5px) calc(var(--design-unit) * 3.5px);
|
|
234
252
|
max-width: 80%;
|
|
235
253
|
min-width: 70px;
|
|
236
254
|
font-family: var(--body-font);
|
|
237
255
|
font-size: 1.1em;
|
|
256
|
+
|
|
257
|
+
/* Long unbroken strings (URLs, file paths, tokens, base64) wrap instead of
|
|
258
|
+
overflowing the bubble. overflow-wrap: anywhere also lets the bubble shrink
|
|
259
|
+
below such a string's width in the flex row, preventing horizontal overflow. */
|
|
260
|
+
overflow-wrap: anywhere;
|
|
261
|
+
word-break: break-word;
|
|
238
262
|
}
|
|
239
263
|
|
|
240
264
|
.message.user {
|
|
@@ -399,6 +423,58 @@ const baseStyles = css `
|
|
|
399
423
|
background-color: var(--neutral-layer-2);
|
|
400
424
|
}
|
|
401
425
|
|
|
426
|
+
/* Mirror the messages column: cap the composer (input row + its buttons, resize
|
|
427
|
+
handle, attachment chips, agent picker panel, suggestions) at the same max width
|
|
428
|
+
and centre it, so it does not span full width while the messages sit in a
|
|
429
|
+
narrower column. These are flex items in the column layout, so margin-inline:auto
|
|
430
|
+
would disable their default stretch — width:100% keeps them filling up to the
|
|
431
|
+
cap, and border-box keeps padding/border from overflowing when full-width.
|
|
432
|
+
Overridable via ::part(input-row) etc. */
|
|
433
|
+
.input-row,
|
|
434
|
+
.composer-resize-handle,
|
|
435
|
+
.attachment-chips,
|
|
436
|
+
.agent-picker-panel,
|
|
437
|
+
chat-suggestions {
|
|
438
|
+
box-sizing: border-box;
|
|
439
|
+
width: 100%;
|
|
440
|
+
max-width: var(--ai-conversation-max-width);
|
|
441
|
+
margin-inline: auto;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* When the assistant is wider than that cap the composer is genuinely constrained,
|
|
445
|
+
so lift the input row — and the panels that sit above it — into matching
|
|
446
|
+
floating, rounded, outlined cards with a gap to the bottom. Below the cap they
|
|
447
|
+
stay full-width and flush (the default border-top). The query resolves against
|
|
448
|
+
the assistant's own inline-size container (.chat-wrapper). The threshold is a
|
|
449
|
+
literal because a container query can't read a custom property — keep it equal
|
|
450
|
+
to the --ai-conversation-max-width default. */
|
|
451
|
+
@container (width > 1500px) {
|
|
452
|
+
.input-row,
|
|
453
|
+
.agent-picker-panel,
|
|
454
|
+
chat-suggestions {
|
|
455
|
+
border: 1px solid var(--neutral-stroke-rest);
|
|
456
|
+
border-radius: 12px;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* chat-suggestions paints its background on an inner element, so clip it to the
|
|
460
|
+
rounded corners — otherwise that square inner background bleeds past the radius
|
|
461
|
+
and the corners read as square with the border hidden behind them. */
|
|
462
|
+
chat-suggestions {
|
|
463
|
+
overflow: hidden;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.input-row {
|
|
467
|
+
margin-bottom: 12px;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* Suggestions and the picker stack above the input row — a smaller gap keeps
|
|
471
|
+
the cards distinct without a large void. */
|
|
472
|
+
.agent-picker-panel,
|
|
473
|
+
chat-suggestions {
|
|
474
|
+
margin-bottom: 8px;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
402
478
|
/* Right-hand control column, mirroring .input-left-controls — holds the
|
|
403
479
|
Stop button (shown while a turn runs) stacked above the Send button. The
|
|
404
480
|
Stop button is an icon (stop → spinner), so the column width is driven by
|
|
@@ -111,6 +111,20 @@ const senderLabelFor = (m) => m.category === 'narration' ? 'Working' : senderLab
|
|
|
111
111
|
* `m.interaction` first; non-interaction messages never consult this.
|
|
112
112
|
*/
|
|
113
113
|
const interactionPresentation = (m) => { var _a, _b; return (_b = (_a = m.interaction) === null || _a === void 0 ? void 0 : _a.presentation) !== null && _b !== void 0 ? _b : 'label'; };
|
|
114
|
+
/**
|
|
115
|
+
* Space-separated `part` names for a message bubble, so a host can style bubbles
|
|
116
|
+
* from its own stylesheet via `::part()`. Every bubble gets `message` plus its
|
|
117
|
+
* type (`message-user`, `message-ai`, `message-ai-thinking`, `message-ai-function`,
|
|
118
|
+
* `message-interaction`). Interaction bubbles additionally carry a
|
|
119
|
+
* presentation-specific part (`message-interaction-label` / `-bare` / `-bubble`)
|
|
120
|
+
* so a host can target, say, only the bubble-framed widgets.
|
|
121
|
+
*/
|
|
122
|
+
const messageParts = (m) => {
|
|
123
|
+
const type = messageType(m);
|
|
124
|
+
return type === 'interaction'
|
|
125
|
+
? `message message-interaction message-interaction-${interactionPresentation(m)}`
|
|
126
|
+
: `message message-${type}`;
|
|
127
|
+
};
|
|
114
128
|
// ─── Sub-agent trace fragments ────────────────────────────────────────────────
|
|
115
129
|
const subAgentAssistantTemplate = html `
|
|
116
130
|
<div class="sub-agent-message sub-agent-assistant">${(m) => m.content}</div>
|
|
@@ -238,6 +252,7 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
|
|
|
238
252
|
</div>
|
|
239
253
|
<div
|
|
240
254
|
class="message ${(m) => messageType(m)} ${(m) => classNames(['narration', m.category === 'narration'])}"
|
|
255
|
+
part="${(m) => messageParts(m)}"
|
|
241
256
|
>
|
|
242
257
|
${when(
|
|
243
258
|
// A 'bare' interaction owns its full presentation — suppress the
|
|
@@ -385,28 +400,33 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
|
|
|
385
400
|
</div>
|
|
386
401
|
|
|
387
402
|
<div class="messages" part="messages" ${ref('messagesEl')}>
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
403
|
+
<div class="messages-content" part="messages-content">
|
|
404
|
+
${repeat((x) => x.visibleMessages, messageRowTemplate)}
|
|
405
|
+
${repeat((x) => x.activeInteractionRow, messageRowTemplate)}
|
|
406
|
+
${when((x) => x.liveSubAgentTrace.length > 0 && x.showToolCalls, liveSubAgentTraceTemplate)}
|
|
407
|
+
${when((x) => {
|
|
392
408
|
var _a;
|
|
393
409
|
return x.showLoadingIndicator &&
|
|
394
410
|
(((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.animations) == null ||
|
|
395
411
|
LOADING_STYLE_ANIMATIONS.some((s) => x.enabledAnimations.includes(s)));
|
|
396
412
|
}, html `
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
413
|
+
<div class="message-row ai" part="thinking">
|
|
414
|
+
<div class="avatar">
|
|
415
|
+
${(x) => x.imageSrc
|
|
400
416
|
? html `
|
|
401
|
-
|
|
402
|
-
|
|
417
|
+
<img src="${() => x.imageSrc}" alt="Assistant" class="avatar-img" />
|
|
418
|
+
`
|
|
403
419
|
: html `
|
|
404
|
-
|
|
405
|
-
|
|
420
|
+
<span
|
|
421
|
+
class="avatar-icon"
|
|
422
|
+
:innerHTML="${() => x.assistantIconSafe}"
|
|
423
|
+
></span>
|
|
424
|
+
`}
|
|
425
|
+
</div>
|
|
426
|
+
${(x) => selectThinkingTemplate(x)}
|
|
406
427
|
</div>
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
`)}
|
|
428
|
+
`)}
|
|
429
|
+
</div>
|
|
410
430
|
</div>
|
|
411
431
|
|
|
412
432
|
${when((x) => !x.composerHiddenByConfig && (x.attachments.length > 0 || x.attachmentErrors.length > 0), html `
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { customElement, GenesisElement, observable, html, css, repeat, when, } from '@genesislcap/web-core';
|
|
2
|
+
import { attr, customElement, GenesisElement, observable, html, css, repeat, when, } from '@genesislcap/web-core';
|
|
3
3
|
const PILL_ANIMATION_STAGGER_MS = 70;
|
|
4
4
|
const template = html `
|
|
5
5
|
${when((x) => x.state.status === 'loading', html `
|
|
@@ -25,14 +25,22 @@ const template = html `
|
|
|
25
25
|
`;
|
|
26
26
|
const styles = css `
|
|
27
27
|
:host {
|
|
28
|
+
/* Collapsed unless there is something to render (see hasContent), so the empty
|
|
29
|
+
host never occupies space or shows through a consumer's border as a stray
|
|
30
|
+
line. */
|
|
31
|
+
display: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:host([has-content]) {
|
|
28
35
|
display: block;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
.suggestions-container {
|
|
32
39
|
display: flex;
|
|
33
40
|
flex-wrap: wrap;
|
|
41
|
+
align-items: center;
|
|
34
42
|
gap: 6px;
|
|
35
|
-
padding:
|
|
43
|
+
padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
|
|
36
44
|
background-color: var(--neutral-layer-2);
|
|
37
45
|
animation: suggestions-appear 0.2s ease-out both;
|
|
38
46
|
}
|
|
@@ -128,6 +136,16 @@ let ChatSuggestions = class ChatSuggestions extends GenesisElement {
|
|
|
128
136
|
constructor() {
|
|
129
137
|
super(...arguments);
|
|
130
138
|
this.state = { status: 'idle' };
|
|
139
|
+
/**
|
|
140
|
+
* Reflected to a `has-content` attribute so the host can collapse when there is
|
|
141
|
+
* nothing to render. True only while loading or when loaded with at least one
|
|
142
|
+
* suggestion; idle, errored, and empty-loaded states render nothing.
|
|
143
|
+
*/
|
|
144
|
+
this.hasContent = false;
|
|
145
|
+
}
|
|
146
|
+
stateChanged() {
|
|
147
|
+
const s = this.state;
|
|
148
|
+
this.hasContent = s.status === 'loading' || (s.status === 'loaded' && s.suggestions.length > 0);
|
|
131
149
|
}
|
|
132
150
|
handleSuggestionClick(suggestion) {
|
|
133
151
|
this.$emit('suggestion-clicked', suggestion);
|
|
@@ -136,6 +154,9 @@ let ChatSuggestions = class ChatSuggestions extends GenesisElement {
|
|
|
136
154
|
__decorate([
|
|
137
155
|
observable
|
|
138
156
|
], ChatSuggestions.prototype, "state", void 0);
|
|
157
|
+
__decorate([
|
|
158
|
+
attr({ attribute: 'has-content', mode: 'boolean' })
|
|
159
|
+
], ChatSuggestions.prototype, "hasContent", void 0);
|
|
139
160
|
ChatSuggestions = __decorate([
|
|
140
161
|
customElement({
|
|
141
162
|
name: 'chat-suggestions',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/flowing-waves-indicator.ts","../src/components/halo-overlay.ts","../src/components/plasma-orb-indicator.ts","../src/components/waves-indicator.ts","../src/components/activity-halo/activity-halo.ts","../src/components/agent-picker/agent-picker.constants.ts","../src/components/agent-picker/agent-picker.styles.ts","../src/components/agent-picker/agent-picker.template.ts","../src/components/agent-picker/agent-picker.ts","../src/components/agent-picker/index.ts","../src/components/ai-driver/ai-driver.ts","../src/components/ai-driver/index.ts","../src/components/chat-bubble/chat-bubble.styles.ts","../src/components/chat-bubble/chat-bubble.template.ts","../src/components/chat-bubble/chat-bubble.ts","../src/components/chat-bubble/index.ts","../src/components/chat-driver/align-event-globals.ts","../src/components/chat-driver/chat-driver.test.ts","../src/components/chat-driver/chat-driver.ts","../src/components/chat-driver/index.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts","../src/components/chat-interaction-wrapper/index.ts","../src/components/chat-markdown/chat-markdown.ts","../src/components/chat-markdown/index.ts","../src/components/orchestrating-driver/index.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/components/settings-modal/index.ts","../src/components/settings-modal/settings-modal.styles.ts","../src/components/settings-modal/settings-modal.template.ts","../src/config/config.ts","../src/config/define-stateful-agent.test.ts","../src/config/define-stateful-agent.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/config/validate-providers.test.ts","../src/config/validate-providers.ts","../src/main/index.ts","../src/main/main.styles.ts","../src/main/main.template.ts","../src/main/main.ts","../src/main/main.types.ts","../src/provider/ai-provider-switcher.ts","../src/provider/assistant-app-settings.ts","../src/state/ai-assistant-slice.ts","../src/state/debug-event-log.test.ts","../src/state/debug-event-log.ts","../src/state/driver-registry.test.ts","../src/state/driver-registry.ts","../src/state/session-store.ts","../src/styles/ai-colours.ts","../src/
|
|
1
|
+
{"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/flowing-waves-indicator.ts","../src/components/halo-overlay.ts","../src/components/plasma-orb-indicator.ts","../src/components/waves-indicator.ts","../src/components/activity-halo/activity-halo.ts","../src/components/agent-picker/agent-picker.constants.ts","../src/components/agent-picker/agent-picker.styles.ts","../src/components/agent-picker/agent-picker.template.ts","../src/components/agent-picker/agent-picker.ts","../src/components/agent-picker/index.ts","../src/components/ai-driver/ai-driver.ts","../src/components/ai-driver/index.ts","../src/components/chat-bubble/chat-bubble.styles.ts","../src/components/chat-bubble/chat-bubble.template.ts","../src/components/chat-bubble/chat-bubble.ts","../src/components/chat-bubble/index.ts","../src/components/chat-driver/align-event-globals.ts","../src/components/chat-driver/chat-driver.test.ts","../src/components/chat-driver/chat-driver.ts","../src/components/chat-driver/index.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts","../src/components/chat-interaction-wrapper/index.ts","../src/components/chat-markdown/chat-markdown.ts","../src/components/chat-markdown/index.ts","../src/components/orchestrating-driver/index.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/components/settings-modal/index.ts","../src/components/settings-modal/settings-modal.styles.ts","../src/components/settings-modal/settings-modal.template.ts","../src/config/config.ts","../src/config/define-stateful-agent.test.ts","../src/config/define-stateful-agent.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/config/validate-providers.test.ts","../src/config/validate-providers.ts","../src/main/index.ts","../src/main/main.styles.ts","../src/main/main.template.ts","../src/main/main.ts","../src/main/main.types.ts","../src/provider/ai-provider-switcher.ts","../src/provider/assistant-app-settings.ts","../src/state/ai-assistant-slice.ts","../src/state/debug-event-log.test.ts","../src/state/debug-event-log.ts","../src/state/driver-registry.test.ts","../src/state/driver-registry.ts","../src/state/session-store.ts","../src/styles/ai-colours.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/collect-session-models.test.ts","../src/utils/collect-session-models.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/cost-session-history.test.ts","../src/utils/cost-session-history.ts","../src/utils/derive-cost-session-title.test.ts","../src/utils/derive-cost-session-title.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.ts","../src/utils/index.ts","../src/utils/logger.ts","../src/utils/message-partition.test.ts","../src/utils/message-partition.ts","../src/utils/resolve-cost-history-config.test.ts","../src/utils/resolve-cost-history-config.ts","../src/utils/strip-agent-handlers.test.ts","../src/utils/strip-agent-handlers.ts","../src/utils/sum-costs.test.ts","../src/utils/sum-costs.ts","../src/utils/sum-tokens.test.ts","../src/utils/sum-tokens.ts","../src/utils/tool-fold.ts"],"version":"5.9.2"}
|
package/docs/styling.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Styling & Theming
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The assistant renders in a shadow root, so its internal classes are not reachable
|
|
6
|
+
from an app stylesheet. Customization is exposed through three deliberate,
|
|
7
|
+
stable surfaces:
|
|
8
|
+
|
|
9
|
+
1. **Design-system tokens** — the widget reads standard tokens (`--neutral-layer-*`,
|
|
10
|
+
`--accent-fill-rest`, `--design-unit`, `--control-corner-radius`, `--body-font`,
|
|
11
|
+
the `--type-ramp-*` ramp, …). These inherit through the shadow boundary, so
|
|
12
|
+
theming the host design system themes the assistant with no widget-specific work.
|
|
13
|
+
2. **`--ai-*` custom properties** — a small set of assistant-specific variables,
|
|
14
|
+
each with a built-in fallback, for the parts of the UI that have no natural
|
|
15
|
+
design-system token.
|
|
16
|
+
3. **CSS Shadow Parts (`::part()`)** — named hooks on internal elements for
|
|
17
|
+
arbitrary restyling from an app stylesheet.
|
|
18
|
+
|
|
19
|
+
Prefer tokens where one exists (they inherit and can be set inline); reach for
|
|
20
|
+
`::part()` when you need to change something a token doesn't cover.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## `--ai-*` custom properties
|
|
25
|
+
|
|
26
|
+
| Property | Default | Applies to |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `--ai-conversation-max-width` | `1500px` | Max width of the centred conversation column **and** the composer (kept in sync) |
|
|
29
|
+
| `--ai-message-shadow` | `0 2px 8px rgb(0 0 0 / 15%)` | Assistant message bubble shadow |
|
|
30
|
+
| `--ai-thinking-color` | `#7c3aed` | Thinking/reasoning bubble and its avatar ring |
|
|
31
|
+
| `--ai-function-color` | `#86efac` | Tool-call bubble text and border |
|
|
32
|
+
|
|
33
|
+
Set them on the host element (or any ancestor — they inherit):
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
foundation-ai-assistant {
|
|
37
|
+
--ai-thinking-color: #2563eb;
|
|
38
|
+
--ai-message-shadow: none;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Shadow parts
|
|
45
|
+
|
|
46
|
+
Parts on the conversation area (the outer frame exposes many more — e.g.
|
|
47
|
+
`chat-header`, `input-row`, `input`, `send-button`):
|
|
48
|
+
|
|
49
|
+
| Part | Element |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `chat-wrapper` | Outer frame (header + messages + composer) |
|
|
52
|
+
| `messages` | Scroll container (full width; owns the scrollbar) |
|
|
53
|
+
| `messages-content` | Width-capped, centred column that holds every message |
|
|
54
|
+
| `message` | Every message bubble |
|
|
55
|
+
| `message-<type>` | A bubble of one kind: `message-user`, `message-ai`, `message-ai-thinking`, `message-ai-function`, `message-interaction` |
|
|
56
|
+
| `message-interaction-<presentation>` | An interaction bubble in one presentation: `message-interaction-label`, `message-interaction-bare`, `message-interaction-bubble` |
|
|
57
|
+
| `thinking` | The loading-indicator row |
|
|
58
|
+
|
|
59
|
+
Target them from an app stylesheet with `::part()`:
|
|
60
|
+
|
|
61
|
+
```css
|
|
62
|
+
/* Constrain every bubble to a width range */
|
|
63
|
+
foundation-ai-assistant::part(message) {
|
|
64
|
+
min-width: 200px;
|
|
65
|
+
max-width: 640px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Restyle just one kind of bubble */
|
|
69
|
+
foundation-ai-assistant::part(message-user) {
|
|
70
|
+
border-radius: 18px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Only interaction widgets, and only when framed as a bubble */
|
|
74
|
+
foundation-ai-assistant::part(message-interaction-bubble) {
|
|
75
|
+
min-width: 320px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Change the padding inside bubbles */
|
|
79
|
+
foundation-ai-assistant::part(message) {
|
|
80
|
+
padding: 12px 16px;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### The conversation column (`messages-content`)
|
|
85
|
+
|
|
86
|
+
Messages sit in a column capped at `1000px` and centred inside the full-width
|
|
87
|
+
scroll container, so the scrollbar stays at the panel edge while the text keeps
|
|
88
|
+
a readable width. Adjust or remove the cap via the part:
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
/* Widen (or narrow) the column */
|
|
92
|
+
foundation-ai-assistant::part(messages-content) { max-width: 1400px; }
|
|
93
|
+
|
|
94
|
+
/* Remove the cap — messages fill the full width */
|
|
95
|
+
foundation-ai-assistant::part(messages-content) { max-width: none; }
|
|
96
|
+
|
|
97
|
+
/* Neutralise the wrapper entirely (as if the div weren't there) */
|
|
98
|
+
foundation-ai-assistant::part(messages-content) { display: contents; }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Responsive sizing
|
|
104
|
+
|
|
105
|
+
A `min-width` only ever affects *short* messages — long ones are already wider —
|
|
106
|
+
so it can push a bubble past a narrow container. The assistant can be rendered at
|
|
107
|
+
any width (docked panel, popout, inline), so size overrides against the *element's*
|
|
108
|
+
width, not the viewport.
|
|
109
|
+
|
|
110
|
+
`@media` queries the viewport, which does not track the assistant's width, so it is
|
|
111
|
+
the wrong tool. Use a **container query** instead. `::part()` rules can be wrapped
|
|
112
|
+
in `@container` from the host stylesheet; the reliable pattern is to make your own
|
|
113
|
+
wrapper a container:
|
|
114
|
+
|
|
115
|
+
```css
|
|
116
|
+
.ai-slot {
|
|
117
|
+
container-type: inline-size;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* A comfortable minimum on wide layouts… */
|
|
121
|
+
foundation-ai-assistant::part(message) {
|
|
122
|
+
min-width: 220px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* …dropped when the assistant itself is narrow, so bubbles never overflow. */
|
|
126
|
+
@container (max-width: 420px) {
|
|
127
|
+
foundation-ai-assistant::part(message) {
|
|
128
|
+
min-width: 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/ai-assistant",
|
|
3
3
|
"description": "Genesis AI Assistant micro-frontend",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.483.0",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -64,25 +64,25 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@genesislcap/foundation-testing": "14.
|
|
68
|
-
"@genesislcap/genx": "14.
|
|
69
|
-
"@genesislcap/rollup-builder": "14.
|
|
70
|
-
"@genesislcap/ts-builder": "14.
|
|
71
|
-
"@genesislcap/uvu-playwright-builder": "14.
|
|
72
|
-
"@genesislcap/vite-builder": "14.
|
|
73
|
-
"@genesislcap/webpack-builder": "14.
|
|
67
|
+
"@genesislcap/foundation-testing": "14.483.0",
|
|
68
|
+
"@genesislcap/genx": "14.483.0",
|
|
69
|
+
"@genesislcap/rollup-builder": "14.483.0",
|
|
70
|
+
"@genesislcap/ts-builder": "14.483.0",
|
|
71
|
+
"@genesislcap/uvu-playwright-builder": "14.483.0",
|
|
72
|
+
"@genesislcap/vite-builder": "14.483.0",
|
|
73
|
+
"@genesislcap/webpack-builder": "14.483.0",
|
|
74
74
|
"@types/dompurify": "^3.0.5",
|
|
75
75
|
"@types/marked": "^5.0.2"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@genesislcap/foundation-ai": "14.
|
|
79
|
-
"@genesislcap/foundation-logger": "14.
|
|
80
|
-
"@genesislcap/foundation-notifications": "14.
|
|
81
|
-
"@genesislcap/foundation-redux": "14.
|
|
82
|
-
"@genesislcap/foundation-ui": "14.
|
|
83
|
-
"@genesislcap/foundation-utils": "14.
|
|
84
|
-
"@genesislcap/rapid-design-system": "14.
|
|
85
|
-
"@genesislcap/web-core": "14.
|
|
78
|
+
"@genesislcap/foundation-ai": "14.483.0",
|
|
79
|
+
"@genesislcap/foundation-logger": "14.483.0",
|
|
80
|
+
"@genesislcap/foundation-notifications": "14.483.0",
|
|
81
|
+
"@genesislcap/foundation-redux": "14.483.0",
|
|
82
|
+
"@genesislcap/foundation-ui": "14.483.0",
|
|
83
|
+
"@genesislcap/foundation-utils": "14.483.0",
|
|
84
|
+
"@genesislcap/rapid-design-system": "14.483.0",
|
|
85
|
+
"@genesislcap/web-core": "14.483.0",
|
|
86
86
|
"dompurify": "^3.3.1",
|
|
87
87
|
"marked": "^17.0.3"
|
|
88
88
|
},
|
|
@@ -94,5 +94,5 @@
|
|
|
94
94
|
"publishConfig": {
|
|
95
95
|
"access": "public"
|
|
96
96
|
},
|
|
97
|
-
"gitHead": "
|
|
97
|
+
"gitHead": "28a6b21ae981f0a10a9a49b503aa0a3c99146da9"
|
|
98
98
|
}
|
package/src/main/index.ts
CHANGED
package/src/main/main.styles.ts
CHANGED
|
@@ -9,6 +9,13 @@ import {
|
|
|
9
9
|
|
|
10
10
|
const baseStyles = css`
|
|
11
11
|
:host {
|
|
12
|
+
/* Shared max width for the conversation column and the composer, so they stay
|
|
13
|
+
aligned. Override on the host to change both at once. NOTE: the @container
|
|
14
|
+
threshold that floats the composer can't read this (container queries can't
|
|
15
|
+
use custom properties), so if you override this below the 1500px default the
|
|
16
|
+
float still triggers at 1500px. */
|
|
17
|
+
--ai-conversation-max-width: 1500px;
|
|
18
|
+
|
|
12
19
|
display: flex;
|
|
13
20
|
flex-direction: column;
|
|
14
21
|
height: 100%;
|
|
@@ -87,9 +94,20 @@ const baseStyles = css`
|
|
|
87
94
|
min-height: 0;
|
|
88
95
|
overflow-y: auto;
|
|
89
96
|
padding: 10px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Caps and centres the conversation column inside the (full-width) scroll
|
|
100
|
+
container, so the scrollbar stays at the panel edge while the messages sit
|
|
101
|
+
in a readable-width column. Exposed as part="messages-content" so a host
|
|
102
|
+
can widen it (::part(messages-content) { max-width: none }) or neutralise
|
|
103
|
+
the wrapper entirely (::part(messages-content) { display: contents }). */
|
|
104
|
+
.messages-content {
|
|
90
105
|
display: flex;
|
|
91
106
|
flex-direction: column;
|
|
92
|
-
gap:
|
|
107
|
+
gap: calc(var(--design-unit) * 2.5px);
|
|
108
|
+
width: 100%;
|
|
109
|
+
max-width: var(--ai-conversation-max-width);
|
|
110
|
+
margin-inline: auto;
|
|
93
111
|
}
|
|
94
112
|
|
|
95
113
|
@keyframes slide-in-right {
|
|
@@ -236,11 +254,17 @@ const baseStyles = css`
|
|
|
236
254
|
}
|
|
237
255
|
|
|
238
256
|
.message {
|
|
239
|
-
padding: calc(var(--design-unit) *
|
|
257
|
+
padding: calc(var(--design-unit) * 2.5px) calc(var(--design-unit) * 3.5px);
|
|
240
258
|
max-width: 80%;
|
|
241
259
|
min-width: 70px;
|
|
242
260
|
font-family: var(--body-font);
|
|
243
261
|
font-size: 1.1em;
|
|
262
|
+
|
|
263
|
+
/* Long unbroken strings (URLs, file paths, tokens, base64) wrap instead of
|
|
264
|
+
overflowing the bubble. overflow-wrap: anywhere also lets the bubble shrink
|
|
265
|
+
below such a string's width in the flex row, preventing horizontal overflow. */
|
|
266
|
+
overflow-wrap: anywhere;
|
|
267
|
+
word-break: break-word;
|
|
244
268
|
}
|
|
245
269
|
|
|
246
270
|
.message.user {
|
|
@@ -405,6 +429,58 @@ const baseStyles = css`
|
|
|
405
429
|
background-color: var(--neutral-layer-2);
|
|
406
430
|
}
|
|
407
431
|
|
|
432
|
+
/* Mirror the messages column: cap the composer (input row + its buttons, resize
|
|
433
|
+
handle, attachment chips, agent picker panel, suggestions) at the same max width
|
|
434
|
+
and centre it, so it does not span full width while the messages sit in a
|
|
435
|
+
narrower column. These are flex items in the column layout, so margin-inline:auto
|
|
436
|
+
would disable their default stretch — width:100% keeps them filling up to the
|
|
437
|
+
cap, and border-box keeps padding/border from overflowing when full-width.
|
|
438
|
+
Overridable via ::part(input-row) etc. */
|
|
439
|
+
.input-row,
|
|
440
|
+
.composer-resize-handle,
|
|
441
|
+
.attachment-chips,
|
|
442
|
+
.agent-picker-panel,
|
|
443
|
+
chat-suggestions {
|
|
444
|
+
box-sizing: border-box;
|
|
445
|
+
width: 100%;
|
|
446
|
+
max-width: var(--ai-conversation-max-width);
|
|
447
|
+
margin-inline: auto;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/* When the assistant is wider than that cap the composer is genuinely constrained,
|
|
451
|
+
so lift the input row — and the panels that sit above it — into matching
|
|
452
|
+
floating, rounded, outlined cards with a gap to the bottom. Below the cap they
|
|
453
|
+
stay full-width and flush (the default border-top). The query resolves against
|
|
454
|
+
the assistant's own inline-size container (.chat-wrapper). The threshold is a
|
|
455
|
+
literal because a container query can't read a custom property — keep it equal
|
|
456
|
+
to the --ai-conversation-max-width default. */
|
|
457
|
+
@container (width > 1500px) {
|
|
458
|
+
.input-row,
|
|
459
|
+
.agent-picker-panel,
|
|
460
|
+
chat-suggestions {
|
|
461
|
+
border: 1px solid var(--neutral-stroke-rest);
|
|
462
|
+
border-radius: 12px;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/* chat-suggestions paints its background on an inner element, so clip it to the
|
|
466
|
+
rounded corners — otherwise that square inner background bleeds past the radius
|
|
467
|
+
and the corners read as square with the border hidden behind them. */
|
|
468
|
+
chat-suggestions {
|
|
469
|
+
overflow: hidden;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.input-row {
|
|
473
|
+
margin-bottom: 12px;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* Suggestions and the picker stack above the input row — a smaller gap keeps
|
|
477
|
+
the cards distinct without a large void. */
|
|
478
|
+
.agent-picker-panel,
|
|
479
|
+
chat-suggestions {
|
|
480
|
+
margin-bottom: 8px;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
408
484
|
/* Right-hand control column, mirroring .input-left-controls — holds the
|
|
409
485
|
Stop button (shown while a turn runs) stacked above the Send button. The
|
|
410
486
|
Stop button is an icon (stop → spinner), so the column width is driven by
|
|
@@ -130,6 +130,21 @@ const senderLabelFor = (m: ChatMessage): string =>
|
|
|
130
130
|
const interactionPresentation = (m: ChatMessage): InteractionPresentation =>
|
|
131
131
|
m.interaction?.presentation ?? 'label';
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Space-separated `part` names for a message bubble, so a host can style bubbles
|
|
135
|
+
* from its own stylesheet via `::part()`. Every bubble gets `message` plus its
|
|
136
|
+
* type (`message-user`, `message-ai`, `message-ai-thinking`, `message-ai-function`,
|
|
137
|
+
* `message-interaction`). Interaction bubbles additionally carry a
|
|
138
|
+
* presentation-specific part (`message-interaction-label` / `-bare` / `-bubble`)
|
|
139
|
+
* so a host can target, say, only the bubble-framed widgets.
|
|
140
|
+
*/
|
|
141
|
+
const messageParts = (m: ChatMessage): string => {
|
|
142
|
+
const type = messageType(m);
|
|
143
|
+
return type === 'interaction'
|
|
144
|
+
? `message message-interaction message-interaction-${interactionPresentation(m)}`
|
|
145
|
+
: `message message-${type}`;
|
|
146
|
+
};
|
|
147
|
+
|
|
133
148
|
// ─── Sub-agent trace fragments ────────────────────────────────────────────────
|
|
134
149
|
|
|
135
150
|
const subAgentAssistantTemplate = html<ChatMessage>`
|
|
@@ -310,6 +325,7 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
|
|
|
310
325
|
<div
|
|
311
326
|
class="message ${(m) => messageType(m)} ${(m) =>
|
|
312
327
|
classNames(['narration', m.category === 'narration'])}"
|
|
328
|
+
part="${(m) => messageParts(m)}"
|
|
313
329
|
>
|
|
314
330
|
${when(
|
|
315
331
|
// A 'bare' interaction owns its full presentation — suppress the
|
|
@@ -496,30 +512,38 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
|
|
|
496
512
|
</div>
|
|
497
513
|
|
|
498
514
|
<div class="messages" part="messages" ${ref('messagesEl')}>
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
515
|
+
<div class="messages-content" part="messages-content">
|
|
516
|
+
${repeat((x) => x.visibleMessages, messageRowTemplate)}
|
|
517
|
+
${repeat((x) => x.activeInteractionRow, messageRowTemplate)}
|
|
518
|
+
${when(
|
|
519
|
+
(x) => x.liveSubAgentTrace.length > 0 && x.showToolCalls,
|
|
520
|
+
liveSubAgentTraceTemplate,
|
|
521
|
+
)}
|
|
522
|
+
${when(
|
|
523
|
+
(x) =>
|
|
524
|
+
x.showLoadingIndicator &&
|
|
525
|
+
(x.chatConfig.ui?.animations == null ||
|
|
526
|
+
LOADING_STYLE_ANIMATIONS.some((s) => x.enabledAnimations.includes(s))),
|
|
527
|
+
html<FoundationAiAssistant>`
|
|
528
|
+
<div class="message-row ai" part="thinking">
|
|
529
|
+
<div class="avatar">
|
|
530
|
+
${(x) =>
|
|
531
|
+
x.imageSrc
|
|
532
|
+
? html<FoundationAiAssistant>`
|
|
533
|
+
<img src="${() => x.imageSrc}" alt="Assistant" class="avatar-img" />
|
|
534
|
+
`
|
|
535
|
+
: html<FoundationAiAssistant>`
|
|
536
|
+
<span
|
|
537
|
+
class="avatar-icon"
|
|
538
|
+
:innerHTML="${() => x.assistantIconSafe}"
|
|
539
|
+
></span>
|
|
540
|
+
`}
|
|
541
|
+
</div>
|
|
542
|
+
${(x) => selectThinkingTemplate(x)}
|
|
518
543
|
</div>
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
)}
|
|
544
|
+
`,
|
|
545
|
+
)}
|
|
546
|
+
</div>
|
|
523
547
|
</div>
|
|
524
548
|
|
|
525
549
|
${when(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
attr,
|
|
2
3
|
customElement,
|
|
3
4
|
GenesisElement,
|
|
4
5
|
observable,
|
|
@@ -50,14 +51,22 @@ const template = html<ChatSuggestions>`
|
|
|
50
51
|
|
|
51
52
|
const styles = css`
|
|
52
53
|
:host {
|
|
54
|
+
/* Collapsed unless there is something to render (see hasContent), so the empty
|
|
55
|
+
host never occupies space or shows through a consumer's border as a stray
|
|
56
|
+
line. */
|
|
57
|
+
display: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:host([has-content]) {
|
|
53
61
|
display: block;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
.suggestions-container {
|
|
57
65
|
display: flex;
|
|
58
66
|
flex-wrap: wrap;
|
|
67
|
+
align-items: center;
|
|
59
68
|
gap: 6px;
|
|
60
|
-
padding:
|
|
69
|
+
padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
|
|
61
70
|
background-color: var(--neutral-layer-2);
|
|
62
71
|
animation: suggestions-appear 0.2s ease-out both;
|
|
63
72
|
}
|
|
@@ -159,6 +168,18 @@ export class ChatSuggestions extends GenesisElement {
|
|
|
159
168
|
@observable
|
|
160
169
|
state: SuggestionsState = { status: 'idle' };
|
|
161
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Reflected to a `has-content` attribute so the host can collapse when there is
|
|
173
|
+
* nothing to render. True only while loading or when loaded with at least one
|
|
174
|
+
* suggestion; idle, errored, and empty-loaded states render nothing.
|
|
175
|
+
*/
|
|
176
|
+
@attr({ attribute: 'has-content', mode: 'boolean' }) hasContent = false;
|
|
177
|
+
|
|
178
|
+
stateChanged(): void {
|
|
179
|
+
const s = this.state;
|
|
180
|
+
this.hasContent = s.status === 'loading' || (s.status === 'loaded' && s.suggestions.length > 0);
|
|
181
|
+
}
|
|
182
|
+
|
|
162
183
|
handleSuggestionClick(suggestion: string): void {
|
|
163
184
|
this.$emit('suggestion-clicked', suggestion);
|
|
164
185
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/styles/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/styles/styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,2BAA2B,iDAwOvC,CAAC"}
|
package/dist/esm/styles/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './styles';
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
import { css } from '@genesislcap/web-core';
|
|
2
|
-
/**
|
|
3
|
-
* @beta
|
|
4
|
-
*/
|
|
5
|
-
export const FoundationAiAssistantStyles = css `
|
|
6
|
-
:host {
|
|
7
|
-
display: flex;
|
|
8
|
-
flex-direction: column;
|
|
9
|
-
height: 100%;
|
|
10
|
-
box-sizing: border-box;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.chat-wrapper {
|
|
14
|
-
display: flex;
|
|
15
|
-
flex-direction: column;
|
|
16
|
-
height: 100%;
|
|
17
|
-
overflow: hidden;
|
|
18
|
-
background: var(--neutral-fill-layer-rest, var(--neutral-layer-1));
|
|
19
|
-
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
20
|
-
border: 1px solid var(--neutral-stroke-rest);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.chat-header {
|
|
24
|
-
display: flex;
|
|
25
|
-
align-items: center;
|
|
26
|
-
gap: calc(var(--design-unit, 4) * 3px);
|
|
27
|
-
padding: calc(var(--design-unit, 4) * 1.5px) calc(var(--design-unit, 4) * 3px);
|
|
28
|
-
border-bottom: 1px solid var(--neutral-stroke-rest);
|
|
29
|
-
background: var(--neutral-fill-stealth-rest);
|
|
30
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
31
|
-
color: var(--neutral-foreground-rest);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.chat-title {
|
|
35
|
-
flex: 1;
|
|
36
|
-
font-weight: 600;
|
|
37
|
-
font-size: var(--type-ramp-base-font-size);
|
|
38
|
-
overflow: hidden;
|
|
39
|
-
text-overflow: ellipsis;
|
|
40
|
-
white-space: nowrap;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.toggle-label {
|
|
44
|
-
display: flex;
|
|
45
|
-
align-items: center;
|
|
46
|
-
gap: calc(var(--design-unit, 4) * 1px);
|
|
47
|
-
cursor: pointer;
|
|
48
|
-
user-select: none;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.toggle-label input[type='checkbox'] {
|
|
52
|
-
cursor: pointer;
|
|
53
|
-
accent-color: var(--accent-fill-rest);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.download-button {
|
|
57
|
-
margin-left: auto;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.messages {
|
|
61
|
-
flex: 1;
|
|
62
|
-
overflow-y: auto;
|
|
63
|
-
padding: calc(var(--design-unit, 4) * 3px);
|
|
64
|
-
display: flex;
|
|
65
|
-
flex-direction: column;
|
|
66
|
-
gap: calc(var(--design-unit, 4) * 2px);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.message {
|
|
70
|
-
padding: calc(var(--design-unit, 4) * 2px) calc(var(--design-unit, 4) * 3px);
|
|
71
|
-
border-radius: calc(var(--design-unit, 4) * 2px);
|
|
72
|
-
max-width: 80%;
|
|
73
|
-
word-break: break-word;
|
|
74
|
-
font-size: var(--type-ramp-base-font-size);
|
|
75
|
-
line-height: var(--type-ramp-base-line-height);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.message--user {
|
|
79
|
-
align-self: flex-end;
|
|
80
|
-
background: var(--accent-fill-rest);
|
|
81
|
-
color: var(--foreground-on-accent-rest);
|
|
82
|
-
border-bottom-right-radius: calc(var(--design-unit, 4) * 0.5px);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.message--assistant {
|
|
86
|
-
align-self: flex-start;
|
|
87
|
-
background: var(--neutral-fill-rest);
|
|
88
|
-
color: var(--neutral-foreground-rest);
|
|
89
|
-
border-bottom-left-radius: calc(var(--design-unit, 4) * 0.5px);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.thinking-block {
|
|
93
|
-
margin-bottom: calc(var(--design-unit, 4) * 1px);
|
|
94
|
-
border: 1px solid var(--neutral-stroke-rest);
|
|
95
|
-
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
96
|
-
overflow: hidden;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.thinking-summary {
|
|
100
|
-
cursor: pointer;
|
|
101
|
-
padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
|
|
102
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
103
|
-
color: var(--neutral-foreground-hint);
|
|
104
|
-
user-select: none;
|
|
105
|
-
list-style: none;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.thinking-summary::marker,
|
|
109
|
-
.thinking-summary::-webkit-details-marker {
|
|
110
|
-
display: none;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.thinking-summary::before {
|
|
114
|
-
content: '▶ ';
|
|
115
|
-
font-size: 0.6em;
|
|
116
|
-
vertical-align: middle;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
details[open] .thinking-summary::before {
|
|
120
|
-
content: '▼ ';
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.thinking-content {
|
|
124
|
-
padding: calc(var(--design-unit, 4) * 2px);
|
|
125
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
126
|
-
color: var(--neutral-foreground-hint);
|
|
127
|
-
border-top: 1px solid var(--neutral-stroke-rest);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.tool-calls {
|
|
131
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
132
|
-
color: var(--neutral-foreground-hint);
|
|
133
|
-
font-family: monospace;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.message--tool {
|
|
137
|
-
align-self: flex-start;
|
|
138
|
-
background: var(--neutral-fill-stealth-rest);
|
|
139
|
-
color: var(--neutral-foreground-hint);
|
|
140
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
141
|
-
font-family: monospace;
|
|
142
|
-
max-width: 100%;
|
|
143
|
-
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.empty-state {
|
|
147
|
-
flex: 1;
|
|
148
|
-
display: flex;
|
|
149
|
-
align-items: center;
|
|
150
|
-
justify-content: center;
|
|
151
|
-
color: var(--neutral-foreground-hint);
|
|
152
|
-
font-size: var(--type-ramp-base-font-size);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.thinking {
|
|
156
|
-
align-self: flex-start;
|
|
157
|
-
padding: calc(var(--design-unit, 4) * 1px);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.file-input {
|
|
161
|
-
display: none;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.attachment-chips {
|
|
165
|
-
display: flex;
|
|
166
|
-
flex-wrap: wrap;
|
|
167
|
-
gap: calc(var(--design-unit, 4) * 1px);
|
|
168
|
-
padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
|
|
169
|
-
border-top: 1px solid var(--neutral-stroke-rest);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.attachment-chip {
|
|
173
|
-
display: inline-flex;
|
|
174
|
-
align-items: center;
|
|
175
|
-
gap: calc(var(--design-unit, 4) * 1px);
|
|
176
|
-
padding: calc(var(--design-unit, 4) * 0.5px) calc(var(--design-unit, 4) * 1.5px);
|
|
177
|
-
background: var(--neutral-fill-rest);
|
|
178
|
-
border: 1px solid var(--neutral-stroke-rest);
|
|
179
|
-
border-radius: calc(var(--design-unit, 4) * 4px);
|
|
180
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
181
|
-
color: var(--neutral-foreground-rest);
|
|
182
|
-
max-width: 200px;
|
|
183
|
-
overflow: hidden;
|
|
184
|
-
text-overflow: ellipsis;
|
|
185
|
-
white-space: nowrap;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.attachment-chip-error {
|
|
189
|
-
background: var(--error-fill-rest, #fde8e8);
|
|
190
|
-
border-color: var(--error-stroke-rest, #f87171);
|
|
191
|
-
color: var(--error-foreground-rest, #b91c1c);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
.chip-remove {
|
|
195
|
-
flex-shrink: 0;
|
|
196
|
-
background: none;
|
|
197
|
-
border: none;
|
|
198
|
-
cursor: pointer;
|
|
199
|
-
padding: 0;
|
|
200
|
-
line-height: 1;
|
|
201
|
-
color: inherit;
|
|
202
|
-
opacity: 0.6;
|
|
203
|
-
font-size: 0.9em;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.chip-remove:hover {
|
|
207
|
-
opacity: 1;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
.input-row {
|
|
211
|
-
display: flex;
|
|
212
|
-
gap: calc(var(--design-unit, 4) * 2px);
|
|
213
|
-
padding: calc(var(--design-unit, 4) * 2px);
|
|
214
|
-
border-top: 1px solid var(--neutral-stroke-rest);
|
|
215
|
-
align-items: flex-end;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.attach-button {
|
|
219
|
-
flex-shrink: 0;
|
|
220
|
-
align-self: flex-end;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.chat-input {
|
|
224
|
-
flex: 1;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.chat-input::part(control) {
|
|
228
|
-
resize: none;
|
|
229
|
-
min-height: calc(var(--base-height-multiplier, 10) * 1px + var(--design-unit, 4) * 4px);
|
|
230
|
-
max-height: calc(var(--base-height-multiplier, 10) * 5px);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.send-button {
|
|
234
|
-
flex-shrink: 0;
|
|
235
|
-
align-self: flex-end;
|
|
236
|
-
}
|
|
237
|
-
`;
|
package/src/styles/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './styles';
|
package/src/styles/styles.ts
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { css } from '@genesislcap/web-core';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @beta
|
|
5
|
-
*/
|
|
6
|
-
export const FoundationAiAssistantStyles = css`
|
|
7
|
-
:host {
|
|
8
|
-
display: flex;
|
|
9
|
-
flex-direction: column;
|
|
10
|
-
height: 100%;
|
|
11
|
-
box-sizing: border-box;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.chat-wrapper {
|
|
15
|
-
display: flex;
|
|
16
|
-
flex-direction: column;
|
|
17
|
-
height: 100%;
|
|
18
|
-
overflow: hidden;
|
|
19
|
-
background: var(--neutral-fill-layer-rest, var(--neutral-layer-1));
|
|
20
|
-
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
21
|
-
border: 1px solid var(--neutral-stroke-rest);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.chat-header {
|
|
25
|
-
display: flex;
|
|
26
|
-
align-items: center;
|
|
27
|
-
gap: calc(var(--design-unit, 4) * 3px);
|
|
28
|
-
padding: calc(var(--design-unit, 4) * 1.5px) calc(var(--design-unit, 4) * 3px);
|
|
29
|
-
border-bottom: 1px solid var(--neutral-stroke-rest);
|
|
30
|
-
background: var(--neutral-fill-stealth-rest);
|
|
31
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
32
|
-
color: var(--neutral-foreground-rest);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.chat-title {
|
|
36
|
-
flex: 1;
|
|
37
|
-
font-weight: 600;
|
|
38
|
-
font-size: var(--type-ramp-base-font-size);
|
|
39
|
-
overflow: hidden;
|
|
40
|
-
text-overflow: ellipsis;
|
|
41
|
-
white-space: nowrap;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.toggle-label {
|
|
45
|
-
display: flex;
|
|
46
|
-
align-items: center;
|
|
47
|
-
gap: calc(var(--design-unit, 4) * 1px);
|
|
48
|
-
cursor: pointer;
|
|
49
|
-
user-select: none;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.toggle-label input[type='checkbox'] {
|
|
53
|
-
cursor: pointer;
|
|
54
|
-
accent-color: var(--accent-fill-rest);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.download-button {
|
|
58
|
-
margin-left: auto;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.messages {
|
|
62
|
-
flex: 1;
|
|
63
|
-
overflow-y: auto;
|
|
64
|
-
padding: calc(var(--design-unit, 4) * 3px);
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-direction: column;
|
|
67
|
-
gap: calc(var(--design-unit, 4) * 2px);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.message {
|
|
71
|
-
padding: calc(var(--design-unit, 4) * 2px) calc(var(--design-unit, 4) * 3px);
|
|
72
|
-
border-radius: calc(var(--design-unit, 4) * 2px);
|
|
73
|
-
max-width: 80%;
|
|
74
|
-
word-break: break-word;
|
|
75
|
-
font-size: var(--type-ramp-base-font-size);
|
|
76
|
-
line-height: var(--type-ramp-base-line-height);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.message--user {
|
|
80
|
-
align-self: flex-end;
|
|
81
|
-
background: var(--accent-fill-rest);
|
|
82
|
-
color: var(--foreground-on-accent-rest);
|
|
83
|
-
border-bottom-right-radius: calc(var(--design-unit, 4) * 0.5px);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.message--assistant {
|
|
87
|
-
align-self: flex-start;
|
|
88
|
-
background: var(--neutral-fill-rest);
|
|
89
|
-
color: var(--neutral-foreground-rest);
|
|
90
|
-
border-bottom-left-radius: calc(var(--design-unit, 4) * 0.5px);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.thinking-block {
|
|
94
|
-
margin-bottom: calc(var(--design-unit, 4) * 1px);
|
|
95
|
-
border: 1px solid var(--neutral-stroke-rest);
|
|
96
|
-
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
97
|
-
overflow: hidden;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.thinking-summary {
|
|
101
|
-
cursor: pointer;
|
|
102
|
-
padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
|
|
103
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
104
|
-
color: var(--neutral-foreground-hint);
|
|
105
|
-
user-select: none;
|
|
106
|
-
list-style: none;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
.thinking-summary::marker,
|
|
110
|
-
.thinking-summary::-webkit-details-marker {
|
|
111
|
-
display: none;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
.thinking-summary::before {
|
|
115
|
-
content: '▶ ';
|
|
116
|
-
font-size: 0.6em;
|
|
117
|
-
vertical-align: middle;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
details[open] .thinking-summary::before {
|
|
121
|
-
content: '▼ ';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.thinking-content {
|
|
125
|
-
padding: calc(var(--design-unit, 4) * 2px);
|
|
126
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
127
|
-
color: var(--neutral-foreground-hint);
|
|
128
|
-
border-top: 1px solid var(--neutral-stroke-rest);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.tool-calls {
|
|
132
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
133
|
-
color: var(--neutral-foreground-hint);
|
|
134
|
-
font-family: monospace;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.message--tool {
|
|
138
|
-
align-self: flex-start;
|
|
139
|
-
background: var(--neutral-fill-stealth-rest);
|
|
140
|
-
color: var(--neutral-foreground-hint);
|
|
141
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
142
|
-
font-family: monospace;
|
|
143
|
-
max-width: 100%;
|
|
144
|
-
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.empty-state {
|
|
148
|
-
flex: 1;
|
|
149
|
-
display: flex;
|
|
150
|
-
align-items: center;
|
|
151
|
-
justify-content: center;
|
|
152
|
-
color: var(--neutral-foreground-hint);
|
|
153
|
-
font-size: var(--type-ramp-base-font-size);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
.thinking {
|
|
157
|
-
align-self: flex-start;
|
|
158
|
-
padding: calc(var(--design-unit, 4) * 1px);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.file-input {
|
|
162
|
-
display: none;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.attachment-chips {
|
|
166
|
-
display: flex;
|
|
167
|
-
flex-wrap: wrap;
|
|
168
|
-
gap: calc(var(--design-unit, 4) * 1px);
|
|
169
|
-
padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
|
|
170
|
-
border-top: 1px solid var(--neutral-stroke-rest);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
.attachment-chip {
|
|
174
|
-
display: inline-flex;
|
|
175
|
-
align-items: center;
|
|
176
|
-
gap: calc(var(--design-unit, 4) * 1px);
|
|
177
|
-
padding: calc(var(--design-unit, 4) * 0.5px) calc(var(--design-unit, 4) * 1.5px);
|
|
178
|
-
background: var(--neutral-fill-rest);
|
|
179
|
-
border: 1px solid var(--neutral-stroke-rest);
|
|
180
|
-
border-radius: calc(var(--design-unit, 4) * 4px);
|
|
181
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
182
|
-
color: var(--neutral-foreground-rest);
|
|
183
|
-
max-width: 200px;
|
|
184
|
-
overflow: hidden;
|
|
185
|
-
text-overflow: ellipsis;
|
|
186
|
-
white-space: nowrap;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
.attachment-chip-error {
|
|
190
|
-
background: var(--error-fill-rest, #fde8e8);
|
|
191
|
-
border-color: var(--error-stroke-rest, #f87171);
|
|
192
|
-
color: var(--error-foreground-rest, #b91c1c);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.chip-remove {
|
|
196
|
-
flex-shrink: 0;
|
|
197
|
-
background: none;
|
|
198
|
-
border: none;
|
|
199
|
-
cursor: pointer;
|
|
200
|
-
padding: 0;
|
|
201
|
-
line-height: 1;
|
|
202
|
-
color: inherit;
|
|
203
|
-
opacity: 0.6;
|
|
204
|
-
font-size: 0.9em;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.chip-remove:hover {
|
|
208
|
-
opacity: 1;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.input-row {
|
|
212
|
-
display: flex;
|
|
213
|
-
gap: calc(var(--design-unit, 4) * 2px);
|
|
214
|
-
padding: calc(var(--design-unit, 4) * 2px);
|
|
215
|
-
border-top: 1px solid var(--neutral-stroke-rest);
|
|
216
|
-
align-items: flex-end;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.attach-button {
|
|
220
|
-
flex-shrink: 0;
|
|
221
|
-
align-self: flex-end;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.chat-input {
|
|
225
|
-
flex: 1;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.chat-input::part(control) {
|
|
229
|
-
resize: none;
|
|
230
|
-
min-height: calc(var(--base-height-multiplier, 10) * 1px + var(--design-unit, 4) * 4px);
|
|
231
|
-
max-height: calc(var(--base-height-multiplier, 10) * 5px);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.send-button {
|
|
235
|
-
flex-shrink: 0;
|
|
236
|
-
align-self: flex-end;
|
|
237
|
-
}
|
|
238
|
-
`;
|