@memori.ai/memori-react 8.8.2 → 8.8.4

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 (43) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/components/Header/Header.d.ts +3 -0
  3. package/dist/components/Header/Header.js +31 -17
  4. package/dist/components/Header/Header.js.map +1 -1
  5. package/dist/components/MediaWidget/MediaItemWidget.css +216 -39
  6. package/dist/components/MediaWidget/MediaItemWidget.js +10 -0
  7. package/dist/components/MediaWidget/MediaItemWidget.js.map +1 -1
  8. package/dist/components/MemoriWidget/MemoriWidget.js +28 -45
  9. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  10. package/dist/components/Snippet/Snippet.css +89 -13
  11. package/dist/components/Snippet/Snippet.js +46 -27
  12. package/dist/components/Snippet/Snippet.js.map +1 -1
  13. package/dist/helpers/tts/useTTS.js +15 -5
  14. package/dist/helpers/tts/useTTS.js.map +1 -1
  15. package/esm/components/Header/Header.d.ts +3 -0
  16. package/esm/components/Header/Header.js +32 -18
  17. package/esm/components/Header/Header.js.map +1 -1
  18. package/esm/components/MediaWidget/MediaItemWidget.css +216 -39
  19. package/esm/components/MediaWidget/MediaItemWidget.js +10 -0
  20. package/esm/components/MediaWidget/MediaItemWidget.js.map +1 -1
  21. package/esm/components/MemoriWidget/MemoriWidget.js +28 -45
  22. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  23. package/esm/components/Snippet/Snippet.css +89 -13
  24. package/esm/components/Snippet/Snippet.js +46 -27
  25. package/esm/components/Snippet/Snippet.js.map +1 -1
  26. package/esm/helpers/tts/useTTS.js +15 -5
  27. package/esm/helpers/tts/useTTS.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/components/Header/Header.tsx +58 -30
  30. package/src/components/Header/__snapshots__/Header.test.tsx.snap +0 -20
  31. package/src/components/MediaWidget/MediaItemWidget.css +216 -39
  32. package/src/components/MediaWidget/MediaItemWidget.stories.tsx +145 -58
  33. package/src/components/MediaWidget/MediaItemWidget.tsx +24 -1
  34. package/src/components/MediaWidget/__snapshots__/MediaItemWidget.test.tsx.snap +76 -12
  35. package/src/components/MemoriWidget/MemoriWidget.tsx +52 -78
  36. package/src/components/Snippet/Snippet.css +89 -13
  37. package/src/components/Snippet/Snippet.tsx +60 -28
  38. package/src/components/Snippet/__snapshots__/Snippet.test.tsx.snap +9 -0
  39. package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +0 -20
  40. package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +0 -40
  41. package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +0 -20
  42. package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +0 -20
  43. package/src/helpers/tts/useTTS.ts +23 -8
