@nuraly/lumenui 0.6.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.
- package/README.md +22 -0
- package/dist/cdn.js +1 -1
- package/dist/nuralyui.bundle.js +55 -55
- package/dist/nuralyui.bundle.js.gz +0 -0
- package/dist/src/components/canvas/bundle.js +98 -98
- package/dist/src/components/canvas/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/bundle.js +69 -69
- package/dist/src/components/chatbot/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/chatbot.component.d.ts +13 -2
- package/dist/src/components/chatbot/chatbot.component.js +81 -10
- package/dist/src/components/chatbot/chatbot.style.js +31 -42
- package/dist/src/components/chatbot/chatbot.types.d.ts +1 -0
- package/dist/src/components/chatbot/templates/chatbot-main.template.d.ts +4 -0
- package/dist/src/components/chatbot/templates/chatbot-main.template.js +6 -4
- package/dist/src/components/chatbot/templates/message.template.d.ts +3 -8
- package/dist/src/components/chatbot/templates/message.template.js +24 -12
- package/package.json +1 -1
- package/packages/themes/dist/default.css +12 -0
|
Binary file
|
|
@@ -79,7 +79,13 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
79
79
|
enableThreadCreation: boolean;
|
|
80
80
|
/** Array of conversation threads */
|
|
81
81
|
threads: ChatbotThread[];
|
|
82
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Currently active thread ID. Set this from a route loader to pre-select a
|
|
84
|
+
* conversation; when a controller is attached, the chatbot will call
|
|
85
|
+
* `controller.switchThread(activeThreadId)` to load that thread's messages.
|
|
86
|
+
* Emits an `nr-thread-change` event when the active thread changes via the
|
|
87
|
+
* sidebar (so a router can sync the URL back).
|
|
88
|
+
*/
|
|
83
89
|
activeThreadId?: string;
|
|
84
90
|
/** Chatbot mode (chat, assistant, etc.) */
|
|
85
91
|
mode: string;
|
|
@@ -89,12 +95,15 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
89
95
|
enableUrlSync: boolean;
|
|
90
96
|
/** Show messages area (set to false for input-only mode) */
|
|
91
97
|
showMessages: boolean;
|
|
98
|
+
/** Welcome heading shown in the empty state. Overridden by a slotted `empty-state` child if provided. */
|
|
99
|
+
welcomeMessage?: string;
|
|
92
100
|
/** Enable file upload functionality */
|
|
93
101
|
enableFileUpload: boolean;
|
|
94
102
|
/** Uploaded files (synced from controller) */
|
|
95
103
|
uploadedFiles: ChatbotFile[];
|
|
96
|
-
/** Action buttons configuration */
|
|
104
|
+
/** Action buttons configuration. `enableFileUpload` unions an attach entry into the resolved list unless one is already present. */
|
|
97
105
|
actionButtons: ChatbotAction[];
|
|
106
|
+
get resolvedActionButtons(): ChatbotAction[];
|
|
98
107
|
/** Enable module selection dropdown */
|
|
99
108
|
enableModuleSelection: boolean;
|
|
100
109
|
/** Available modules for selection */
|
|
@@ -162,6 +171,8 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
162
171
|
*/
|
|
163
172
|
private teardownUrlSync;
|
|
164
173
|
private handleHashChange;
|
|
174
|
+
private _pendingThreadId?;
|
|
175
|
+
private syncActiveThreadToController;
|
|
165
176
|
private handleControllerStateChange;
|
|
166
177
|
private handleControllerMessageSent;
|
|
167
178
|
private handleControllerMessageReceived;
|
|
@@ -80,6 +80,7 @@ const DEFAULT_I18N = {
|
|
|
80
80
|
retryButton: msg('Retry'),
|
|
81
81
|
startConversationLabel: msg('Start a conversation'),
|
|
82
82
|
suggestionPrefix: msg('Select suggestion: '),
|
|
83
|
+
loadingConversationLabel: msg('Loading conversation…'),
|
|
83
84
|
},
|
|
84
85
|
urlModal: {
|
|
85
86
|
addUrlTitle: msg('Add URL'),
|
|
@@ -180,7 +181,7 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
180
181
|
this.enableFileUpload = false;
|
|
181
182
|
/** Uploaded files (synced from controller) */
|
|
182
183
|
this.uploadedFiles = [];
|
|
183
|
-
/** Action buttons configuration */
|
|
184
|
+
/** Action buttons configuration. `enableFileUpload` unions an attach entry into the resolved list unless one is already present. */
|
|
184
185
|
this.actionButtons = [];
|
|
185
186
|
/** Enable module selection dropdown */
|
|
186
187
|
this.enableModuleSelection = false;
|
|
@@ -217,6 +218,16 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
217
218
|
this.isThreadSidebarOpen = !this.isThreadSidebarOpen;
|
|
218
219
|
};
|
|
219
220
|
}
|
|
221
|
+
get resolvedActionButtons() {
|
|
222
|
+
var _a;
|
|
223
|
+
const explicit = (_a = this.actionButtons) !== null && _a !== void 0 ? _a : [];
|
|
224
|
+
if (!this.enableFileUpload)
|
|
225
|
+
return explicit;
|
|
226
|
+
const hasAttach = explicit.some((a) => (a === null || a === void 0 ? void 0 : a.type) === 'attach');
|
|
227
|
+
if (hasAttach)
|
|
228
|
+
return explicit;
|
|
229
|
+
return [...explicit, { type: 'attach', enabled: true }];
|
|
230
|
+
}
|
|
220
231
|
/** Convert modules to select options */
|
|
221
232
|
get moduleSelectOptions() {
|
|
222
233
|
return this.modules.map(module => ({
|
|
@@ -329,8 +340,12 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
329
340
|
if (this.enableUrlSync) {
|
|
330
341
|
this.handleHashChange();
|
|
331
342
|
}
|
|
343
|
+
this.syncActiveThreadToController();
|
|
332
344
|
}
|
|
333
345
|
}
|
|
346
|
+
if (changedProperties.has('activeThreadId')) {
|
|
347
|
+
this.syncActiveThreadToController();
|
|
348
|
+
}
|
|
334
349
|
// Handle enableUrlSync toggled after connectedCallback
|
|
335
350
|
if (changedProperties.has('enableUrlSync')) {
|
|
336
351
|
if (this.enableUrlSync) {
|
|
@@ -428,8 +443,38 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
428
443
|
}
|
|
429
444
|
}
|
|
430
445
|
}
|
|
446
|
+
syncActiveThreadToController() {
|
|
447
|
+
var _a;
|
|
448
|
+
if (!this.controller || !this.activeThreadId) {
|
|
449
|
+
this._pendingThreadId = undefined;
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
let state;
|
|
453
|
+
try {
|
|
454
|
+
state = this.controller.getState();
|
|
455
|
+
}
|
|
456
|
+
catch (_b) {
|
|
457
|
+
state = null;
|
|
458
|
+
}
|
|
459
|
+
if ((state === null || state === void 0 ? void 0 : state.currentThreadId) === this.activeThreadId) {
|
|
460
|
+
this._pendingThreadId = undefined;
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const exists = (_a = state === null || state === void 0 ? void 0 : state.threads) === null || _a === void 0 ? void 0 : _a.some((t) => t.id === this.activeThreadId);
|
|
464
|
+
if (!exists) {
|
|
465
|
+
this._pendingThreadId = this.activeThreadId;
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
this._pendingThreadId = undefined;
|
|
469
|
+
try {
|
|
470
|
+
this.controller.switchThread(this.activeThreadId);
|
|
471
|
+
}
|
|
472
|
+
catch (_c) {
|
|
473
|
+
this._pendingThreadId = this.activeThreadId;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
431
476
|
handleControllerStateChange(state) {
|
|
432
|
-
var _a, _b, _c, _d, _e;
|
|
477
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
433
478
|
// Sync controller state to component properties
|
|
434
479
|
if (state.messages)
|
|
435
480
|
this.messages = state.messages;
|
|
@@ -439,15 +484,26 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
439
484
|
if (state.suggestions && state.suggestions.length > 0) {
|
|
440
485
|
this.suggestions = state.suggestions;
|
|
441
486
|
}
|
|
442
|
-
if (state.currentThreadId)
|
|
487
|
+
if (state.currentThreadId && state.currentThreadId !== this.activeThreadId) {
|
|
443
488
|
this.activeThreadId = state.currentThreadId;
|
|
489
|
+
}
|
|
490
|
+
if (this._pendingThreadId && ((_a = state.threads) === null || _a === void 0 ? void 0 : _a.some((t) => t.id === this._pendingThreadId))) {
|
|
491
|
+
const pending = this._pendingThreadId;
|
|
492
|
+
this._pendingThreadId = undefined;
|
|
493
|
+
try {
|
|
494
|
+
(_b = this.controller) === null || _b === void 0 ? void 0 : _b.switchThread(pending);
|
|
495
|
+
}
|
|
496
|
+
catch (_h) {
|
|
497
|
+
this._pendingThreadId = pending;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
444
500
|
if (this.enableUrlSync && state.currentThreadId) {
|
|
445
501
|
const newHash = `#conversation/${encodeURIComponent(state.currentThreadId)}`;
|
|
446
502
|
if (window.location.hash !== newHash) {
|
|
447
503
|
history.replaceState(null, '', newHash);
|
|
448
504
|
}
|
|
449
505
|
}
|
|
450
|
-
this.chatStarted = ((
|
|
506
|
+
this.chatStarted = ((_c = state.messages) === null || _c === void 0 ? void 0 : _c.length) > 0;
|
|
451
507
|
this.isBotTyping = state.isTyping || false;
|
|
452
508
|
this.statusText = state.statusText;
|
|
453
509
|
// Keep Stop button in sync with provider processing lifecycle
|
|
@@ -457,19 +513,19 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
457
513
|
this.uploadedFiles = state.uploadedFiles;
|
|
458
514
|
// Reset artifact panel when switching to a conversation with no artifacts
|
|
459
515
|
if (this.enableArtifacts) {
|
|
460
|
-
const hasArtifacts = (
|
|
516
|
+
const hasArtifacts = (_d = state.messages) === null || _d === void 0 ? void 0 : _d.some((m) => { var _a, _b; return ((_b = (_a = m.metadata) === null || _a === void 0 ? void 0 : _a.artifactIds) === null || _b === void 0 ? void 0 : _b.length) > 0; });
|
|
461
517
|
if (!hasArtifacts) {
|
|
462
518
|
this.isArtifactPanelOpen = false;
|
|
463
519
|
this.selectedArtifact = null;
|
|
464
520
|
}
|
|
465
521
|
}
|
|
466
522
|
// Auto-select the last artifact when a new one appears
|
|
467
|
-
if (this.enableArtifacts && ((
|
|
523
|
+
if (this.enableArtifacts && ((_e = state.messages) === null || _e === void 0 ? void 0 : _e.length)) {
|
|
468
524
|
const lastBot = [...state.messages].reverse().find((m) => m.sender === 'bot');
|
|
469
|
-
const artifactIds = (
|
|
525
|
+
const artifactIds = (_f = lastBot === null || lastBot === void 0 ? void 0 : lastBot.metadata) === null || _f === void 0 ? void 0 : _f.artifactIds;
|
|
470
526
|
if (artifactIds === null || artifactIds === void 0 ? void 0 : artifactIds.length) {
|
|
471
527
|
const lastId = artifactIds[artifactIds.length - 1];
|
|
472
|
-
if (((
|
|
528
|
+
if (((_g = this.selectedArtifact) === null || _g === void 0 ? void 0 : _g.id) !== lastId) {
|
|
473
529
|
const plugin = this.getArtifactPlugin();
|
|
474
530
|
const artifact = plugin === null || plugin === void 0 ? void 0 : plugin.getArtifact(lastId);
|
|
475
531
|
if (artifact) {
|
|
@@ -513,6 +569,8 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
513
569
|
const templateData = {
|
|
514
570
|
boxed: this.boxed,
|
|
515
571
|
showMessages: this.showMessages,
|
|
572
|
+
welcomeMessage: this.welcomeMessage,
|
|
573
|
+
isPendingThread: !!this._pendingThreadId,
|
|
516
574
|
messages: this.messages,
|
|
517
575
|
isTyping: this.isBotTyping,
|
|
518
576
|
loadingIndicator: this.loadingIndicator,
|
|
@@ -526,7 +584,7 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
526
584
|
uploadedFiles: this.uploadedFiles,
|
|
527
585
|
isQueryRunning: this.isQueryRunning,
|
|
528
586
|
showSendButton: this.showSendButton,
|
|
529
|
-
enableFileUpload: this.
|
|
587
|
+
enableFileUpload: this.resolvedActionButtons.some((action) => (action === null || action === void 0 ? void 0 : action.type) === 'attach' && (action === null || action === void 0 ? void 0 : action.enabled) !== false),
|
|
530
588
|
fileUploadItems: [
|
|
531
589
|
{ id: 'upload-file', label: 'Upload File', icon: 'upload' },
|
|
532
590
|
{ id: 'upload-url', label: 'Upload from URL', icon: 'link' }
|
|
@@ -601,10 +659,17 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
601
659
|
onCreateNew: () => { var _a; (_a = this.controller) === null || _a === void 0 ? void 0 : _a.createThread('New Chat'); },
|
|
602
660
|
onSelectThread: (threadId) => {
|
|
603
661
|
var _a;
|
|
662
|
+
if (threadId === this.activeThreadId)
|
|
663
|
+
return;
|
|
604
664
|
if (this.enableUrlSync) {
|
|
605
665
|
history.pushState(null, '', `#conversation/${encodeURIComponent(threadId)}`);
|
|
606
666
|
}
|
|
607
667
|
(_a = this.controller) === null || _a === void 0 ? void 0 : _a.switchThread(threadId);
|
|
668
|
+
this.dispatchEvent(new CustomEvent('nr-thread-change', {
|
|
669
|
+
detail: { threadId },
|
|
670
|
+
bubbles: true,
|
|
671
|
+
composed: true,
|
|
672
|
+
}));
|
|
608
673
|
},
|
|
609
674
|
onDeleteThread: (threadId) => { var _a; (_a = this.controller) === null || _a === void 0 ? void 0 : _a.deleteThread(threadId); },
|
|
610
675
|
onBookmarkThread: (threadId) => { var _a; (_a = this.controller) === null || _a === void 0 ? void 0 : _a.bookmarkThread(threadId); },
|
|
@@ -1194,7 +1259,7 @@ __decorate([
|
|
|
1194
1259
|
property({ type: Array })
|
|
1195
1260
|
], NrChatbotElement.prototype, "threads", void 0);
|
|
1196
1261
|
__decorate([
|
|
1197
|
-
property({ type: String })
|
|
1262
|
+
property({ type: String, attribute: 'active-thread-id' })
|
|
1198
1263
|
], NrChatbotElement.prototype, "activeThreadId", void 0);
|
|
1199
1264
|
__decorate([
|
|
1200
1265
|
property({ type: String })
|
|
@@ -1208,6 +1273,9 @@ __decorate([
|
|
|
1208
1273
|
__decorate([
|
|
1209
1274
|
property({ type: Boolean })
|
|
1210
1275
|
], NrChatbotElement.prototype, "showMessages", void 0);
|
|
1276
|
+
__decorate([
|
|
1277
|
+
property({ type: String, attribute: 'welcome-message' })
|
|
1278
|
+
], NrChatbotElement.prototype, "welcomeMessage", void 0);
|
|
1211
1279
|
__decorate([
|
|
1212
1280
|
property({ type: Boolean })
|
|
1213
1281
|
], NrChatbotElement.prototype, "enableFileUpload", void 0);
|
|
@@ -1286,6 +1354,9 @@ __decorate([
|
|
|
1286
1354
|
__decorate([
|
|
1287
1355
|
state()
|
|
1288
1356
|
], NrChatbotElement.prototype, "_isDragging", void 0);
|
|
1357
|
+
__decorate([
|
|
1358
|
+
state()
|
|
1359
|
+
], NrChatbotElement.prototype, "_pendingThreadId", void 0);
|
|
1289
1360
|
NrChatbotElement = __decorate([
|
|
1290
1361
|
localized(),
|
|
1291
1362
|
customElement('nr-chatbot')
|
|
@@ -19,10 +19,10 @@ export default css `
|
|
|
19
19
|
display: flex;
|
|
20
20
|
width: 100%;
|
|
21
21
|
height: 100%;
|
|
22
|
-
background-color: #ffffff;
|
|
23
22
|
border-radius: 8px;
|
|
24
23
|
position: relative;
|
|
25
24
|
border: 1px solid #e0e0e0;
|
|
25
|
+
box-sizing: border-box;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
.chatbot-container {
|
|
@@ -47,13 +47,24 @@ export default css `
|
|
|
47
47
|
min-width: 0;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
.chatbot-boxed-area {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
flex: 1;
|
|
54
|
+
min-height: 0;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
width: 100%;
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
.chatbot-header {
|
|
51
60
|
display: flex;
|
|
52
61
|
align-items: center;
|
|
53
62
|
justify-content: space-between;
|
|
54
63
|
gap: 0.5rem;
|
|
55
64
|
padding: 0.5rem;
|
|
56
|
-
|
|
65
|
+
min-height: 43px;
|
|
66
|
+
box-sizing: border-box;
|
|
67
|
+
border-bottom: 1px solid var(--nuraly-color-divider, rgb(224, 224, 224));
|
|
57
68
|
}
|
|
58
69
|
|
|
59
70
|
.chatbot-content {
|
|
@@ -65,7 +76,6 @@ export default css `
|
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
:host([boxed]) .chat-container {
|
|
68
|
-
background-color: #ffffff;
|
|
69
79
|
border: none;
|
|
70
80
|
border-radius: 0;
|
|
71
81
|
}
|
|
@@ -76,22 +86,15 @@ export default css `
|
|
|
76
86
|
|
|
77
87
|
:host([boxed]) .chatbot-main {
|
|
78
88
|
width: 100%;
|
|
79
|
-
max-width: 768px;
|
|
80
|
-
margin: 0 auto;
|
|
81
|
-
background-color: #ffffff;
|
|
82
89
|
border: none;
|
|
83
90
|
border-radius: 0;
|
|
84
91
|
box-shadow: none;
|
|
85
92
|
height: 100%;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.chat-container--boxed.chat-container--with-threads .chatbot-main {
|
|
94
|
-
background-color: #ffffff;
|
|
95
|
+
:host([boxed]) .chatbot-boxed-area {
|
|
96
|
+
max-width: 768px;
|
|
97
|
+
margin: 0 auto;
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
.chat-container--boxed.chat-container--with-threads .chat-box {
|
|
@@ -107,9 +110,7 @@ export default css `
|
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
:host([boxed]) .chatbot-header {
|
|
110
|
-
/* Keep header at the top */
|
|
111
113
|
flex: 0 0 auto;
|
|
112
|
-
border-bottom: none;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
:host([boxed]) .chatbot-content:has(.empty-state) {
|
|
@@ -123,24 +124,15 @@ export default css `
|
|
|
123
124
|
min-height: 0;
|
|
124
125
|
}
|
|
125
126
|
|
|
126
|
-
:host([boxed]) .chatbot-main:has(.empty-state) {
|
|
127
|
-
/* Make main container relative for absolute positioning */
|
|
128
|
-
position: relative;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
127
|
:host([boxed]) .empty-state {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
transform: translate(-50%, calc(-50% - 80px));
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
flex-direction: column;
|
|
137
132
|
width: 100%;
|
|
133
|
+
height: 100%;
|
|
138
134
|
max-width: 768px;
|
|
139
|
-
height: auto;
|
|
140
135
|
padding: 0;
|
|
141
|
-
display: flex;
|
|
142
|
-
flex-direction: column;
|
|
143
|
-
align-items: center;
|
|
144
136
|
gap: 1.5rem;
|
|
145
137
|
}
|
|
146
138
|
|
|
@@ -149,13 +141,9 @@ export default css `
|
|
|
149
141
|
}
|
|
150
142
|
|
|
151
143
|
:host([boxed]) .chatbot-content:has(.empty-state) + .input-box {
|
|
152
|
-
/* Position input-box in the middle with empty state - moved up */
|
|
153
|
-
position: absolute;
|
|
154
|
-
top: 50%;
|
|
155
|
-
left: 50%;
|
|
156
|
-
transform: translate(-50%, calc(-50% + 40px));
|
|
157
144
|
width: 100%;
|
|
158
145
|
max-width: 768px;
|
|
146
|
+
margin: 0 auto;
|
|
159
147
|
}
|
|
160
148
|
|
|
161
149
|
:host([boxed]) .suggestion-container {
|
|
@@ -165,7 +153,7 @@ export default css `
|
|
|
165
153
|
:host([boxed]) .messages {
|
|
166
154
|
box-shadow: none;
|
|
167
155
|
margin-bottom: 0;
|
|
168
|
-
background-color:
|
|
156
|
+
background-color: var(--chatbot-messages-bg, transparent);
|
|
169
157
|
align-items: stretch;
|
|
170
158
|
width: 98%;
|
|
171
159
|
padding: 8px 1.5rem;
|
|
@@ -209,7 +197,7 @@ export default css `
|
|
|
209
197
|
align-items: center;
|
|
210
198
|
justify-content: space-between;
|
|
211
199
|
padding: 0.75rem;
|
|
212
|
-
border-bottom: 1px solid
|
|
200
|
+
border-bottom: 1px solid var(--nuraly-color-divider, rgb(224, 224, 224));
|
|
213
201
|
}
|
|
214
202
|
|
|
215
203
|
.thread-sidebar__header h3 {
|
|
@@ -420,12 +408,13 @@ export default css `
|
|
|
420
408
|
|
|
421
409
|
.messages {
|
|
422
410
|
flex: 1;
|
|
411
|
+
min-height: 0;
|
|
423
412
|
overflow-y: auto;
|
|
424
413
|
overflow-x: hidden;
|
|
425
414
|
display: flex;
|
|
426
415
|
flex-direction: column;
|
|
427
416
|
gap: 0;
|
|
428
|
-
background-color:
|
|
417
|
+
background-color: var(--chatbot-messages-bg, transparent);
|
|
429
418
|
padding: 8px 1rem;
|
|
430
419
|
box-sizing: border-box;
|
|
431
420
|
justify-content: flex-start; /* Always align messages to top */
|
|
@@ -564,16 +553,16 @@ export default css `
|
|
|
564
553
|
}
|
|
565
554
|
|
|
566
555
|
.message.user .message__content {
|
|
567
|
-
background-color:
|
|
568
|
-
color:
|
|
556
|
+
background-color: var(--nuraly-color-user-bubble-bg, rgb(124, 58, 237));
|
|
557
|
+
color: var(--nuraly-color-user-bubble-fg, rgb(255, 255, 255));
|
|
569
558
|
border-radius: var(--chatbot-radius, 8px);
|
|
570
559
|
border: 0 solid transparent;
|
|
571
560
|
box-shadow: none;
|
|
572
561
|
}
|
|
573
562
|
|
|
574
563
|
.message.bot .message__content {
|
|
575
|
-
background-color: transparent;
|
|
576
|
-
color: inherit;
|
|
564
|
+
background-color: var(--nuraly-color-bot-bubble-bg, transparent);
|
|
565
|
+
color: var(--nuraly-color-bot-bubble-fg, inherit);
|
|
577
566
|
border-radius: 0;
|
|
578
567
|
border: 0 solid transparent;
|
|
579
568
|
box-shadow: none;
|
|
@@ -1618,10 +1607,10 @@ export default css `
|
|
|
1618
1607
|
.artifact-panel {
|
|
1619
1608
|
width: 400px;
|
|
1620
1609
|
min-width: 300px;
|
|
1610
|
+
min-height: 0;
|
|
1621
1611
|
flex-shrink: 0;
|
|
1622
1612
|
display: flex;
|
|
1623
1613
|
flex-direction: row;
|
|
1624
|
-
background-color: #ffffff;
|
|
1625
1614
|
overflow: hidden;
|
|
1626
1615
|
position: relative;
|
|
1627
1616
|
}
|
|
@@ -16,6 +16,10 @@ export interface ChatbotMainTemplateData {
|
|
|
16
16
|
boxed?: boolean;
|
|
17
17
|
/** Show messages area (set to false for input-only mode) */
|
|
18
18
|
showMessages?: boolean;
|
|
19
|
+
/** Welcome heading shown when the messages list is empty. Falls back to i18n.messages.startConversationLabel. */
|
|
20
|
+
welcomeMessage?: string;
|
|
21
|
+
/** True when activeThreadId points at a thread that has not yet been loaded. Renders a loading state in the messages area. */
|
|
22
|
+
isPendingThread?: boolean;
|
|
19
23
|
messages: ChatbotMessage[];
|
|
20
24
|
isTyping: boolean;
|
|
21
25
|
loadingIndicator?: ChatbotLoadingType;
|
|
@@ -52,7 +52,7 @@ function renderContentArea(data, handlers) {
|
|
|
52
52
|
<div class="chatbot-content" part="content">
|
|
53
53
|
${renderMessages(data.messages, renderSuggestions(data.chatStarted, data.suggestions, handlers.suggestion, data.i18n), data.isTyping
|
|
54
54
|
? renderBotTypingIndicator(data.isTyping, data.loadingIndicator || ChatbotLoadingType.Spinner, data.loadingText)
|
|
55
|
-
: nothing, handlers.message, data.i18n)}
|
|
55
|
+
: nothing, handlers.message, data.i18n, data.welcomeMessage, data.isPendingThread)}
|
|
56
56
|
<slot name="messages"></slot>
|
|
57
57
|
</div>
|
|
58
58
|
`;
|
|
@@ -92,11 +92,13 @@ export function renderChatbotMain(data, handlers) {
|
|
|
92
92
|
<div class="chatbot-main" part="main">
|
|
93
93
|
${renderThreadHeader(data, handlers)}
|
|
94
94
|
|
|
95
|
-
<
|
|
95
|
+
<div class="chatbot-boxed-area" part="boxed-area">
|
|
96
|
+
<slot name="header"></slot>
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
${renderContentArea(data, handlers)}
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
${renderInputBox(data.inputBox, handlers.inputBox)}
|
|
101
|
+
</div>
|
|
100
102
|
|
|
101
103
|
<slot name="footer"></slot>
|
|
102
104
|
</div>
|
|
@@ -20,12 +20,7 @@ export declare function renderMessage(message: ChatbotMessage, handlers: Message
|
|
|
20
20
|
* Renders bot typing indicator
|
|
21
21
|
*/
|
|
22
22
|
export declare function renderBotTypingIndicator(isTyping: boolean, loadingIndicator: ChatbotLoadingType, loadingText?: string): TemplateResult | typeof nothing;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export declare function renderEmptyState(i18n: ChatbotI18n): TemplateResult;
|
|
27
|
-
/**
|
|
28
|
-
* Renders messages container with all messages
|
|
29
|
-
*/
|
|
30
|
-
export declare function renderMessages(messages: ChatbotMessage[], suggestions: TemplateResult | typeof nothing, typingIndicator: TemplateResult | typeof nothing, messageHandlers: MessageTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
|
|
23
|
+
export declare function renderEmptyState(i18n: ChatbotI18n, welcomeMessage?: string): TemplateResult;
|
|
24
|
+
export declare function renderThreadLoading(i18n: ChatbotI18n): TemplateResult;
|
|
25
|
+
export declare function renderMessages(messages: ChatbotMessage[], suggestions: TemplateResult | typeof nothing, typingIndicator: TemplateResult | typeof nothing, messageHandlers: MessageTemplateHandlers, i18n: ChatbotI18n, welcomeMessage?: string, isPendingThread?: boolean): TemplateResult;
|
|
31
26
|
//# sourceMappingURL=message.template.d.ts.map
|
|
@@ -68,14 +68,15 @@ export function renderMessage(message, handlers, i18n) {
|
|
|
68
68
|
introduction: !!message.introduction,
|
|
69
69
|
[message.sender]: true,
|
|
70
70
|
};
|
|
71
|
+
const role = message.sender;
|
|
71
72
|
return html `
|
|
72
73
|
<div
|
|
73
74
|
class="message ${classMap(messageClasses)}"
|
|
74
|
-
part
|
|
75
|
+
part=${`message message-${role}`}
|
|
75
76
|
data-sender="${message.sender}"
|
|
76
77
|
data-id="${message.id}"
|
|
77
78
|
>
|
|
78
|
-
<div class="message__content" part
|
|
79
|
+
<div class="message__content" part=${`message-content message-content-${role}`}>
|
|
79
80
|
${isError
|
|
80
81
|
? renderErrorMessage((_c = (_b = message.text) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : '')
|
|
81
82
|
: ((_d = message === null || message === void 0 ? void 0 : message.metadata) === null || _d === void 0 ? void 0 : _d.renderAsHtml)
|
|
@@ -194,27 +195,38 @@ export function renderBotTypingIndicator(isTyping, loadingIndicator, loadingText
|
|
|
194
195
|
</div>
|
|
195
196
|
`;
|
|
196
197
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
*/
|
|
200
|
-
export function renderEmptyState(i18n) {
|
|
198
|
+
export function renderEmptyState(i18n, welcomeMessage) {
|
|
199
|
+
const heading = welcomeMessage !== null && welcomeMessage !== void 0 ? welcomeMessage : i18n.messages.startConversationLabel;
|
|
201
200
|
return html `
|
|
202
201
|
<div class="empty-state" part="empty-state">
|
|
203
202
|
<slot name="empty-state">
|
|
204
203
|
<div class="empty-state__content" part="empty-state-content">
|
|
205
|
-
${
|
|
204
|
+
${heading}
|
|
206
205
|
</div>
|
|
207
206
|
</slot>
|
|
208
207
|
</div>
|
|
209
208
|
`;
|
|
210
209
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
210
|
+
export function renderThreadLoading(i18n) {
|
|
211
|
+
return html `
|
|
212
|
+
<div class="empty-state empty-state--loading" part="empty-state thread-loading">
|
|
213
|
+
<slot name="thread-loading">
|
|
214
|
+
<div class="spinner" part="thread-loading-spinner"></div>
|
|
215
|
+
<div class="empty-state__content" part="empty-state-content">
|
|
216
|
+
${i18n.messages.loadingConversationLabel}
|
|
217
|
+
</div>
|
|
218
|
+
</slot>
|
|
219
|
+
</div>
|
|
220
|
+
`;
|
|
221
|
+
}
|
|
222
|
+
export function renderMessages(messages, suggestions, typingIndicator, messageHandlers, i18n, welcomeMessage, isPendingThread) {
|
|
215
223
|
return html `
|
|
216
224
|
<div class="messages" part="messages">
|
|
217
|
-
${messages.length === 0
|
|
225
|
+
${messages.length === 0
|
|
226
|
+
? isPendingThread
|
|
227
|
+
? renderThreadLoading(i18n)
|
|
228
|
+
: renderEmptyState(i18n, welcomeMessage)
|
|
229
|
+
: nothing}
|
|
218
230
|
${messages.map((message) => renderMessage(message, messageHandlers, i18n))}
|
|
219
231
|
${suggestions}
|
|
220
232
|
${typingIndicator}
|
package/package.json
CHANGED
|
@@ -64,6 +64,11 @@
|
|
|
64
64
|
--nuraly-color-info-light: #e6f7ff;
|
|
65
65
|
--nuraly-color-info-dark: #0050b3;
|
|
66
66
|
|
|
67
|
+
--nuraly-color-user-bubble-bg: rgb(124, 58, 237);
|
|
68
|
+
--nuraly-color-user-bubble-fg: rgb(255, 255, 255);
|
|
69
|
+
--nuraly-color-bot-bubble-bg: transparent;
|
|
70
|
+
--nuraly-color-bot-bubble-fg: inherit;
|
|
71
|
+
|
|
67
72
|
--nuraly-color-background: #ffffff;
|
|
68
73
|
--nuraly-color-background-hover: #fafafa;
|
|
69
74
|
--nuraly-color-background-active: #f5f5f5;
|
|
@@ -85,6 +90,7 @@
|
|
|
85
90
|
--nuraly-color-border-danger: #ff4d4f;
|
|
86
91
|
--nuraly-color-border-success: #52c41a;
|
|
87
92
|
--nuraly-color-border-warning: #faad14;
|
|
93
|
+
--nuraly-color-divider: rgb(224, 224, 224);
|
|
88
94
|
|
|
89
95
|
--nuraly-border-radius-none: 0;
|
|
90
96
|
--nuraly-border-radius-xs: 2px;
|
|
@@ -201,6 +207,11 @@
|
|
|
201
207
|
--nuraly-color-info-light: #93c5fd;
|
|
202
208
|
--nuraly-color-info-dark: #1e40af;
|
|
203
209
|
|
|
210
|
+
--nuraly-color-user-bubble-bg: rgb(124, 58, 237);
|
|
211
|
+
--nuraly-color-user-bubble-fg: rgb(255, 255, 255);
|
|
212
|
+
--nuraly-color-bot-bubble-bg: transparent;
|
|
213
|
+
--nuraly-color-bot-bubble-fg: inherit;
|
|
214
|
+
|
|
204
215
|
--nuraly-color-background: #111827;
|
|
205
216
|
--nuraly-color-background-hover: #1f2937;
|
|
206
217
|
--nuraly-color-background-active: #374151;
|
|
@@ -222,6 +233,7 @@
|
|
|
222
233
|
--nuraly-color-border-danger: #f87171;
|
|
223
234
|
--nuraly-color-border-success: #34d399;
|
|
224
235
|
--nuraly-color-border-warning: #fbbf24;
|
|
236
|
+
--nuraly-color-divider: #374151;
|
|
225
237
|
|
|
226
238
|
--nuraly-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
227
239
|
--nuraly-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
|