@memori.ai/memori-react 8.8.5 → 8.9.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 (176) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +28 -0
  3. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +0 -1
  4. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
  5. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +0 -10
  6. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
  7. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js +0 -9
  8. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js.map +1 -1
  9. package/dist/components/Chat/Chat.css +31 -0
  10. package/dist/components/Chat/Chat.js +18 -4
  11. package/dist/components/Chat/Chat.js.map +1 -1
  12. package/dist/components/ChatBubble/ChatBubble.js +1 -2
  13. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  14. package/dist/components/ChatInputs/ChatInputs.css +23 -0
  15. package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
  16. package/dist/components/ChatInputs/ChatInputs.js +37 -21
  17. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  18. package/dist/components/ChatTextArea/ChatTextArea.css +31 -0
  19. package/dist/components/ChatTextArea/ChatTextArea.d.ts +1 -0
  20. package/dist/components/ChatTextArea/ChatTextArea.js +9 -2
  21. package/dist/components/ChatTextArea/ChatTextArea.js.map +1 -1
  22. package/dist/components/FilePreview/FilePreview.css +39 -0
  23. package/dist/components/Header/Header.js +3 -16
  24. package/dist/components/Header/Header.js.map +1 -1
  25. package/dist/components/MediaWidget/LinkItemWidget.js +1 -1
  26. package/dist/components/MediaWidget/LinkItemWidget.js.map +1 -1
  27. package/dist/components/MediaWidget/MediaItemWidget.js +5 -9
  28. package/dist/components/MediaWidget/MediaItemWidget.js.map +1 -1
  29. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +65 -51
  30. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  31. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.d.ts +5 -0
  32. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js +287 -0
  33. package/dist/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -0
  34. package/dist/components/MemoriWidget/MemoriWidget.d.ts +12 -0
  35. package/dist/components/MemoriWidget/MemoriWidget.js +12 -3
  36. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  37. package/dist/components/Snippet/Snippet.js +4 -3
  38. package/dist/components/Snippet/Snippet.js.map +1 -1
  39. package/dist/components/StartPanel/StartPanel.css +14 -0
  40. package/dist/components/StartPanel/StartPanel.js +2 -2
  41. package/dist/components/StartPanel/StartPanel.js.map +1 -1
  42. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +0 -21
  43. package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
  44. package/dist/components/VenueWidget/VenueWidget.js +0 -1
  45. package/dist/components/VenueWidget/VenueWidget.js.map +1 -1
  46. package/dist/components/layouts/HiddenChat.js +0 -15
  47. package/dist/components/layouts/HiddenChat.js.map +1 -1
  48. package/dist/components/layouts/chat.css +2 -2
  49. package/dist/context/visemeContext.js +0 -6
  50. package/dist/context/visemeContext.js.map +1 -1
  51. package/dist/helpers/constants.d.ts +11 -0
  52. package/dist/helpers/constants.js +24 -2
  53. package/dist/helpers/constants.js.map +1 -1
  54. package/dist/helpers/tts/useTTS.js +0 -3
  55. package/dist/helpers/tts/useTTS.js.map +1 -1
  56. package/dist/helpers/utils.d.ts +1 -0
  57. package/dist/helpers/utils.js +6 -1
  58. package/dist/helpers/utils.js.map +1 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/locales/de.json +2 -0
  61. package/dist/locales/en.json +2 -0
  62. package/dist/locales/es.json +2 -0
  63. package/dist/locales/fr.json +2 -0
  64. package/dist/locales/it.json +2 -0
  65. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +0 -1
  66. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
  67. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +0 -10
  68. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
  69. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js +0 -9
  70. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js.map +1 -1
  71. package/esm/components/Chat/Chat.css +31 -0
  72. package/esm/components/Chat/Chat.js +19 -5
  73. package/esm/components/Chat/Chat.js.map +1 -1
  74. package/esm/components/ChatBubble/ChatBubble.js +1 -2
  75. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  76. package/esm/components/ChatInputs/ChatInputs.css +23 -0
  77. package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
  78. package/esm/components/ChatInputs/ChatInputs.js +37 -21
  79. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  80. package/esm/components/ChatTextArea/ChatTextArea.css +31 -0
  81. package/esm/components/ChatTextArea/ChatTextArea.d.ts +1 -0
  82. package/esm/components/ChatTextArea/ChatTextArea.js +9 -2
  83. package/esm/components/ChatTextArea/ChatTextArea.js.map +1 -1
  84. package/esm/components/FilePreview/FilePreview.css +39 -0
  85. package/esm/components/Header/Header.js +3 -16
  86. package/esm/components/Header/Header.js.map +1 -1
  87. package/esm/components/MediaWidget/LinkItemWidget.js +1 -1
  88. package/esm/components/MediaWidget/LinkItemWidget.js.map +1 -1
  89. package/esm/components/MediaWidget/MediaItemWidget.js +5 -9
  90. package/esm/components/MediaWidget/MediaItemWidget.js.map +1 -1
  91. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +65 -51
  92. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  93. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.d.ts +5 -0
  94. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js +282 -0
  95. package/esm/components/MemoriArtifactSystem/utils/ArtifactAPI.js.map +1 -0
  96. package/esm/components/MemoriWidget/MemoriWidget.d.ts +12 -0
  97. package/esm/components/MemoriWidget/MemoriWidget.js +12 -3
  98. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  99. package/esm/components/Snippet/Snippet.js +4 -3
  100. package/esm/components/Snippet/Snippet.js.map +1 -1
  101. package/esm/components/StartPanel/StartPanel.css +14 -0
  102. package/esm/components/StartPanel/StartPanel.js +3 -3
  103. package/esm/components/StartPanel/StartPanel.js.map +1 -1
  104. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +0 -21
  105. package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
  106. package/esm/components/VenueWidget/VenueWidget.js +0 -1
  107. package/esm/components/VenueWidget/VenueWidget.js.map +1 -1
  108. package/esm/components/layouts/HiddenChat.js +0 -15
  109. package/esm/components/layouts/HiddenChat.js.map +1 -1
  110. package/esm/components/layouts/chat.css +2 -2
  111. package/esm/context/visemeContext.js +0 -6
  112. package/esm/context/visemeContext.js.map +1 -1
  113. package/esm/helpers/constants.d.ts +11 -0
  114. package/esm/helpers/constants.js +22 -1
  115. package/esm/helpers/constants.js.map +1 -1
  116. package/esm/helpers/tts/useTTS.js +0 -3
  117. package/esm/helpers/tts/useTTS.js.map +1 -1
  118. package/esm/helpers/utils.d.ts +1 -0
  119. package/esm/helpers/utils.js +4 -0
  120. package/esm/helpers/utils.js.map +1 -1
  121. package/esm/index.js.map +1 -1
  122. package/esm/locales/de.json +2 -0
  123. package/esm/locales/en.json +2 -0
  124. package/esm/locales/es.json +2 -0
  125. package/esm/locales/fr.json +2 -0
  126. package/esm/locales/it.json +2 -0
  127. package/package.json +1 -1
  128. package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +0 -1
  129. package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +0 -17
  130. package/src/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.ts +0 -20
  131. package/src/components/Chat/Chat.css +31 -0
  132. package/src/components/Chat/Chat.stories.tsx +503 -9
  133. package/src/components/Chat/Chat.tsx +23 -3
  134. package/src/components/Chat/__snapshots__/Chat.test.tsx.snap +73 -73
  135. package/src/components/ChatBubble/ChatBubble.tsx +1 -2
  136. package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +25 -25
  137. package/src/components/ChatInputs/ChatInputs.css +23 -0
  138. package/src/components/ChatInputs/ChatInputs.tsx +36 -14
  139. package/src/components/ChatTextArea/ChatTextArea.css +31 -0
  140. package/src/components/ChatTextArea/ChatTextArea.tsx +11 -1
  141. package/src/components/FilePreview/FilePreview.css +39 -0
  142. package/src/components/Header/Header.tsx +0 -13
  143. package/src/components/MediaWidget/LinkItemWidget.tsx +1 -1
  144. package/src/components/MediaWidget/MediaItemWidget.stories.tsx +33 -0
  145. package/src/components/MediaWidget/MediaItemWidget.tsx +7 -10
  146. package/src/components/MediaWidget/__snapshots__/LinkItemWidget.test.tsx.snap +4 -4
  147. package/src/components/MediaWidget/__snapshots__/MediaItemWidget.test.tsx.snap +6 -6
  148. package/src/components/MediaWidget/__snapshots__/MediaWidget.test.tsx.snap +2 -2
  149. package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +766 -2
  150. package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +103 -89
  151. package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.test.tsx +307 -0
  152. package/src/components/MemoriArtifactSystem/utils/ArtifactAPI.tsx +373 -0
  153. package/src/components/MemoriWidget/MemoriWidget.tsx +26 -4
  154. package/src/components/Snippet/Snippet.tsx +3 -2
  155. package/src/components/StartPanel/StartPanel.css +14 -0
  156. package/src/components/StartPanel/StartPanel.tsx +23 -10
  157. package/src/components/StartPanel/__snapshots__/StartPanel.test.tsx.snap +206 -84
  158. package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +0 -23
  159. package/src/components/VenueWidget/VenueWidget.tsx +0 -1
  160. package/src/components/layouts/HiddenChat.tsx +0 -16
  161. package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +204 -82
  162. package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +408 -164
  163. package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +204 -82
  164. package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +204 -82
  165. package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +204 -82
  166. package/src/components/layouts/chat.css +2 -2
  167. package/src/context/visemeContext.tsx +0 -7
  168. package/src/helpers/constants.ts +28 -3
  169. package/src/helpers/tts/useTTS.ts +0 -2
  170. package/src/helpers/utils.ts +5 -0
  171. package/src/index.tsx +0 -1
  172. package/src/locales/de.json +2 -0
  173. package/src/locales/en.json +2 -0
  174. package/src/locales/es.json +2 -0
  175. package/src/locales/fr.json +2 -0
  176. package/src/locales/it.json +2 -0