@@ -113,73 +113,160 @@ JavaScript.args = {
113
113
  mediumID: '65ca4a6d-f20b-402e-9d79-5e470f247928',
114
114
  mimeType: 'text/javascript',
115
115
  title: 'JavaScript',
116
- content: `[
117
- {
118
- "name": "France",
119
- "capital": "Paris",
120
- "population": 67364357,
121
- "area": 551695,
122
- "currency": "Euro",
123
- "languages": [
124
- "French"
125
- ],
126
- "region": "Europe",
127
- "subregion": "Western Europe",
128
- "flag": "https://upload.wikimedia.org/wikipedia/commons/c/c3/Flag_of_France.svg"
129
- },
130
- {
131
- "name": "Germany",
132
- "capital": "Berlin",
133
- "population": 83240525,
134
- "area": 357022,
135
- "currency": "Euro",
136
- "languages": [
137
- "German"
138
- ],
139
- "region": "Europe",
140
- "subregion": "Western Europe",
141
- "flag": "https://upload.wikimedia.org/wikipedia/commons/b/ba/Flag_of_Germany.svg"
142
- },
143
- {
144
- "name": "United States",
145
- "capital": "Washington, D.C.",
146
- "population": 331893745,
147
- "area": 9833517,
148
- "currency": "USD",
149
- "languages": [
150
- "English"
151
- ],
152
- "region": "Americas",
153
- "subregion": "Northern America",
154
- "flag": "https://upload.wikimedia.org/wikipedia/commons/a/a4/Flag_of_the_United_States.svg"
155
- },
156
- {
157
- "name": "Belgium",
158
- "capital": "Brussels",
159
- "population": 11589623,
160
- "area": 30528,
161
- "currency": "Euro",
162
- "languages": [
163
- "Flemish",
164
- "French",
165
- "German"
166
- ],
167
- "region": "Europe",
168
- "subregion": "Western Europe",
169
- "flag": "https://upload.wikimedia.org/wikipedia/commons/6/65/Flag_of_Belgium.svg"
170
- ]`,
116
+ content: `{
117
+ "name": "John Doe",
118
+ "age": 43,
119
+ "city": "New York",
120
+ "items": [
121
+ {
122
+ "name": "Item 1",
123
+ "price": 10
124
+ },
125
+ {
126
+ "name": "Item 2",
127
+ "price": 20
128
+ }
129
+ ]
130
+ }
131
+ `,
132
+ },
133
+ ],
134
+ };
135
+
136
+ export const ShortCodeSnippets = Template.bind({});
137
+ ShortCodeSnippets.args = {
138
+ items: [
139
+ {
140
+ mediumID: 'short-js-1',
141
+ mimeType: 'text/javascript',
142
+ title: 'Short JS Function',
143
+ content: 'function greet() {\n return "Hello World!";\n}',
144
+ },
145
+ {
146
+ mediumID: 'short-python-1',
147
+ mimeType: 'text/python',
148
+ title: 'Python Print',
149
+ content: 'print("Hello, World!")',
150
+ },
151
+ {
152
+ mediumID: 'short-css-1',
153
+ mimeType: 'text/css',
154
+ title: 'CSS Rule',
155
+ content: 'body {\n background: #f0f0f0;\n color: #333;\n}',
156
+ },
157
+ ],
158
+ };
159
+
160
+ export const LongCodeSnippets = Template.bind({});
161
+ LongCodeSnippets.args = {
162
+ items: [
163
+ {
164
+ mediumID: 'long-js-1',
165
+ mimeType: 'text/javascript',
166
+ title: 'Long JavaScript Function',
167
+ content: `function processData(data) {
168
+ // Validate input
169
+ if (!data || typeof data !== 'object') {
170
+ throw new Error('Invalid data provided');
171
+ }
172
+
173
+ // Process each item
174
+ return data.map(item => {
175
+ const processed = {
176
+ id: item.id,
177
+ name: item.name.toUpperCase(),
178
+ value: item.value * 2,
179
+ timestamp: new Date().toISOString()
180
+ };
181
+
182
+ return processed;
183
+ });
184
+ }`,
185
+ },
186
+ {
187
+ mediumID: 'long-python-1',
188
+ mimeType: 'text/python',
189
+ title: 'Python Class',
190
+ content: `class DataProcessor:
191
+ def __init__(self, config):
192
+ self.config = config
193
+ self.cache = {}
194
+
195
+ def process(self, data):
196
+ if data in self.cache:
197
+ return self.cache[data]
198
+
199
+ result = self._transform(data)
200
+ self.cache[data] = result
201
+ return result
202
+
203
+ def _transform(self, data):
204
+ # Complex transformation logic
205
+ return data.upper()`,
206
+ },
207
+ ],
208
+ };
209
+
210
+ export const MixedSnippets = Template.bind({});
211
+ MixedSnippets.args = {
212
+ items: [
213
+ {
214
+ mediumID: 'short-1',
215
+ mimeType: 'text/javascript',
216
+ title: 'Quick Function',
217
+ content: 'const add = (a, b) => a + b;',
218
+ },
219
+ {
220
+ mediumID: 'long-1',
221
+ mimeType: 'text/javascript',
222
+ title: 'Complex Component',
223
+ content: `import React, { useState, useEffect } from 'react';
224
+
225
+ const MyComponent = ({ data, onUpdate }) => {
226
+ const [loading, setLoading] = useState(false);
227
+ const [error, setError] = useState(null);
228
+
229
+ useEffect(() => {
230
+ if (data) {
231
+ setLoading(true);
232
+ processData(data)
233
+ .then(result => {
234
+ onUpdate(result);
235
+ setLoading(false);
236
+ })
237
+ .catch(err => {
238
+ setError(err.message);
239
+ setLoading(false);
240
+ });
241
+ }
242
+ }, [data, onUpdate]);
243
+
244
+ if (loading) return <div>Loading...</div>;
245
+ if (error) return <div>Error: {error}</div>;
246
+
247
+ return <div>Data processed successfully</div>;
248
+ };
249
+
250
+ export default MyComponent;`,
251
+ },
252
+ {
253
+ mediumID: 'short-2',
254
+ mimeType: 'text/css',
255
+ title: 'Simple Style',
256
+ content: '.button {\n padding: 10px;\n background: blue;\n}',
171
257
  },
172
258
  ],
173
259
  };
