@nuraly/lumenui 0.3.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/nuralyui.bundle.js +633 -634
  2. package/dist/nuralyui.bundle.js.gz +0 -0
  3. package/dist/src/components/canvas/bundle.js +409 -410
  4. package/dist/src/components/canvas/bundle.js.gz +0 -0
  5. package/dist/src/components/chatbot/bundle.js +147 -148
  6. package/dist/src/components/chatbot/bundle.js.gz +0 -0
  7. package/dist/src/components/chatbot/chatbot.component.d.ts +14 -1
  8. package/dist/src/components/chatbot/chatbot.component.js +165 -8
  9. package/dist/src/components/chatbot/chatbot.style.js +6 -9
  10. package/dist/src/components/chatbot/chatbot.types.d.ts +94 -0
  11. package/dist/src/components/chatbot/plugins/artifact-plugin.d.ts +44 -0
  12. package/dist/src/components/chatbot/plugins/artifact-plugin.js +62 -0
  13. package/dist/src/components/chatbot/templates/artifact-panel.template.d.ts +2 -1
  14. package/dist/src/components/chatbot/templates/artifact-panel.template.js +4 -5
  15. package/dist/src/components/chatbot/templates/chatbot-main.template.d.ts +3 -1
  16. package/dist/src/components/chatbot/templates/chatbot-main.template.js +15 -10
  17. package/dist/src/components/chatbot/templates/file-upload-area.template.d.ts +5 -6
  18. package/dist/src/components/chatbot/templates/file-upload-area.template.js +4 -11
  19. package/dist/src/components/chatbot/templates/input-box.template.d.ts +2 -1
  20. package/dist/src/components/chatbot/templates/input-box.template.js +25 -26
  21. package/dist/src/components/chatbot/templates/message.template.d.ts +4 -4
  22. package/dist/src/components/chatbot/templates/message.template.js +11 -12
  23. package/dist/src/components/chatbot/templates/suggestion.template.d.ts +3 -9
  24. package/dist/src/components/chatbot/templates/suggestion.template.js +6 -13
  25. package/dist/src/components/chatbot/templates/thread-sidebar.template.d.ts +2 -1
  26. package/dist/src/components/chatbot/templates/thread-sidebar.template.js +11 -12
  27. package/dist/src/components/chatbot/templates/url-modal.template.d.ts +2 -3
  28. package/dist/src/components/chatbot/templates/url-modal.template.js +24 -28
  29. package/dist/src/components/icon/bundle.js +10 -10
  30. package/dist/src/components/icon/bundle.js.gz +0 -0
  31. package/dist/src/components/icon/icon-paths.js +1 -0
  32. package/dist/src/components/iconpicker/bundle.js +1 -1
  33. package/dist/src/components/iconpicker/bundle.js.gz +0 -0
  34. package/dist/src/components/panel/bundle.js +1 -1
  35. package/dist/src/components/panel/bundle.js.gz +0 -0
  36. package/dist/src/components/tabs/bundle.js +1 -1
  37. package/dist/src/components/tabs/bundle.js.gz +0 -0
  38. package/package.json +1 -1
  39. package/packages/common/dist/VERSIONS.md +1 -1
@@ -5,7 +5,6 @@
5
5
  */
6
6
  import { nothing, html } from 'lit';
7
7
  import { classMap } from 'lit/directives/class-map.js';
8
- import { msg } from '@lit/localize';
9
8
  import { renderMessages, renderBotTypingIndicator } from './message.template.js';
10
9
  import { renderSuggestions } from './suggestion.template.js';
11
10
  import { renderInputBox } from './input-box.template.js';