@@ -0,0 +1,373 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useArtifact } from '../context/ArtifactContext';
3
+ import type { ArtifactData } from '../types/artifact.types';
4
+ import { Message } from '@memori.ai/memori-api-client/dist/types';
5
+
6
+ // Queue for calls made before the component is ready
7
+ const pendingCalls: Array<{ method: string; args: any[] }> = [];
8
+ let isReady = false;
9
+
10
+ /**
11
+ * Initialize the MemoriArtifactAPI stub on window
12
+ * This should be called as early as possible to prevent "undefined" errors
13
+ */
14
+ export const initMemoriArtifactAPI = () => {
15
+ if (typeof window === 'undefined') return;
16
+
17
+ // Only initialize if not already present
18
+ if ((window as any).MemoriArtifactAPI) {
19
+ return;
20
+ }
21
+
22
+ (window as any).MemoriArtifactAPI = {
23
+ _isReady: () => isReady,
24
+ _setReady: (ready: boolean) => { isReady = ready; },
25
+ _getPendingCalls: () => pendingCalls,
26
+ _clearPendingCalls: () => { pendingCalls.length = 0; },
27
+
28
+ openArtifact: (artifact: ArtifactData) => {
29
+ if (!isReady) {
30
+ pendingCalls.push({ method: 'openArtifact', args: [artifact] });
31
+ }
32
+ },
33
+ createAndOpenArtifact: (content: string, mimeType?: string, title?: string) => {
34
+ if (!isReady) {
35
+ pendingCalls.push({ method: 'createAndOpenArtifact', args: [content, mimeType, title] });
36
+ }
37
+ },
38
+ createFromOutputElement: (outputElement: HTMLOutputElement) => {
39
+ if (!isReady) {
40
+ pendingCalls.push({ method: 'createFromOutputElement', args: [outputElement] });
41
+ return 'pending';
42
+ }
43
+ return 'not-ready';
44
+ },
45
+ closeArtifact: () => {
46
+ if (!isReady) {
47
+ pendingCalls.push({ method: 'closeArtifact', args: [] });
48
+ }
49
+ },
50
+ toggleFullscreen: () => {
51
+ if (!isReady) {
52
+ pendingCalls.push({ method: 'toggleFullscreen', args: [] });
53
+ }
54
+ },
55
+ getState: () => {
56
+ if (!isReady) {
57
+ return { currentArtifact: null, isDrawerOpen: false, isFullscreen: false };
58
+ }
59
+ return { currentArtifact: null, isDrawerOpen: false, isFullscreen: false };
60
+ },
61
+ };
62
+ };
63
+
64
+ // Initialize immediately when this module is loaded
65
+ initMemoriArtifactAPI();
66
+
67
+ /**
68
+ * Componente che espone le funzioni dell'Artifact System come API globale
69
+ * Questo permette di controllare gli artifacts da JavaScript vanilla esterno
70
+ */
71
+ export const ArtifactAPIBridge = ({
72
+ pushMessage,
73
+ }: {
74
+ pushMessage: (message: Message) => void;
75
+ }) => {
76
+ const { openArtifact, closeArtifact, toggleFullscreen, state } =
77
+ useArtifact();
78
+
79
+ const apiRef = useRef<any>(null);
80
+
81
+ useEffect(() => {
82
+ // Update API with actual implementations
83
+ if (typeof window !== 'undefined') {
84
+ const windowApi = (window as any).MemoriArtifactAPI;
85
+
86
+ // Store reference to actual implementations
87
+ apiRef.current = {
88
+ /**
89
+ * Apri un artifact esistente
90
+ * @param artifact - Oggetto ArtifactData completo
91
+ */
92
+ openArtifact: (artifact: ArtifactData) => {
93
+ openArtifact(artifact);
94
+ },
95
+
96
+ /**
97
+ * Crea e apri un artifact con parametri semplici
98
+ * @param content - Contenuto dell'artifact (HTML, markdown, ecc.)
99
+ * @param mimeType - Tipo MIME (default: 'html')
100
+ * @param title - Titolo da mostrare (default: auto-generato)
101
+ */
102
+ createAndOpenArtifact: (
103
+ content: string,
104
+ mimeType: string = 'html',
105
+ title?: string
106
+ ) => {
107
+ const autoTitle = title || getTitleFromMimeType(mimeType);
108
+
109
+ // Create the artifact object
110
+ const artifact: ArtifactData = {
111
+ id: `artifact-${Date.now()}-${Math.random()
112
+ .toString(36)
113
+ .substr(2, 9)}`,
114
+ content,
115
+ mimeType,
116
+ title: autoTitle,
117
+ timestamp: new Date(),
118
+ size: content.length,
119
+ };
120
+
121
+ // Create wrapped message text for artifact detection
122
+ // Don't reassign content parameter - use a new variable
123
+ let messageText = content;
124
+ if (!messageText.includes('<output class="memori-artifact">')) {
125
+ messageText = `<output class="memori-artifact" data-mimetype="${mimeType}" data-title="${autoTitle}">${content}</output>`;
126
+ }
127
+
128
+ //we have to push in the history the artifact as message
129
+ pushMessage({
130
+ text: messageText,
131
+ timestamp: new Date().toISOString(),
132
+ fromUser: false as const,
133
+ media: [],
134
+ initial: false,
135
+ translatedText: undefined,
136
+ questionAnswered: undefined,
137
+ generatedByAI: false,
138
+ contextVars: undefined,
139
+ date: undefined,
140
+ placeName: undefined,
141
+ placeLatitude: undefined,
142
+ placeLongitude: undefined,
143
+ placeUncertaintyKm: undefined,
144
+ });
145
+
146
+ // Open the artifact immediately
147
+ openArtifact(artifact);
148
+ },
149
+
150
+ /**
151
+ * Crea un artifact da un elemento <output> esistente nel DOM
152
+ * @param outputElement - Elemento DOM <output class="memori-artifact">
153
+ * @returns artifactId
154
+ */
155
+ createFromOutputElement: (outputElement: HTMLOutputElement) => {
156
+ const content = outputElement.innerHTML;
157
+ const mimeType =
158
+ outputElement.getAttribute('data-mimetype') || 'html';
159
+ const title =
160
+ outputElement.getAttribute('data-title') ||
161
+ getTitleFromMimeType(mimeType);
162
+
163
+ // Nascondi l'elemento originale
164
+ outputElement.style.display = 'none';
165
+ outputElement.setAttribute('data-memori-processed', 'true');
166
+
167
+ const artifact: ArtifactData = {
168
+ id: `artifact-${Date.now()}-${Math.random()
169
+ .toString(36)
170
+ .substr(2, 9)}`,
171
+ content,
172
+ mimeType,
173
+ title,
174
+ timestamp: new Date(),
175
+ size: content.length,
176
+ };
177
+
178
+ // Create wrapped message text for artifact detection
179
+ // Don't reassign content - use a new variable
180
+ let messageText = content;
181
+ if (!messageText.includes('<output class="memori-artifact">')) {
182
+ messageText = `<output class="memori-artifact" data-mimetype="${mimeType}" data-title="${title}">${content}</output>`;
183
+ }
184
+
185
+ pushMessage({
186
+ text: messageText,
187
+ timestamp: new Date().toISOString(),
188
+ fromUser: false as const,
189
+ media: [],
190
+ initial: false,
191
+ translatedText: undefined,
192
+ questionAnswered: undefined,
193
+ generatedByAI: false,
194
+ contextVars: undefined,
195
+ date: undefined,
196
+ placeName: undefined,
197
+ placeLatitude: undefined,
198
+ placeLongitude: undefined,
199
+ placeUncertaintyKm: undefined,
200
+ });
201
+
202
+ // Open the artifact immediately
203
+ openArtifact(artifact);
204
+
205
+ return artifact.id;
206
+ },
207
+
208
+ /**
209
+ * Chiudi l'artifact drawer corrente
210
+ */
211
+ closeArtifact: () => {
212
+ closeArtifact();
213
+ },
214
+
215
+ /**
216
+ * Toggle fullscreen dell'artifact drawer
217
+ */
218
+ toggleFullscreen: () => {
219
+ toggleFullscreen();
220
+ },
221
+
222
+ /**
223
+ * Ottieni lo stato corrente del sistema artifacts
224
+ */
225
+ getState: () => {
226
+ return {
227
+ currentArtifact: state.currentArtifact,
228
+ isDrawerOpen: state.isDrawerOpen,
229
+ isFullscreen: state.isFullscreen,
230
+ };
231
+ },
232
+ };
233
+
234
+ // Update window API methods to use the real implementations
235
+ if (windowApi) {
236
+ windowApi.openArtifact = apiRef.current.openArtifact;
237
+ windowApi.createAndOpenArtifact = apiRef.current.createAndOpenArtifact;
238
+ windowApi.createFromOutputElement = apiRef.current.createFromOutputElement;
239
+ windowApi.closeArtifact = apiRef.current.closeArtifact;
240
+ windowApi.toggleFullscreen = apiRef.current.toggleFullscreen;
241
+ windowApi.getState = apiRef.current.getState;
242
+
243
+ // Mark API as ready
244
+ windowApi._setReady(true);
245
+
246
+ // Process any pending calls that were queued before ready
247
+ const pendingCalls = windowApi._getPendingCalls();
248
+ if (pendingCalls.length > 0) {
249
+ pendingCalls.forEach((call: { method: string; args: any[] }) => {
250
+ try {
251
+ const method = (apiRef.current as any)[call.method];
252
+ if (method) {
253
+ method(...call.args);
254
+ }
255
+ } catch (error) {
256
+ // Swallow error, remove log
257
+ }
258
+ });
259
+ windowApi._clearPendingCalls();
260
+ }
261
+ } else {
262
+ // If windowApi doesn't exist yet, initialize it now
263
+ (window as any).MemoriArtifactAPI = {
264
+ ...apiRef.current,
265
+ _isReady: true,
266
+ _pendingCalls: [],
267
+ _setReady: (ready: boolean) => {
268
+ (window as any).MemoriArtifactAPI._isReady = ready;
269
+ },
270
+ _getPendingCalls: () => {
271
+ return (window as any).MemoriArtifactAPI._pendingCalls;
272
+ },
273
+ _clearPendingCalls: () => {
274
+ (window as any).MemoriArtifactAPI._pendingCalls = [];
275
+ },
276
+ };
277
+ }
278
+ }
279
+
280
+ return () => {
281
+ // Clean up the API on unmount
282
+ if (typeof window !== 'undefined') {
283
+ delete (window as any).MemoriArtifactAPI;
284
+ }
285
+ };
286
+ }, [openArtifact, closeArtifact, toggleFullscreen, state, pushMessage]);
287
+
288
+ return null;
289
+ };
290
+
291
+ // Helper functions
292
+ function getTitleFromMimeType(mimeType: string): string {
293
+ if (mimeType.includes('html')) return 'HTML Document';
294
+ if (mimeType.includes('markdown')) return 'Markdown Document';
295
+ if (mimeType.includes('javascript')) return 'JavaScript Code';
296
+ if (mimeType.includes('python')) return 'Python Code';
297
+ if (mimeType.includes('json')) return 'JSON Data';
298
+ if (mimeType.includes('css')) return 'CSS Stylesheet';
299
+ if (mimeType.includes('typescript')) return 'TypeScript Code';
300
+ if (mimeType.includes('xml')) return 'XML Document';
301
+ if (mimeType.includes('svg')) return 'SVG Image';
302
+ return 'Document';
303
+ }
304
+
305
+ function createArtifactHandler(
306
+ content: string,
307
+ mimeType: string,
308
+ title: string
309
+ ): HTMLDivElement {
310
+ const handler = document.createElement('div');
311
+ handler.className = 'memori-artifact-handler';
312
+ handler.style.cssText = `
313
+ display: flex;
314
+ align-items: center;
315
+ gap: 12px;
316
+ padding: 16px;
317
+ margin: 12px 0;
318
+ background: white;
319
+ border: 1px solid #e5e7eb;
320
+ border-radius: 12px;
321
+ cursor: pointer;
322
+ transition: all 0.2s ease;
323
+ `;
324
+
325
+ const icon = getIconForMimeType(mimeType);
326
+ const size = `${(content.length / 1024).toFixed(1)} KB`;
327
+
328
+ handler.innerHTML = `
329
+ <div style="font-size: 32px;">${icon}</div>
330
+ <div style="flex: 1;">
331
+ <div style="font-weight: 600; margin-bottom: 4px;">${escapeHtml(
332
+ title
333
+ )}</div>
334
+ <div style="font-size: 13px; color: #6b7280;">${mimeType} • ${size}</div>
335
+ </div>
336
+ <div>
337
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
338
+ <polyline points="9 18 15 12 9 6"></polyline>
339
+ </svg>
340
+ </div>
341
+ `;
342
+
343
+ handler.addEventListener('mouseenter', () => {
344
+ handler.style.background = '#faf5ff';
345
+ handler.style.borderColor = '#9333ea';
346
+ });
347
+
348
+ handler.addEventListener('mouseleave', () => {
349
+ handler.style.background = 'white';
350
+ handler.style.borderColor = '#e5e7eb';
351
+ });
352
+
353
+ return handler;
354
+ }
355
+
356
+ function getIconForMimeType(mimeType: string): string {
357
+ if (mimeType.includes('html')) return '🌐';
358
+ if (mimeType.includes('markdown')) return '📝';
359
+ if (mimeType.includes('javascript') || mimeType.includes('typescript'))
360
+ return '📜';
361
+ if (mimeType.includes('python')) return '🐍';
362
+ if (mimeType.includes('json')) return '📊';
363
+ if (mimeType.includes('css')) return '🎨';
364
+ if (mimeType.includes('xml')) return '📋';
365
+ if (mimeType.includes('svg')) return '🖼️';
366
+ return '📄';
367
+ }
368
+
369
+ function escapeHtml(text: string): string {
370
+ const div = document.createElement('div');
371
+ div.textContent = text;
372
+ return div.innerHTML;
373
+ }
@@ -17,6 +17,7 @@ import {
17
17
  ChatLog,
18
18
  } from '@memori.ai/memori-api-client/src/types';