174
260
 
175
- export const longTXT = Template.bind({});
176
- longTXT.args = {
261
+ export const LongTXT = Template.bind({});
262
+ LongTXT.args = {
177
263
  items: [
178
264
  {
179
265
  mediumID: '65ca4a6d-f20b-402e-9d79-5e470f247928',
180
266
  mimeType: 'text/plain',
181
267
  title: 'Long Text',
182
- content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.',
268
+ content:
269
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.',
183
270
  },
184
271
  ],
185
272
  };
@@ -187,7 +187,7 @@ export const RenderMediaItem = ({
187
187
  widthMd="90%"
188
188
  >
189
189
  <div className="memori-media-item-preview--content">
190
- <Snippet medium={item} showCopyButton={true} />
190
+ <Snippet medium={item} showCopyButton={true} />
191
191
  </div>
192
192
  </Modal>
193
193
  </>
@@ -368,6 +368,12 @@ export const RenderMediaItem = ({
368
368
  }
369
369
  };
370
370
 
371
+ // Helper function to count lines in content
372
+ const countLines = (content: string | undefined): number => {
373
+ if (!content) return 0;
374
+ return content.split('\n').length;
375
+ };
376
+
371
377
  export const RenderSnippetItem = ({
372
378
  item,
373
379
  sessionID: _sessionID,
@@ -383,6 +389,23 @@ export const RenderSnippetItem = ({
383
389
  apiURL?: string;
384
390
  onClick?: (mediumID: string) => void;
385
391
  }) => {
392
+ const lineCount = countLines(item.content);
393
+ const isShortSnippet = lineCount <= 5;
394
+
395
+ // For short snippets, show them directly without the clickable link
396
+ if (isShortSnippet) {
397
+ return (
398
+ <div className="memori-media-item--snippet-direct">
399
+ <Card className="memori-media-item--card memori-media-item--snippet">
400
+ <div className="memori-media-item--snippet-preview">
401
+ <Snippet showCopyButton={true} preview={false} medium={item} />
402
+ </div>
403
+ </Card>
404
+ </div>
405
+ );
406
+ }
407
+
408
+ // For longer snippets, show preview with click to open modal
386
409
  return (
387
410
  <>
388
411
  <a
@@ -25,13 +25,11 @@ exports[`renders MediaItemWidget unchanged with css snippet to show 1`] = `
25
25
  <div
26
26
  class="memori-media-item ease-out duration-500 delay-0 opacity-0 scale-95"
27
27
  >
28
- <a
29
- class="memori-media-item--link"
30
- href="#"
31
- title="Snippet"
28
+ <div
29
+ class="memori-media-item--snippet-direct"
32
30
  >
33
31
  <div
34
- class="memori-card memori-media-item--card memori-media-item--snippet memori-card--hoverable"
32
+ class="memori-card memori-media-item--card memori-media-item--snippet"
35
33
  >
36
34
  <div
37
35
  class="memori-spin"
@@ -57,12 +55,46 @@ exports[`renders MediaItemWidget unchanged with css snippet to show 1`] = `
57
55
  >
58
56
  <code
59
57
  class="language-scss"
58
+ data-language="scss"
60
59
  >
61
60
  body{
62
61
  background-color: #f00;
63
62
  }
64
63
  </code>
65
64
  </pre>
65
+ <button
66
+ class="memori-button memori-button--ghost memori-button--rounded memori-button--icon-only memori-snippet--copy-button"
67
+ title="copy"
68
+ >
69
+ <span
70
+ class="memori-button--icon"
71
+ >
72
+ <svg
73
+ aria-hidden="true"
74
+ fill="none"
75
+ focusable="false"
76
+ role="img"
77
+ stroke="currentColor"
78
+ stroke-linecap="round"
79
+ stroke-linejoin="round"
80
+ stroke-width="1.5"
81
+ viewBox="0 0 24 24"
82
+ xmlns="http://www.w3.org/2000/svg"
83
+ >
84
+ <rect
85
+ height="14"
86
+ rx="2"
87
+ ry="2"
88
+ width="14"
89
+ x="8"
90
+ y="8"
91
+ />
92
+ <path
93
+ d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
94
+ />
95
+ </svg>
96
+ </span>
97
+ </button>
66
98
  </div>
67
99
  <p
68
100
  class="memori-snippet--caption"
@@ -92,7 +124,7 @@ exports[`renders MediaItemWidget unchanged with css snippet to show 1`] = `
92
124
  </div>
93
125
  </div>
94
126
  </div>
95
- </a>
127
+ </div>
96
128
  </div>
97
129
  </div>
98
130
  </div>
@@ -280,13 +312,11 @@ exports[`renders MediaItemWidget unchanged with js snippet to show 1`] = `
280
312
  <div
281
313
  class="memori-media-item ease-out duration-500 delay-0 opacity-0 scale-95"
282
314
  >
283
- <a
284
- class="memori-media-item--link"
285
- href="#"
286
- title="Snippet"
315
+ <div
316
+ class="memori-media-item--snippet-direct"
287
317
  >
288
318
  <div
289
- class="memori-card memori-media-item--card memori-media-item--snippet memori-card--hoverable"
319
+ class="memori-card memori-media-item--card memori-media-item--snippet"
290
320
  >
291
321
  <div
292
322
  class="memori-spin"
@@ -312,10 +342,44 @@ exports[`renders MediaItemWidget unchanged with js snippet to show 1`] = `
312
342
  >
313
343
  <code
314
344
  class="language-jsx"
345
+ data-language="jsx"
315
346
  >
316
347
  console.log("Hello World!");
317
348
  </code>
318
349
  </pre>
350
+ <button
351
+ class="memori-button memori-button--ghost memori-button--rounded memori-button--icon-only memori-snippet--copy-button"
352
+ title="copy"
353
+ >
354
+ <span
355
+ class="memori-button--icon"
356
+ >
357
+ <svg
358
+ aria-hidden="true"
359
+ fill="none"
360
+ focusable="false"
361
+ role="img"
362
+ stroke="currentColor"
363
+ stroke-linecap="round"
364
+ stroke-linejoin="round"
365
+ stroke-width="1.5"
366
+ viewBox="0 0 24 24"
367
+ xmlns="http://www.w3.org/2000/svg"
368
+ >
369
+ <rect
370
+ height="14"
371
+ rx="2"
372
+ ry="2"
373
+ width="14"
374
+ x="8"
375
+ y="8"
376
+ />
377
+ <path
378
+ d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
379
+ />
380
+ </svg>
381
+ </span>
382
+ </button>
319
383
  </div>
320
384
  <p
321
385
  class="memori-snippet--caption"
@@ -345,7 +409,7 @@ exports[`renders MediaItemWidget unchanged with js snippet to show 1`] = `
345
409
  </div>
346
410
  </div>
347
411
  </div>
348
- </a>
412
+ </div>
349
413
  </div>
350
414
  </div>
351
415
  </div>
@@ -330,7 +330,6 @@ window.typeBatchMessages = typeBatchMessages;
330
330
  let audioContext: IAudioContext;
331
331
 
332
332
  let memoriPassword: string | undefined;
333
- let speakerMuted: boolean = false;
334
333
  let userToken: string | undefined;
335
334
 
336
335
  export interface LayoutProps {
@@ -510,19 +509,21 @@ const MemoriWidget = ({
510
509
  !user?.userID &&
511
510
  (showLogin || memori.requireLoginToken)
512
511
  ) {
513
- client.backend.pwlGetCurrentUser(loginToken).then(({ user, resultCode }) => {
514
- if (user && resultCode === 0) {
515
- setUser(user);
516
- setLocalConfig('loginToken', loginToken);
517
-
518
- if (!birthDate && user.birthDate) {
519
- setBirthDate(user.birthDate);
520
- setLocalConfig('birthDate', user.birthDate);
512
+ client.backend
513
+ .pwlGetCurrentUser(loginToken)
514
+ .then(({ user, resultCode }) => {
515
+ if (user && resultCode === 0) {
516
+ setUser(user);
517
+ setLocalConfig('loginToken', loginToken);
518
+
519
+ if (!birthDate && user.birthDate) {
520
+ setBirthDate(user.birthDate);
521
+ setLocalConfig('birthDate', user.birthDate);
522
+ }
523
+ } else {
524
+ removeLocalConfig('loginToken');
521
525
  }
522
- } else {
523
- removeLocalConfig('loginToken');
524
- }
525
- });
526
+ });
526
527
  }
527
528
  }, [loginToken, user?.userID]);
528
529
  const [showLoginDrawer, setShowLoginDrawer] = useState(false);
@@ -870,7 +871,7 @@ const MemoriWidget = ({
870
871
 
871
872
  translateDialogState(currentState, userLang, msg).then(ts => {
872
873
  let text = ts.translatedEmission || ts.emission;
873
- if (text && text.trim() && !speakerMuted) {
874
+ if (text && shouldPlayAudio(text)) {
874
875
  handleSpeak(text);
875
876
  }
876
877
  });
@@ -897,7 +898,7 @@ const MemoriWidget = ({
897
898
  tag: currentState.currentTag,
898
899
  memoryTags: currentState.memoryTags,
899
900
  });
900
- if (emission && emission.trim()) {
901
+ if (emission && shouldPlayAudio(emission)) {
901
902
  handleSpeak(emission);
902
903
  }
903
904
  }
@@ -1721,18 +1722,21 @@ const MemoriWidget = ({
1721
1722
 
1722
1723
  const handleVisibilityChange = () => {
1723
1724
  const isVisible = !document.hidden;
1724
-
1725
+
1725
1726
  if (isVisible && !isTabVisible) {
1726
1727
  // Tab became visible - start polling and send immediate date event
1727
1728
  console.log('Tab is now active/visible - starting date polling');
1728
- sendDateChangedEvent({ sessionID: sessionId, state: currentDialogState });
1729
+ sendDateChangedEvent({
1730
+ sessionID: sessionId,
1731
+ state: currentDialogState,
1732
+ });
1729
1733
  startDatePolling();
1730
1734
  } else if (!isVisible && isTabVisible) {
1731
1735
  // Tab became hidden - stop polling
1732
1736
  console.log('Tab is now hidden - stopping date polling');
1733
1737
  stopDatePolling();
1734
1738
  }
1735
-
1739
+
1736
1740
  isTabVisible = isVisible;
1737
1741
  };
1738
1742
 
@@ -1746,7 +1750,10 @@ const MemoriWidget = ({
1746
1750
 
1747
1751
  return () => {
1748
1752
  stopDatePolling();
1749
- document.removeEventListener('visibilitychange', handleVisibilityChange);
1753
+ document.removeEventListener(
1754
+ 'visibilitychange',
1755
+ handleVisibilityChange
1756
+ );
1750
1757
  };
1751
1758
  }
1752
1759
  }, [memori.needsDateTime, sessionId]);
@@ -1832,6 +1839,19 @@ const MemoriWidget = ({
1832
1839
  defaultSpeakerActive
1833
1840
  );
1834
1841
 
1842
+ // Helper function to check if audio should be played
1843
+ const shouldPlayAudio = (text?: string) => {
1844
+ const currentSpeakerMuted = getLocalConfig('muteSpeaker', false);
1845
+ console.log('[MemoriWidget] shouldPlayAudio', currentSpeakerMuted);
1846
+ return (
1847
+ text &&
1848
+ text.trim() &&
1849
+ !preview &&
1850
+ !currentSpeakerMuted &&
1851
+ defaultEnableAudio
1852
+ );
1853
+ };
1854
+
1835
1855
  // Create a single, centralized function to process and send messages
1836
1856
  const processSpeechAndSendMessage = (text: string) => {
1837
1857
  // console.log('processSpeechAndSendMessage', text);
@@ -1880,16 +1900,9 @@ const MemoriWidget = ({
1880
1900
  * Uses promise-based approach for better reliability
1881
1901
  */
1882
1902
  const handleSpeak = async (text: string) => {
1883
- if (
1884
- !text ||
1885
- !text.trim() ||
1886
- preview ||
1887
- speakerMuted ||
1888
- !defaultEnableAudio
1889
- ) {
1903
+ if (!shouldPlayAudio(text)) {
1890
1904
  const e = new CustomEvent('MemoriEndSpeak');
1891
1905
  document.dispatchEvent(e);
1892
-
1893
1906
  return Promise.resolve();
1894
1907
  }
1895
1908
 
@@ -1901,7 +1914,6 @@ const MemoriWidget = ({
1901
1914
  setHasUserTypedMessage(false);
1902
1915
 
1903
1916
  const processedText = sanitizeText(text);
1904
-
1905
1917
  return ttsSpeak(processedText);
1906
1918
  };
1907
1919
  /**
@@ -1918,7 +1930,6 @@ const MemoriWidget = ({
1918
1930
  try {
1919
1931
  // First ensure we have a valid dialog state
1920
1932
  if (!dialogState) {
1921
- console.warn('translateAndSpeak called with empty dialog state');
1922
1933
  return null;
1923
1934
  }
1924
1935
 
@@ -1934,20 +1945,13 @@ const MemoriWidget = ({
1934
1945
  const textToSpeak =
1935
1946
  translatedState.translatedEmission || translatedState.emission;
1936
1947
 
1937
- // Always set
1938
- // to true when we have a valid dialog state,
1948
+ // Always set hasUserActivatedSpeak to true when we have a valid dialog state,
1939
1949
  // regardless of audio settings, so the chat can start properly
1940
1950
  if (!hasUserActivatedSpeak) {
1941
1951
  setHasUserActivatedSpeak(true);
1942
1952
  }
1943
1953
 
1944
- if (
1945
- textToSpeak &&
1946
- textToSpeak.trim() &&
1947
- !skipEmission &&
1948
- !speakerMuted
1949
- ) {
1950
- // Note: now using the Promise-based speak function to ensure proper sequencing
1954
+ if (textToSpeak && !skipEmission && shouldPlayAudio(textToSpeak)) {
1951
1955
  await handleSpeak(textToSpeak);
1952
1956
  }
1953
1957
 
@@ -1966,9 +1970,11 @@ const MemoriWidget = ({
1966
1970
  handleSpeak,
1967
1971
  hasUserActivatedSpeak,
1968
1972
  setHasUserActivatedSpeak,
1973
+ speakerMuted,
1969
1974
  ]
1970
1975
  );
1971
1976
 
1977
+
1972
1978
  const focusChatInput = () => {
1973
1979
  let textarea = document.querySelector(
1974
1980
  '#chat-fieldset textarea'
@@ -2179,7 +2185,9 @@ const MemoriWidget = ({
2179
2185
  // to use in integrations or snippets
2180
2186
  const memoriTextEnteredHandler = useCallback(
2181
2187
  (e: MemoriTextEnteredEvent) => {
2182
- if (disableTextEnteredEvents) return;
2188
+ if (disableTextEnteredEvents) {
2189
+ return;
2190
+ }
2183
2191
 
2184
2192
  const {
2185
2193
  text,
@@ -2222,6 +2230,7 @@ const MemoriWidget = ({
2222
2230
  memoriTyping,
2223
2231
  userLang,
2224
2232
  disableTextEnteredEvents,
2233
+ speakerMuted,
2225
2234
  ]
2226
2235
  );
2227
2236
  useEffect(() => {
@@ -2776,8 +2785,7 @@ const MemoriWidget = ({
2776
2785
 
2777
2786
  const showFullHistory =
2778
2787
  showOnlyLastMessages === undefined
2779
- ? selectedLayout !== 'TOTEM' &&
2780
- selectedLayout !== 'WEBSITE_ASSISTANT'
2788
+ ? selectedLayout !== 'TOTEM' && selectedLayout !== 'WEBSITE_ASSISTANT'
2781
2789
  : !showOnlyLastMessages;
2782
2790
 
2783
2791
  const headerProps: HeaderProps = {
@@ -2790,49 +2798,16 @@ const MemoriWidget = ({
2790
2798
  history,
2791
2799
  showShare: showShare ?? integrationConfig?.showShare ?? true,
2792
2800
  position,
2801
+ layout: selectedLayout,
2802
+ additionalSettings,
2793
2803
  setShowPositionDrawer,
2794
2804
  setShowSettingsDrawer,
2795
2805
  setShowKnownFactsDrawer,
2796
2806
  setShowExpertsDrawer,
2797
2807
  enableAudio: defaultEnableAudio,
2798
2808
  speakerMuted: speakerMuted ?? false,
2799
- setSpeakerMuted: mute => {
2800
- // If audio is disabled, force mute and don't allow unmuting
2801
- if (!(enableAudio ?? integrationConfig?.enableAudio ?? true)) {
2802
- mute = true;
2803
- }
2804
-
2805
- // Use the toggleMute function from useTTS hook which properly manages state
2809
+ setSpeakerMuted: (mute: boolean) => {
2806
2810
  toggleMute(mute);
2807
-
2808
- // Update local config for persistence
2809
- setLocalConfig('muteSpeaker', !!mute);
2810
-
2811
- // Handle microphone mode changes
2812
- let microphoneMode = getLocalConfig<string>(
2813
- 'microphoneMode',
2814
- 'HOLD_TO_TALK'
2815
- );
2816
- if (microphoneMode === 'CONTINUOUS' && mute) {
2817
- setContinuousSpeech(false);
2818
- setLocalConfig('microphoneMode', 'HOLD_TO_TALK');
2819
- }
2820
-
2821
- // Stop audio if muting
2822
- if (mute) {
2823
- ttsStop();
2824
- } else {
2825
- // Initialize audio context when unmuting
2826
- try {
2827
- audioContext = new AudioContext();
2828
- let buffer = audioContext.createBuffer(1, 10000, 22050);
2829
- let source = audioContext.createBufferSource();
2830
- source.buffer = buffer;
2831
- source.connect(audioContext.destination);
2832
- } catch (error) {
2833
- console.warn('Failed to initialize audio context:', error);
2834
- }
2835
- }
2836
2811
  },
2837
2812
  setShowChatHistoryDrawer,
2838
2813
  showSettings: showSettings ?? integrationConfig?.showSettings ?? true,
@@ -3280,7 +3255,6 @@ const MemoriWidget = ({
3280
3255
  }}
3281
3256
  />
3282
3257
  )}
3283
-
3284
3258
  </div>
3285
3259
  );
3286
3260
  };