@@ -28,8 +27,8 @@ function renderThreadHeader(data, handlers) {
28
27
  size="small"
29
28
  .icon=${['panel-left']}
30
29
  @click=${handlers.onToggleThreadSidebar}
31
- title="${msg(data.isThreadSidebarOpen ? 'Hide threads' : 'Show threads')}"
32
- aria-label="${msg(data.isThreadSidebarOpen ? 'Hide threads' : 'Show threads')}"
30
+ title="${data.isThreadSidebarOpen ? data.i18n.threads.hideThreadsLabel : data.i18n.threads.showThreadsLabel}"
31
+ aria-label="${data.isThreadSidebarOpen ? data.i18n.threads.hideThreadsLabel : data.i18n.threads.showThreadsLabel}"
33
32
  ></nr-button>
34
33
  ${data.enableThreadCreation && data.messages.length > 0 ? html `
35
34
  <nr-button
@@ -37,8 +36,8 @@ function renderThreadHeader(data, handlers) {
37
36
  size="small"
38
37
  .icon=${['square-pen']}
39
38
  @click=${(_a = handlers.threadSidebar) === null || _a === void 0 ? void 0 : _a.onCreateNew}
40
- title="${msg('New conversation')}"
41
- aria-label="${msg('New conversation')}"
39
+ title="${data.i18n.threads.newConversationLabel}"
40
+ aria-label="${data.i18n.threads.newConversationLabel}"
42
41
  ></nr-button>
43
42
  ` : ''}
44
43
  </div>
@@ -51,9 +50,9 @@ function renderContentArea(data, handlers) {
51
50
  if (data.showMessages !== false) {
52
51
  return html `
53
52
  <div class="chatbot-content" part="content">
54
- ${renderMessages(data.messages, renderSuggestions(data.chatStarted, data.suggestions, handlers.suggestion), data.isTyping
53
+ ${renderMessages(data.messages, renderSuggestions(data.chatStarted, data.suggestions, handlers.suggestion, data.i18n), data.isTyping
55
54
  ? renderBotTypingIndicator(data.isTyping, data.loadingIndicator || ChatbotLoadingType.Spinner, data.loadingText)
56
- : nothing, handlers.message)}
55
+ : nothing, handlers.message, data.i18n)}
57
56
  <slot name="messages"></slot>
58
57
  </div>
59
58
  `;
@@ -62,7 +61,7 @@ function renderContentArea(data, handlers) {
62
61
  if (data.suggestions && data.suggestions.length > 0) {
63
62
  return html `
64
63
  <div class="input-only-suggestions" part="input-only-suggestions">
65
- ${renderSuggestions(false, data.suggestions, handlers.suggestion)}
64
+ ${renderSuggestions(false, data.suggestions, handlers.suggestion, data.i18n)}
66
65
  </div>
67
66
  `;
68
67
  }
@@ -74,11 +73,17 @@ function renderContentArea(data, handlers) {
74
73
  export function renderChatbotMain(data, handlers) {
75
74
  var _a;
76
75
  const isArtifactPanelOpen = data.enableArtifacts && ((_a = data.artifactPanel) === null || _a === void 0 ? void 0 : _a.isOpen);
76
+ const dnd = data.enableFileUpload ? handlers.fileUploadArea : undefined;
77
77
  return html `
78
78
  <div class="chatbot-container ${classMap({
79
79
  'chatbot-container--with-sidebar': data.enableThreads && data.isThreadSidebarOpen,
80
80
  'chatbot-container--with-artifact-panel': !!isArtifactPanelOpen
81
- })}" part="container">
81
+ })}" part="container"
82
+ @dragenter=${dnd === null || dnd === void 0 ? void 0 : dnd.onDragEnter}
83
+ @dragover=${dnd === null || dnd === void 0 ? void 0 : dnd.onDragOver}
84
+ @dragleave=${dnd === null || dnd === void 0 ? void 0 : dnd.onDragLeave}
85
+ @drop=${dnd === null || dnd === void 0 ? void 0 : dnd.onDrop}
86
+ >
82
87
 
83
88
  ${data.enableThreads && data.isThreadSidebarOpen && data.threadSidebar && handlers.threadSidebar
84
89
  ? renderThreadSidebar(data.threadSidebar, handlers.threadSidebar)
@@ -101,7 +106,7 @@ export function renderChatbotMain(data, handlers) {
101
106
  : ''}
102
107
 
103
108
  ${data.isDragging
104
- ? renderFileUploadArea({ isDragging: data.isDragging }, handlers.fileUploadArea)
109
+ ? renderFileUploadArea({ isDragging: data.isDragging, label: data.i18n.input.dropFilesHere })
105
110
  : ''}
106
111
 
107
112
  ${data.urlModal && handlers.urlModal
@@ -5,15 +5,14 @@
5
5
  */
6
6
  import { TemplateResult } from 'lit';
7
7
  export interface FileUploadAreaTemplateHandlers {
8
- onDrop: (e: DragEvent) => void;
8
+ onDragEnter: (e: DragEvent) => void;
9
9
  onDragOver: (e: DragEvent) => void;
10
- onDragLeave: () => void;
10
+ onDragLeave: (e: DragEvent) => void;
11
+ onDrop: (e: DragEvent) => void;
11
12
  }
12
13
  export interface FileUploadAreaTemplateData {
13
14
  isDragging: boolean;
15
+ label: string;
14
16
  }
15
- /**
16
- * Renders file upload drag-and-drop area
17
- */
18
- export declare function renderFileUploadArea(data: FileUploadAreaTemplateData, handlers: FileUploadAreaTemplateHandlers): TemplateResult;
17
+ export declare function renderFileUploadArea(data: FileUploadAreaTemplateData): TemplateResult;
19
18
  //# sourceMappingURL=file-upload-area.template.d.ts.map
@@ -4,23 +4,16 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import { html } from 'lit';
7
- import { msg } from '@lit/localize';
8
- /**
9
- * Renders file upload drag-and-drop area
10
- */
11
- export function renderFileUploadArea(data, handlers) {
7
+ export function renderFileUploadArea(data) {
12
8
  return html `
13
- <div
9
+ <div
14
10
  class="file-upload-area ${data.isDragging ? 'file-upload-area--dragging' : ''}"
15
11
  part="file-upload-area"
16
- @drop=${handlers.onDrop}
17
- @dragover=${handlers.onDragOver}
18
- @dragleave=${handlers.onDragLeave}
19
12
  >
20
13
  <div class="file-upload-area__content">
21
- <div class="file-upload-area__icon">📁</div>
14
+ <nr-icon name="upload" size="xlarge"></nr-icon>
22
15
  <div class="file-upload-area__text">
23
- ${msg('Drop files here to upload')}
16
+ ${data.label}
24
17
  </div>
25
18
  </div>
26
19
  </div>
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import { TemplateResult } from 'lit';
7
- import { ChatbotFile } from '../chatbot.types.js';
7
+ import { ChatbotFile, ChatbotI18n } from '../chatbot.types.js';
8
8
  import type { AudioRecordingState } from '../chatbot-audio.controller.js';
9
9
  import { DropdownItem } from '../../dropdown/dropdown.types.js';
10
10
  import { SelectOption } from '../../select/select.types.js';
@@ -41,6 +41,7 @@ export interface InputBoxTemplateData {
41
41
  showAudioButton: boolean;
42
42
  audioRecording: AudioRecordingState;
43
43
  audioMode: 'transcribe' | 'message';
44
+ i18n: ChatbotI18n;
44
45
  }
45
46
  /**
46
47
  * Renders the complete input box
@@ -6,13 +6,12 @@
6
6
  import { html, nothing } from 'lit';
7
7
  import { repeat } from 'lit/directives/repeat.js';
8
8
  import { styleMap } from 'lit/directives/style-map.js';
9
- import { msg } from '@lit/localize';
10
9
  /**
11
10
  * Renders thumbnail chips for uploaded files (image thumb for images,
12
11
  * extension badge for other file types). While a file is uploading, a
13
12
  * spinner overlay is shown on top of the thumbnail.
14
13
  */
15
- function renderContextTags(files, onRemove, onFileClick) {
14
+ function renderContextTags(files, onRemove, i18n, onFileClick) {
16
15
  const formatFileSize = (bytes) => {
17
16
  if (bytes === 0)
18
17
  return '0 Bytes';
@@ -63,15 +62,15 @@ function renderContextTags(files, onRemove, onFileClick) {
63
62
  </div>
64
63
  `}
65
64
  ${f.isUploading ? html `
66
- <div class="file-thumb__spinner" aria-label="${msg('Uploading')}">
65
+ <div class="file-thumb__spinner" aria-label="${i18n.input.uploadingLabel}">
67
66
  <span class="file-thumb__spinner-ring"></span>
68
67
  </div>
69
68
  ` : ''}
70
69
  <button
71
70
  type="button"
72
71
  class="file-thumb__remove"
73
- aria-label="${msg('Remove file')}"
74
- title="${msg('Remove file')}"
72
+ aria-label="${i18n.input.removeFileLabel}"
73
+ title="${i18n.input.removeFileLabel}"
75
74
  @click=${(e) => { e.stopPropagation(); onRemove(f.id); }}
76
75
  >
77
76
  <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round">
@@ -97,7 +96,7 @@ function renderContextTags(files, onRemove, onFileClick) {
97
96
  <div class="file-preview-name" title="${f.name}">${f.name}</div>
98
97
  <div class="file-preview-details">
99
98
  <span>${formatFileSize(f.size)}</span>
100
- ${f.isUploading ? html `<span> · ${msg('Uploading…')}</span>` : ''}
99
+ ${f.isUploading ? html `<span> · ${i18n.input.uploadingProgress}</span>` : ''}
101
100
  </div>
102
101
  </div>
103
102
  </div>
@@ -120,17 +119,17 @@ function renderFileUploadButton(data, handlers) {
120
119
  ?disabled=${data.disabled}
121
120
  @nr-dropdown-item-click=${handlers.onFileDropdownClick}
122
121
  >
123
- <nr-button
122
+ <nr-button
124
123
  slot="trigger"
125
124
  part="file-button"
126
125
  type="default"
127
126
  size="small"
128
- .icon=${["upload"]}
127
+ .icon=${["paperclip"]}
129
128
  ?disabled=${data.disabled}
130
- aria-label="${msg('Attach files')}"
131
- title="${msg('Attach files')}"
129
+ aria-label="${data.i18n.input.attachFilesAriaLabel}"
130
+ title="${data.i18n.input.attachFilesAriaLabel}"
132
131
  >
133
- Attach
132
+ ${data.i18n.input.attachButton}
134
133
  </nr-button>
135
134
  </nr-dropdown>
136
135
  `;
@@ -148,12 +147,12 @@ function renderModuleSelector(data, handlers) {
148
147
  size="small"
149
148
  ?disabled=${data.disabled}
150
149
  searchable
151
- search-placeholder="${msg('Search modules...')}"
150
+ search-placeholder="${data.i18n.modules.moduleSearchPlaceholder}"
152
151
  use-custom-selected-display
153
152
  part="module-select"
154
153
  class="module-select"
155
154
  @nr-change=${handlers.onModuleChange}
156
- aria-label="${msg('Select modules')}"
155
+ aria-label="${data.i18n.modules.moduleSelectAriaLabel}"
157
156
  >
158
157
  <span slot="selected-display">
159
158
  ${data.renderModuleDisplay()}
@@ -174,10 +173,10 @@ function renderSendButton(data, handlers) {
174
173
  .iconRight=${data.isQueryRunning ? 'square' : 'arrow-up'}
175
174
  @click=${data.isQueryRunning ? handlers.onStop : handlers.onSend}
176
175
  @keydown=${handlers.onSendKeydown}
177
- aria-label="${data.isQueryRunning ? msg('Stop query') : msg('Send message')}"
178
- title="${data.isQueryRunning ? msg('Stop query') : msg('Send message')}"
176
+ aria-label="${data.isQueryRunning ? data.i18n.send.stopQueryLabel : data.i18n.send.sendMessageLabel}"
177
+ title="${data.isQueryRunning ? data.i18n.send.stopQueryLabel : data.i18n.send.sendMessageLabel}"
179
178
  >
180
- ${data.isQueryRunning ? msg('Stop') : msg('Send')}
179
+ ${data.isQueryRunning ? data.i18n.send.stopButton : data.i18n.send.sendButton}
181
180
  </nr-button>
182
181
  `;
183
182
  }
@@ -190,7 +189,7 @@ function renderSendButton(data, handlers) {
190
189
  function renderRecordingBar(data, handlers) {
191
190
  const { duration, bars } = data.audioRecording;
192
191
  const isTranscribe = data.audioMode === 'transcribe';
193
- const sendTitle = isTranscribe ? msg('Convert to text') : msg('Send as voice message');
192
+ const sendTitle = isTranscribe ? data.i18n.audio.convertToTextLabel : data.i18n.audio.sendAsVoiceMessageLabel;
194
193
  const sendIcon = isTranscribe
195
194
  ? html `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
196
195
  <rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>
@@ -203,9 +202,9 @@ function renderRecordingBar(data, handlers) {
203
202
  <div class="audio-recording-bar">
204
203
  <button
205
204
  class="audio-rec-cancel"
206
- title="${msg('Cancel recording')}"
205
+ title="${data.i18n.audio.cancelRecordingLabel}"
207
206
  @click=${handlers.onAudioCancel}
208
- aria-label="${msg('Cancel recording')}"
207
+ aria-label="${data.i18n.audio.cancelRecordingLabel}"
209
208
  >
210
209
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
211
210
  <polyline points="3 6 5 6 21 6"/>
@@ -225,7 +224,7 @@ function renderRecordingBar(data, handlers) {
225
224
  </div>
226
225
 
227
226
  <span class="audio-rec-mode-label">
228
- ${isTranscribe ? msg('Speech to text') : msg('Voice message')}
227
+ ${isTranscribe ? data.i18n.audio.speechToTextLabel : data.i18n.audio.voiceMessageLabel}
229
228
  </span>
230
229
 
231
230
  <button
@@ -257,10 +256,10 @@ function renderActionButtons(data, handlers) {
257
256
  <!-- Speech-to-text: mic + keyboard indicator -->
258
257
  <button
259
258
  class="audio-mic-btn"
260
- title="${msg('Record speech to text')}"
259
+ title="${data.i18n.audio.recordSpeechLabel}"
261
260
  ?disabled=${data.disabled}
262
261
  @click=${() => { var _a; return (_a = handlers.onAudioStart) === null || _a === void 0 ? void 0 : _a.call(handlers, 'transcribe'); }}
263
- aria-label="${msg('Record speech to text')}"
262
+ aria-label="${data.i18n.audio.recordSpeechLabel}"
264
263
  >
265
264
  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
266
265
  <path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/>
@@ -275,10 +274,10 @@ function renderActionButtons(data, handlers) {
275
274
  <!-- Voice message: mic + waveform indicator -->
276
275
  <button
277
276
  class="audio-mic-btn"
278
- title="${msg('Send voice message')}"
277
+ title="${data.i18n.audio.sendVoiceMessageLabel}"
279
278
  ?disabled=${data.disabled}
280
279
  @click=${() => { var _a; return (_a = handlers.onAudioStart) === null || _a === void 0 ? void 0 : _a.call(handlers, 'message'); }}
281
- aria-label="${msg('Send voice message')}"
280
+ aria-label="${data.i18n.audio.sendVoiceMessageLabel}"
282
281
  >
283
282
  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
284
283
  <path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/>
@@ -316,7 +315,7 @@ export function renderInputBox(data, handlers) {
316
315
  <div class="input-container" part="input-container">
317
316
  <!-- Context tags -->
318
317
  ${data.uploadedFiles.length > 0
319
- ? renderContextTags(data.uploadedFiles, handlers.onFileRemove, handlers.onFileClick)
318
+ ? renderContextTags(data.uploadedFiles, handlers.onFileRemove, data.i18n, handlers.onFileClick)
320
319
  : nothing}
321
320
 
322
321
  <!-- Input area -->
@@ -327,7 +326,7 @@ export function renderInputBox(data, handlers) {
327
326
  contenteditable="true"
328
327
  role="textbox"
329
328
  aria-multiline="true"
330
- aria-label="${msg('Chat input')}"
329
+ aria-label="${data.i18n.input.chatInputAriaLabel}"
331
330
  data-placeholder="${data.placeholder}"
332
331
  @input=${handlers.onInput}
333
332
  @keydown=${handlers.onKeydown}
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import { TemplateResult, nothing } from 'lit';
7
- import { ChatbotMessage, ChatbotLoadingType } from '../chatbot.types.js';
7
+ import { ChatbotMessage, ChatbotLoadingType, ChatbotI18n } from '../chatbot.types.js';
8
8
  export interface MessageTemplateHandlers {
9
9
  onRetry: (message: ChatbotMessage) => void;
10
10
  onRetryKeydown: (e: KeyboardEvent) => void;
@@ -15,7 +15,7 @@ export interface MessageTemplateHandlers {
15
15
  /**
16
16
  * Renders a single message
17
17
  */
18
- export declare function renderMessage(message: ChatbotMessage, handlers: MessageTemplateHandlers): TemplateResult;
18
+ export declare function renderMessage(message: ChatbotMessage, handlers: MessageTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
19
19
  /**
20
20
  * Renders bot typing indicator
21
21
  */
@@ -23,9 +23,9 @@ export declare function renderBotTypingIndicator(isTyping: boolean, loadingIndic
23
23
  /**
24
24
  * Renders empty state
25
25
  */
26
- export declare function renderEmptyState(): TemplateResult;
26
+ export declare function renderEmptyState(i18n: ChatbotI18n): TemplateResult;
27
27
  /**
28
28
  * Renders messages container with all messages
29
29
  */
30
- export declare function renderMessages(messages: ChatbotMessage[], suggestions: TemplateResult | typeof nothing, typingIndicator: TemplateResult | typeof nothing, messageHandlers: MessageTemplateHandlers): TemplateResult;
30
+ export declare function renderMessages(messages: ChatbotMessage[], suggestions: TemplateResult | typeof nothing, typingIndicator: TemplateResult | typeof nothing, messageHandlers: MessageTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
31
31
  //# sourceMappingURL=message.template.d.ts.map
@@ -6,7 +6,6 @@
6
6
  import { html, nothing } from 'lit';
7
7
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
8
8
  import { classMap } from 'lit/directives/class-map.js';
9
- import { msg } from '@lit/localize';
10
9
  import { ChatbotLoadingType } from '../chatbot.types.js';
11
10
  import { formatTimestamp } from '../utils/format.js';
12
11
  /**
@@ -61,7 +60,7 @@ function getFileExtension(name, mimeType) {
61
60
  /**
62
61
  * Renders a single message
63
62
  */
64
- export function renderMessage(message, handlers) {
63
+ export function renderMessage(message, handlers, i18n) {
65
64
  var _a, _b, _c, _d, _e, _f, _g, _h;
66
65
  const isError = (_a = message.text) === null || _a === void 0 ? void 0 : _a.includes('[ERROR_START]');
67
66
  const messageClasses = {
@@ -84,7 +83,7 @@ export function renderMessage(message, handlers) {
84
83
  : unsafeHTML(((_h = (_g = message.text) === null || _g === void 0 ? void 0 : _g.trim()) !== null && _h !== void 0 ? _h : '').replaceAll('\n', '<br>'))}
85
84
  </div>
86
85
  ${message.files && message.files.length > 0 ? html `
87
- <div class="message__attachments" part="message-attachments" role="list" aria-label="${msg('Attached files')}">
86
+ <div class="message__attachments" part="message-attachments" role="list" aria-label="${i18n.messages.attachedFilesLabel}">
88
87
  ${message.files.map((f) => html `
89
88
  <nr-dropdown
90
89
  trigger="hover"
@@ -147,8 +146,8 @@ export function renderMessage(message, handlers) {
147
146
  class="message__copy"
148
147
  @click=${() => handlers.onCopy(message)}
149
148
  @keydown=${(e) => handlers.onCopyKeydown(e, message)}
150
- title="${msg('Copy message')}"
151
- aria-label="${msg('Copy message')}"
149
+ title="${i18n.messages.copyMessageLabel}"
150
+ aria-label="${i18n.messages.copyMessageLabel}"
152
151
  role="button"
153
152
  tabindex="0"
154
153
  ></nr-icon>
@@ -162,9 +161,9 @@ export function renderMessage(message, handlers) {
162
161
  part="retry-button"
163
162
  @click=${() => handlers.onRetry(message)}
164
163
  @keydown=${handlers.onRetryKeydown}
165
- aria-label="${msg('Retry message')}"
164
+ aria-label="${i18n.messages.retryMessageLabel}"
166
165
  >
167
- ${msg('Retry')}
166
+ ${i18n.messages.retryButton}
168
167
  </nr-button>`
169
168
  : nothing}
170
169
  </div>
@@ -197,12 +196,12 @@ export function renderBotTypingIndicator(isTyping, loadingIndicator, loadingText
197
196
  /**
198
197
  * Renders empty state
199
198
  */
200
- export function renderEmptyState() {
199
+ export function renderEmptyState(i18n) {
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">
205
- ${msg('Start a conversation')}
204
+ ${i18n.messages.startConversationLabel}
206
205
  </div>
207
206
  </slot>
208
207
  </div>
@@ -211,11 +210,11 @@ export function renderEmptyState() {
211
210
  /**
212
211
  * Renders messages container with all messages
213
212
  */
214
- export function renderMessages(messages, suggestions, typingIndicator, messageHandlers) {
213
+ export function renderMessages(messages, suggestions, typingIndicator, messageHandlers, i18n) {
215
214
  return html `
216
215
  <div class="messages" part="messages">
217
- ${messages.length === 0 ? renderEmptyState() : nothing}
218
- ${messages.map((message) => renderMessage(message, messageHandlers))}
216
+ ${messages.length === 0 ? renderEmptyState(i18n) : nothing}
217
+ ${messages.map((message) => renderMessage(message, messageHandlers, i18n))}
219
218
  ${suggestions}
220
219
  ${typingIndicator}
221
220
  </div>
@@ -4,17 +4,11 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import { TemplateResult, nothing } from 'lit';
7
- import { ChatbotSuggestion } from '../chatbot.types.js';
7
+ import { ChatbotSuggestion, ChatbotI18n } from '../chatbot.types.js';
8
8
  export interface SuggestionTemplateHandlers {
9
9
  onClick: (suggestion: ChatbotSuggestion) => void;
10
10
  onKeydown: (e: KeyboardEvent) => void;
11
11
  }
12
- /**
13
- * Renders a single suggestion
14
- */
15
- export declare function renderSuggestion(suggestion: ChatbotSuggestion, handlers: SuggestionTemplateHandlers): TemplateResult;
16
- /**
17
- * Renders suggestions container
18
- */
19
- export declare function renderSuggestions(_chatStarted: boolean, suggestions: ChatbotSuggestion[], handlers: SuggestionTemplateHandlers): TemplateResult | typeof nothing;
12
+ export declare function renderSuggestion(suggestion: ChatbotSuggestion, handlers: SuggestionTemplateHandlers, i18n: ChatbotI18n): TemplateResult;
13
+ export declare function renderSuggestions(_chatStarted: boolean, suggestions: ChatbotSuggestion[], handlers: SuggestionTemplateHandlers, i18n: ChatbotI18n): TemplateResult | typeof nothing;
20
14
  //# sourceMappingURL=suggestion.template.d.ts.map
@@ -5,34 +5,27 @@
5
5
  */
6
6
  import { html, nothing } from 'lit';
7
7
  import { classMap } from 'lit/directives/class-map.js';
8
- import { msg } from '@lit/localize';
9
- /**
10
- * Renders a single suggestion
11
- */
12
- export function renderSuggestion(suggestion, handlers) {
8
+ export function renderSuggestion(suggestion, handlers, i18n) {
13
9
  return html `
14
- <div
15
- class="suggestion ${classMap({ 'suggestion--disabled': suggestion.enabled === false })}"
10
+ <div
11
+ class="suggestion ${classMap({ 'suggestion--disabled': suggestion.enabled === false })}"
16
12
  part="suggestion"
17
13
  role="button"
18
14
  tabindex="0"
19
15
  @click=${() => handlers.onClick(suggestion)}
20
16
  @keydown=${handlers.onKeydown}
21
17
  data-id="${suggestion.id}"
22
- aria-label="${msg('Select suggestion: ')}${suggestion.text}"
18
+ aria-label="${i18n.messages.suggestionPrefix}${suggestion.text}"
23
19
  >
24
20
  ${suggestion.text}
25
21
  </div>
26
22
  `;
27
23
  }
28
- /**
29
- * Renders suggestions container
30
- */
31
- export function renderSuggestions(_chatStarted, suggestions, handlers) {
24
+ export function renderSuggestions(_chatStarted, suggestions, handlers, i18n) {
32
25
  return suggestions.length > 0
33
26
  ? html `
34
27
  <div class="suggestion-container" part="suggestions">
35
- ${suggestions.map((suggestion) => renderSuggestion(suggestion, handlers))}
28
+ ${suggestions.map((suggestion) => renderSuggestion(suggestion, handlers, i18n))}
36
29
  </div>
37
30
  `
38
31
  : nothing;
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import { TemplateResult } from 'lit';
7
- import { ChatbotThread } from '../chatbot.types.js';
7
+ import { ChatbotThread, ChatbotI18n } from '../chatbot.types.js';
8
8
  export interface ThreadSidebarTemplateHandlers {
9
9
  onCreateNew: () => void;
10
10
  onSelectThread: (threadId: string) => void;
@@ -16,6 +16,7 @@ export interface ThreadSidebarTemplateData {
16
16
  threads: ChatbotThread[];
17
17
  activeThreadId?: string;
18
18
  editingThreadId?: string;
19
+ i18n: ChatbotI18n;
19
20
  }
20
21
  /**
21
22
  * Renders thread sidebar
@@ -6,7 +6,6 @@
6
6
  import { html, nothing } from 'lit';
7
7
  import { repeat } from 'lit/directives/repeat.js';
8
8
  import { classMap } from 'lit/directives/class-map.js';
9
- import { msg } from '@lit/localize';
10
9
  import { formatTimestamp } from '../utils/format.js';
11
10
  function renderThreadItem(thread, data, handlers) {
12
11
  const lastMessage = thread.messages.length > 0
@@ -53,13 +52,13 @@ function renderThreadItem(thread, data, handlers) {
53
52
  }}
54
53
  />
55
54
  ` : html `
56
- <div class="thread-item__title">${thread.title || msg('New Chat')}</div>
55
+ <div class="thread-item__title">${thread.title || data.i18n.threads.newChatTitle}</div>
57
56
  `}
58
57
  <div class="thread-item__actions">
59
58
  ${handlers.onBookmarkThread && thread.bookmarked ? html `
60
59
  <button
61
60
  class="thread-item__action-btn thread-item__bookmark--active"
62
- title="${msg('Remove bookmark')}"
61
+ title="${data.i18n.threads.removeBookmarkLabel}"
63
62
  @click=${(e) => {
64
63
  e.stopPropagation();
65
64
  handlers.onBookmarkThread(thread.id);
@@ -94,17 +93,17 @@ function renderThreadItem(thread, data, handlers) {
94
93
  }
95
94
  }}
96
95
  .items=${[
97
- ...(handlers.onRenameThread ? [{ id: 'rename', label: msg('Rename') }] : []),
98
- ...(handlers.onBookmarkThread ? [{ id: 'bookmark', label: thread.bookmarked ? msg('Remove bookmark') : msg('Bookmark') }] : []),
99
- ...(handlers.onDeleteThread ? [{ id: 'delete', label: msg('Delete') }] : []),
96
+ ...(handlers.onRenameThread ? [{ id: 'rename', label: data.i18n.threads.renameLabel }] : []),
97
+ ...(handlers.onBookmarkThread ? [{ id: 'bookmark', label: thread.bookmarked ? data.i18n.threads.removeBookmarkLabel : data.i18n.threads.bookmarkLabel }] : []),
98
+ ...(handlers.onDeleteThread ? [{ id: 'delete', label: data.i18n.threads.deleteLabel }] : []),
100
99
  ]}
101
100
  >
102
101
  <button
103
102
  slot="trigger"
104
103
  class="thread-item__action-btn thread-item__menu"
105
- title="${msg('More options')}"
104
+ title="${data.i18n.threads.moreOptionsLabel}"
106
105
  part="thread-menu"
107
- aria-label="${msg('More options')}"
106
+ aria-label="${data.i18n.threads.moreOptionsLabel}"
108
107
  >
109
108
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="none"><circle cx="5" cy="12" r="1.8"/><circle cx="12" cy="12" r="1.8"/><circle cx="19" cy="12" r="1.8"/></svg>
110
109
  </button>
@@ -128,7 +127,7 @@ export function renderThreadSidebar(data, handlers) {
128
127
  return html `
129
128
  <div class="thread-sidebar" part="thread-sidebar">
130
129
  <div class="thread-sidebar__header">
131
- <h3>${msg('Conversations')}</h3>
130
+ <h3>${data.i18n.threads.conversationsTitle}</h3>
132
131
  </div>
133
132
 
134
133
  <div class="thread-list">
@@ -136,18 +135,18 @@ export function renderThreadSidebar(data, handlers) {
136
135
  <div class="thread-section" part="thread-section-bookmarks">
137
136
  <div class="thread-section__label">
138
137
  <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
139
- ${msg('Bookmarks')}
138
+ ${data.i18n.threads.bookmarksLabel}
140
139
  </div>
141
140
  ${repeat(bookmarkedThreads, t => t.id, t => renderThreadItem(t, data, handlers))}
142
141
  </div>
143
142
  ` : nothing}
144
143
  ${regularThreads.length > 0 || bookmarkedThreads.length === 0 ? html `
145
144
  ${bookmarkedThreads.length > 0 ? html `
146
- <div class="thread-section__label">${msg('All Conversations')}</div>
145
+ <div class="thread-section__label">${data.i18n.threads.allConversationsLabel}</div>
147
146
  ` : nothing}
148
147
  ${repeat(regularThreads, t => t.id, t => renderThreadItem(t, data, handlers))}
149
148
  ${regularThreads.length === 0 && bookmarkedThreads.length === 0 ? html `
150
- <p class="empty-msg">${msg('No conversations yet')}</p>
149
+ <p class="empty-msg">${data.i18n.threads.noConversationsLabel}</p>
151
150
  ` : nothing}
152
151
  ` : nothing}
153
152
  </div>
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import { TemplateResult } from 'lit';
7
+ import { ChatbotI18n } from '../chatbot.types.js';
7
8
  export interface UrlModalTemplateHandlers {
8
9
  onClose: () => void;
9
10
  onUrlInputChange: (e: Event) => void;
@@ -17,9 +18,7 @@ export interface UrlModalTemplateData {
17
18
  isLoading?: boolean;
18
19
  error?: string;
19
20
  selectedFileName?: string;
21
+ i18n: ChatbotI18n;
20
22
  }
21
- /**
22
- * Renders URL attachment modal
23
- */
24
23
  export declare function renderUrlModal(data: UrlModalTemplateData, handlers: UrlModalTemplateHandlers): TemplateResult;
25
24
  //# sourceMappingURL=url-modal.template.d.ts.map