19
19
  import { ArtifactData } from '../MemoriArtifactSystem/types/artifact.types';
20
+ import { ArtifactAPIBridge } from '../MemoriArtifactSystem/utils/ArtifactAPI';
20
21
 
21
22
  // Libraries
22
23
  import React, {
@@ -320,6 +321,18 @@ declare global {
320
321
  typeMessage: typeof typeMessage;
321
322
  typeMessageHidden: typeof typeMessageHidden;
322
323
  typeBatchMessages: typeof typeBatchMessages;
324
+ MemoriArtifactAPI?: {
325
+ openArtifact: (artifact: ArtifactData) => void;
326
+ createAndOpenArtifact: (content: string, mimeType?: string, title?: string) => void;
327
+ createFromOutputElement: (outputElement: HTMLOutputElement) => string;
328
+ closeArtifact: () => void;
329
+ toggleFullscreen: () => void;
330
+ getState: () => {
331
+ currentArtifact: ArtifactData | null;
332
+ isDrawerOpen: boolean;
333
+ isFullscreen: boolean
334
+ };
335
+ };
323
336
  }
324
337
  }
325
338
  window.getMemoriState = getMemoriState;
@@ -1725,7 +1738,6 @@ const MemoriWidget = ({
1725
1738
 
1726
1739
  if (isVisible && !isTabVisible) {
1727
1740
  // Tab became visible - start polling and send immediate date event
1728
- console.log('Tab is now active/visible - starting date polling');
1729
1741
  sendDateChangedEvent({
1730
1742
  sessionID: sessionId,
1731
1743
  state: currentDialogState,
@@ -1733,7 +1745,6 @@ const MemoriWidget = ({
1733
1745
  startDatePolling();
1734
1746
  } else if (!isVisible && isTabVisible) {
1735
1747
  // Tab became hidden - stop polling
1736
- console.log('Tab is now hidden - stopping date polling');
1737
1748
  stopDatePolling();
1738
1749
  }
1739
1750
 
@@ -1974,7 +1985,6 @@ const MemoriWidget = ({
1974
1985
  ]
1975
1986
  );
1976
1987
 
1977
-
1978
1988
  const focusChatInput = () => {
1979
1989
  let textarea = document.querySelector(
1980
1990
  '#chat-fieldset textarea'
@@ -2901,7 +2911,8 @@ const MemoriWidget = ({
2901
2911
  layout,
2902
2912
  memoriTyping,
2903
2913
  typingText,
2904
- showTypingText: showTypingText ?? integrationConfig?.showTypingText ?? false,
2914
+ showTypingText:
2915
+ showTypingText ?? integrationConfig?.showTypingText ?? false,
2905
2916
  history: showFullHistory ? history : history.slice(-2),
2906
2917
  authToken:
2907
2918
  loginToken ?? userToken ?? additionalInfo?.loginToken ?? authToken,
@@ -3045,6 +3056,17 @@ const MemoriWidget = ({
3045
3056
  loading={loading}
3046
3057
  />
3047
3058
 
3059
+ <ArtifactAPIBridge pushMessage={(message: Message) => {
3060
+ setHistory(history => {
3061
+ if (!history.length) return history;
3062
+ const lastMessage = history[history.length - 1];
3063
+ if (!lastMessage || lastMessage.fromUser) return history;
3064
+ // Create a new message object with the updated text
3065
+ const updatedLastMessage = { ...lastMessage, text: lastMessage.text + message.text };
3066
+ return [...history.slice(0, -1), updatedLastMessage];
3067
+ });
3068
+ }} />
3069
+
3048
3070
  <audio
3049
3071
  id="memori-audio"
3050
3072
  style={{ display: 'none' }}
@@ -5,6 +5,7 @@ import Copy from '../icons/Copy';
5
5
  import { prismSyntaxLangs } from '../../helpers/constants';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import cx from 'classnames';
8
+ import { stripDocumentAttachmentTags, stripOutputTags } from '../../helpers/utils';
8
9
 
9
10
  export interface Props {
10
11
  medium: Medium;
@@ -107,8 +108,8 @@ const Snippet = ({
107
108
  }
108
109
  >
109
110
  {medium.content?.length && medium.content.length > 200 && preview
110
- ? `${medium.content.slice(0, 200)}\n...`
111
- : `${medium.content}`}
111
+ ? `${stripDocumentAttachmentTags(medium.content)?.slice(0, 200)}\n...`
112
+ : stripDocumentAttachmentTags(medium.content ?? '')}
112
113
  </code>
113
114
  </pre>
114
115
 
@@ -155,6 +155,20 @@
155
155
  color: #000;
156
156
  }
157
157
 
158
+ .memori--language-chooser select optgroup {
159
+ background: #fff;
160
+ color: #666;
161
+ font-size: 0.9em;
162
+ font-style: normal;
163
+ font-weight: 700;
164
+ }
165
+
166
+ .memori--language-chooser select optgroup option {
167
+ padding-left: 0.5rem;
168
+ color: #000;
169
+ font-weight: 400;
170
+ }
171
+
158
172
  .memori--completions-enabled,
159
173
  .memori--board-of-experts,
160
174
  .memori--nsfw {
@@ -11,7 +11,7 @@ import Tooltip from '../ui/Tooltip';
11
11
  import { getTranslation } from '../../helpers/translations';
12
12
  import Button from '../ui/Button';
13
13
  import Translation from '../icons/Translation';
14
- import { chatLanguages } from '../../helpers/constants';
14
+ import { getGroupedChatLanguages } from '../../helpers/constants';
15
15
  import BlockedMemoriBadge from '../BlockedMemoriBadge/BlockedMemoriBadge';
16
16
  import AI from '../icons/AI';
17
17
  import Group from '../icons/Group';
@@ -259,15 +259,28 @@ const StartPanel: React.FC<Props> = ({
259
259
  setUserLang(e.target.value);
260
260
  }}
261
261
  >
262
- {chatLanguages.map(lang => (
263
- <option
264
- key={lang.value}
265
- value={lang.value}
266
- aria-label={lang.label}
267
- >
268
- {lang.label}
269
- </option>
270
- ))}
262
+ <optgroup label={t('popularLanguages') || 'Popular'}>
263
+ {getGroupedChatLanguages().popular.map(lang => (
264
+ <option
265
+ key={`popular-${lang.value}`}
266
+ value={lang.value}
267
+ aria-label={lang.label}
268
+ >
269
+ {lang.label}
270
+ </option>
271
+ ))}
272
+ </optgroup>
273
+ <optgroup label={t('allLanguages') || 'All Languages'}>
274
+ {getGroupedChatLanguages().all.map(lang => (
275
+ <option
276
+ key={`all-${lang.value}`}
277
+ value={lang.value}
278
+ aria-label={lang.label}
279
+ >
280
+ {lang.label}
281
+ </option>
282
+ ))}
283
+ </optgroup>
271
284
  </select>
272
285
  </div>
273
286
  )}