@memori.ai/memori-react 2.1.0 → 2.2.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 (106) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/components/Chat/Chat.d.ts +1 -0
  3. package/dist/components/Chat/Chat.js +2 -2
  4. package/dist/components/Chat/Chat.js.map +1 -1
  5. package/dist/components/ChatBubble/ChatBubble.js +1 -1
  6. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  7. package/dist/components/ChatInputs/ChatInputs.css +1 -41
  8. package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
  9. package/dist/components/ChatInputs/ChatInputs.js +9 -3
  10. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  11. package/dist/components/FeedbackButtons/FeedbackButtons.js +1 -1
  12. package/dist/components/FeedbackButtons/FeedbackButtons.js.map +1 -1
  13. package/dist/components/MemoriWidget/MemoriWidget.js +23 -13
  14. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  15. package/dist/components/MicrophoneButton/MicrophoneButton.css +101 -0
  16. package/dist/components/MicrophoneButton/MicrophoneButton.d.ts +9 -0
  17. package/dist/components/MicrophoneButton/MicrophoneButton.js +46 -0
  18. package/dist/components/MicrophoneButton/MicrophoneButton.js.map +1 -0
  19. package/dist/components/SettingsDrawer/SettingsDrawer.d.ts +3 -3
  20. package/dist/components/SettingsDrawer/SettingsDrawer.js +8 -6
  21. package/dist/components/SettingsDrawer/SettingsDrawer.js.map +1 -1
  22. package/dist/components/SettingsDrawer/SettingsDrawer.test.js +7 -7
  23. package/dist/components/SettingsDrawer/SettingsDrawer.test.js.map +1 -1
  24. package/dist/components/StartPanel/StartPanel.js +1 -1
  25. package/dist/components/StartPanel/StartPanel.js.map +1 -1
  26. package/dist/components/ui/Button.d.ts +5 -1
  27. package/dist/components/ui/Button.js +1 -1
  28. package/dist/components/ui/Button.js.map +1 -1
  29. package/dist/components/ui/Tooltip.css +33 -2
  30. package/dist/components/ui/Tooltip.d.ts +2 -1
  31. package/dist/components/ui/Tooltip.js +1 -2
  32. package/dist/components/ui/Tooltip.js.map +1 -1
  33. package/dist/components/ui/Tooltip.test.js +16 -0
  34. package/dist/components/ui/Tooltip.test.js.map +1 -1
  35. package/dist/helpers/configuration.js +1 -1
  36. package/dist/helpers/configuration.js.map +1 -1
  37. package/dist/locales/en.json +4 -0
  38. package/dist/locales/it.json +4 -0
  39. package/dist/styles.css +3 -2
  40. package/esm/components/Chat/Chat.d.ts +1 -0
  41. package/esm/components/Chat/Chat.js +2 -2
  42. package/esm/components/Chat/Chat.js.map +1 -1
  43. package/esm/components/ChatBubble/ChatBubble.js +1 -1
  44. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  45. package/esm/components/ChatInputs/ChatInputs.css +1 -41
  46. package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
  47. package/esm/components/ChatInputs/ChatInputs.js +9 -3
  48. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  49. package/esm/components/FeedbackButtons/FeedbackButtons.js +1 -1
  50. package/esm/components/FeedbackButtons/FeedbackButtons.js.map +1 -1
  51. package/esm/components/MemoriWidget/MemoriWidget.js +23 -13
  52. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  53. package/esm/components/MicrophoneButton/MicrophoneButton.css +101 -0
  54. package/esm/components/MicrophoneButton/MicrophoneButton.d.ts +9 -0
  55. package/esm/components/MicrophoneButton/MicrophoneButton.js +43 -0
  56. package/esm/components/MicrophoneButton/MicrophoneButton.js.map +1 -0
  57. package/esm/components/SettingsDrawer/SettingsDrawer.d.ts +3 -3
  58. package/esm/components/SettingsDrawer/SettingsDrawer.js +9 -7
  59. package/esm/components/SettingsDrawer/SettingsDrawer.js.map +1 -1
  60. package/esm/components/SettingsDrawer/SettingsDrawer.test.js +7 -7
  61. package/esm/components/SettingsDrawer/SettingsDrawer.test.js.map +1 -1
  62. package/esm/components/StartPanel/StartPanel.js +1 -1
  63. package/esm/components/StartPanel/StartPanel.js.map +1 -1
  64. package/esm/components/ui/Button.d.ts +5 -1
  65. package/esm/components/ui/Button.js +1 -1
  66. package/esm/components/ui/Button.js.map +1 -1
  67. package/esm/components/ui/Tooltip.css +33 -2
  68. package/esm/components/ui/Tooltip.d.ts +2 -1
  69. package/esm/components/ui/Tooltip.js +1 -2
  70. package/esm/components/ui/Tooltip.js.map +1 -1
  71. package/esm/components/ui/Tooltip.test.js +16 -0
  72. package/esm/components/ui/Tooltip.test.js.map +1 -1
  73. package/esm/helpers/configuration.js +1 -1
  74. package/esm/helpers/configuration.js.map +1 -1
  75. package/esm/locales/en.json +4 -0
  76. package/esm/locales/it.json +4 -0
  77. package/esm/styles.css +3 -2
  78. package/package.json +1 -1
  79. package/src/components/BlockedMemoriBadge/__snapshots__/BlockedMemoriBadge.test.tsx.snap +4 -4
  80. package/src/components/Chat/Chat.tsx +3 -0
  81. package/src/components/ChatBubble/ChatBubble.tsx +1 -1
  82. package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +1 -1
  83. package/src/components/ChatInputs/ChatInputs.css +1 -41
  84. package/src/components/ChatInputs/ChatInputs.stories.tsx +50 -3
  85. package/src/components/ChatInputs/ChatInputs.tsx +20 -3
  86. package/src/components/ChatInputs/__snapshots__/ChatInputs.test.tsx.snap +160 -85
  87. package/src/components/FeedbackButtons/FeedbackButtons.tsx +1 -1
  88. package/src/components/Header/Header.stories.tsx +3 -0
  89. package/src/components/MemoriWidget/MemoriWidget.tsx +29 -12
  90. package/src/components/MicrophoneButton/MicrophoneButton.css +101 -0
  91. package/src/components/MicrophoneButton/MicrophoneButton.stories.tsx +49 -0
  92. package/src/components/MicrophoneButton/MicrophoneButton.tsx +95 -0
  93. package/src/components/SettingsDrawer/SettingsDrawer.stories.tsx +6 -4
  94. package/src/components/SettingsDrawer/SettingsDrawer.test.tsx +14 -14
  95. package/src/components/SettingsDrawer/SettingsDrawer.tsx +57 -25
  96. package/src/components/StartPanel/StartPanel.tsx +3 -3
  97. package/src/components/ui/Button.tsx +21 -1
  98. package/src/components/ui/Tooltip.css +33 -2
  99. package/src/components/ui/Tooltip.stories.tsx +40 -3
  100. package/src/components/ui/Tooltip.test.tsx +52 -0
  101. package/src/components/ui/Tooltip.tsx +12 -7
  102. package/src/components/ui/__snapshots__/Tooltip.test.tsx.snap +80 -4
  103. package/src/helpers/configuration.ts +1 -1
  104. package/src/locales/en.json +4 -0
  105. package/src/locales/it.json +4 -0
  106. package/src/styles.css +3 -2
@@ -1,12 +1,13 @@
1
- import React from 'react';
1
+ import React, { useState, useEffect, useRef } from 'react';
2
2
  import { DialogState } from '@memori.ai/memori-api-client/dist/types';
3
3
  import UploadMenu from '../UploadMenu/UploadMenu';
4
4
  import SendOnEnterMenu from '../SendOnEnterMenu/SendOnEnterMenu';
5
5
  import ChatTextArea from '../ChatTextArea/ChatTextArea';
6
6
  import Button from '../ui/Button';
7
7
  import { useTranslation } from 'react-i18next';
8
- import cx from 'classnames';
9
8
  import Send from '../icons/Send';
9
+ import MicrophoneButton from '../MicrophoneButton/MicrophoneButton';
10
+ import cx from 'classnames';
10
11
  import Microphone from '../icons/Microphone';
11
12
 
12
13
  export interface Props {
@@ -28,6 +29,7 @@ export interface Props {
28
29
  startListening: () => void;
29
30
  stopListening: () => void;
30
31
  showMicrophone?: boolean;
32
+ microphoneMode?: 'CONTINUOUS' | 'HOLD_TO_TALK';
31
33
  authToken?: string;
32
34
  }
33
35
 
@@ -45,6 +47,7 @@ const ChatInputs: React.FC<Props> = ({
45
47
  onTextareaBlur,
46
48
  onTextareaPressEnter,
47
49
  showMicrophone = false,
50
+ microphoneMode = 'HOLD_TO_TALK',
48
51
  listening = false,
49
52
  stopAudio,
50
53
  startListening,
@@ -94,7 +97,21 @@ const ChatInputs: React.FC<Props> = ({
94
97
  title={t('send') || 'Send'}
95
98
  icon={<Send />}
96
99
  />
97
- {showMicrophone && (
100
+ {showMicrophone && microphoneMode === 'HOLD_TO_TALK' && (
101
+ <MicrophoneButton
102
+ listening={listening}
103
+ startListening={startListening}
104
+ stopListening={() => {
105
+ stopListening();
106
+
107
+ if (!!userMessage?.length) {
108
+ sendMessage(userMessage);
109
+ }
110
+ }}
111
+ stopAudio={stopAudio}
112
+ />
113
+ )}
114
+ {showMicrophone && microphoneMode === 'CONTINUOUS' && (
98
115
  <Button
99
116
  primary
100
117
  className={cx('memori-chat-inputs--mic', {
@@ -88,26 +88,41 @@ exports[`renders ChatInputs disabled unchanged 1`] = `
88
88
  </svg>
89
89
  </span>
90
90
  </button>
91
- <button
92
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
93
- title="write_and_speak.micButtonPopover"
91
+ <div
92
+ class="memori-tooltip memori-tooltip--align-topLeft memori-mic-btn-tooltip"
94
93
  >
95
- <span
96
- class="memori-button--icon"
94
+ <div
95
+ class="memori-tooltip--content"
97
96
  >
98
- <svg
99
- aria-hidden="true"
100
- focusable="false"
101
- role="img"
102
- viewBox="0 0 1024 1024"
103
- xmlns="http://www.w3.org/2000/svg"
97
+ <span>
98
+ write_and_speak.pressAndHoldToSpeak
99
+ </span>
100
+ </div>
101
+ <div
102
+ class="memori-tooltip--trigger"
103
+ >
104
+ <button
105
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
106
+ title="write_and_speak.micButtonPopover"
104
107
  >
105
- <path
106
- d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
107
- />
108
- </svg>
109
- </span>
110
- </button>
108
+ <span
109
+ class="memori-button--icon"
110
+ >
111
+ <svg
112
+ aria-hidden="true"
113
+ focusable="false"
114
+ role="img"
115
+ viewBox="0 0 1024 1024"
116
+ xmlns="http://www.w3.org/2000/svg"
117
+ >
118
+ <path
119
+ d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
120
+ />
121
+ </svg>
122
+ </span>
123
+ </button>
124
+ </div>
125
+ </div>
111
126
  </fieldset>
112
127
  </div>
113
128
  `;
@@ -198,26 +213,41 @@ exports[`renders ChatInputs listening unchanged 1`] = `
198
213
  </svg>
199
214
  </span>
200
215
  </button>
201
- <button
202
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic memori-chat-inputs--mic--listening"
203
- title="write_and_speak.micButtonPopoverListening"
216
+ <div
217
+ class="memori-tooltip memori-tooltip--align-topLeft memori-mic-btn-tooltip"
204
218
  >
205
- <span
206
- class="memori-button--icon"
219
+ <div
220
+ class="memori-tooltip--content"
207
221
  >
208
- <svg
209
- aria-hidden="true"
210
- focusable="false"
211
- role="img"
212
- viewBox="0 0 1024 1024"
213
- xmlns="http://www.w3.org/2000/svg"
222
+ <span>
223
+ write_and_speak.pressAndHoldToSpeak
224
+ </span>
225
+ </div>
226
+ <div
227
+ class="memori-tooltip--trigger"
228
+ >
229
+ <button
230
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic memori-chat-inputs--mic--listening"
231
+ title="write_and_speak.micButtonPopoverListening"
214
232
  >
215
- <path
216
- d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
217
- />
218
- </svg>
219
- </span>
220
- </button>
233
+ <span
234
+ class="memori-button--icon"
235
+ >
236
+ <svg
237
+ aria-hidden="true"
238
+ focusable="false"
239
+ role="img"
240
+ viewBox="0 0 1024 1024"
241
+ xmlns="http://www.w3.org/2000/svg"
242
+ >
243
+ <path
244
+ d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
245
+ />
246
+ </svg>
247
+ </span>
248
+ </button>
249
+ </div>
250
+ </div>
221
251
  </fieldset>
222
252
  </div>
223
253
  `;
@@ -337,26 +367,41 @@ exports[`renders ChatInputs on instruct unchanged 1`] = `
337
367
  </svg>
338
368
  </span>
339
369
  </button>
340
- <button
341
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
342
- title="write_and_speak.micButtonPopover"
370
+ <div
371
+ class="memori-tooltip memori-tooltip--align-topLeft memori-mic-btn-tooltip"
343
372
  >
344
- <span
345
- class="memori-button--icon"
373
+ <div
374
+ class="memori-tooltip--content"
346
375
  >
347
- <svg
348
- aria-hidden="true"
349
- focusable="false"
350
- role="img"
351
- viewBox="0 0 1024 1024"
352
- xmlns="http://www.w3.org/2000/svg"
376
+ <span>
377
+ write_and_speak.pressAndHoldToSpeak
378
+ </span>
379
+ </div>
380
+ <div
381
+ class="memori-tooltip--trigger"
382
+ >
383
+ <button
384
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
385
+ title="write_and_speak.micButtonPopover"
353
386
  >
354
- <path
355
- d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
356
- />
357
- </svg>
358
- </span>
359
- </button>
387
+ <span
388
+ class="memori-button--icon"
389
+ >
390
+ <svg
391
+ aria-hidden="true"
392
+ focusable="false"
393
+ role="img"
394
+ viewBox="0 0 1024 1024"
395
+ xmlns="http://www.w3.org/2000/svg"
396
+ >
397
+ <path
398
+ d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
399
+ />
400
+ </svg>
401
+ </span>
402
+ </button>
403
+ </div>
404
+ </div>
360
405
  </fieldset>
361
406
  </div>
362
407
  `;
@@ -446,26 +491,41 @@ exports[`renders ChatInputs unchanged 1`] = `
446
491
  </svg>
447
492
  </span>
448
493
  </button>
449
- <button
450
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
451
- title="write_and_speak.micButtonPopover"
494
+ <div
495
+ class="memori-tooltip memori-tooltip--align-topLeft memori-mic-btn-tooltip"
452
496
  >
453
- <span
454
- class="memori-button--icon"
497
+ <div
498
+ class="memori-tooltip--content"
455
499
  >
456
- <svg
457
- aria-hidden="true"
458
- focusable="false"
459
- role="img"
460
- viewBox="0 0 1024 1024"
461
- xmlns="http://www.w3.org/2000/svg"
500
+ <span>
501
+ write_and_speak.pressAndHoldToSpeak
502
+ </span>
503
+ </div>
504
+ <div
505
+ class="memori-tooltip--trigger"
506
+ >
507
+ <button
508
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
509
+ title="write_and_speak.micButtonPopover"
462
510
  >
463
- <path
464
- d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
465
- />
466
- </svg>
467
- </span>
468
- </button>
511
+ <span
512
+ class="memori-button--icon"
513
+ >
514
+ <svg
515
+ aria-hidden="true"
516
+ focusable="false"
517
+ role="img"
518
+ viewBox="0 0 1024 1024"
519
+ xmlns="http://www.w3.org/2000/svg"
520
+ >
521
+ <path
522
+ d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
523
+ />
524
+ </svg>
525
+ </span>
526
+ </button>
527
+ </div>
528
+ </div>
469
529
  </fieldset>
470
530
  </div>
471
531
  `;
@@ -556,26 +616,41 @@ exports[`renders ChatInputs with user message unchanged 1`] = `
556
616
  </svg>
557
617
  </span>
558
618
  </button>
559
- <button
560
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
561
- title="write_and_speak.micButtonPopover"
619
+ <div
620
+ class="memori-tooltip memori-tooltip--align-topLeft memori-mic-btn-tooltip"
562
621
  >
563
- <span
564
- class="memori-button--icon"
622
+ <div
623
+ class="memori-tooltip--content"
565
624
  >
566
- <svg
567
- aria-hidden="true"
568
- focusable="false"
569
- role="img"
570
- viewBox="0 0 1024 1024"
571
- xmlns="http://www.w3.org/2000/svg"
625
+ <span>
626
+ write_and_speak.pressAndHoldToSpeak
627
+ </span>
628
+ </div>
629
+ <div
630
+ class="memori-tooltip--trigger"
631
+ >
632
+ <button
633
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-chat-inputs--mic"
634
+ title="write_and_speak.micButtonPopover"
572
635
  >
573
- <path
574
- d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
575
- />
576
- </svg>
577
- </span>
578
- </button>
636
+ <span
637
+ class="memori-button--icon"
638
+ >
639
+ <svg
640
+ aria-hidden="true"
641
+ focusable="false"
642
+ role="img"
643
+ viewBox="0 0 1024 1024"
644
+ xmlns="http://www.w3.org/2000/svg"
645
+ >
646
+ <path
647
+ d="M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"
648
+ />
649
+ </svg>
650
+ </span>
651
+ </button>
652
+ </div>
653
+ </div>
579
654
  </fieldset>
580
655
  </div>
581
656
  `;
@@ -122,7 +122,7 @@ const FeedbackButtons = ({
122
122
  </Transition>
123
123
  </Menu>
124
124
  ) : (
125
- <Tooltip alignLeft content="Feedback">
125
+ <Tooltip align="left" content="Feedback">
126
126
  <Button
127
127
  title="Feedback"
128
128
  onClick={() => {
@@ -46,6 +46,9 @@ const Template: Story<Props> = args => {
46
46
  continuousSpeechTimeout={continuousSpeechTimeout}
47
47
  setContinuousSpeech={setContinuousSpeech}
48
48
  setContinuousSpeechTimeout={setContinuousSpeechTimeout}
49
+ setControlsPosition={() => {}}
50
+ controlsPosition="bottom"
51
+ setHideEmissions={() => {}}
49
52
  />
50
53
  </>
51
54
  );
@@ -251,18 +251,19 @@ const MemoriWidget = ({
251
251
  ?.find(c => c.memoriConfigID === memori.memoriConfigurationID)
252
252
  ?.culture?.split('-')?.[0]
253
253
  ?.toUpperCase();
254
- // eslint-disable-next-line
254
+ const integrationConfig = integration?.customData
255
+ ? JSON.parse(integration.customData)
256
+ : null;
257
+ const isMultilanguageEnabled = !!integrationConfig?.multilanguage;
255
258
  const [userLang, setUserLang] = useState(
256
- memoriLang ??
259
+ integrationConfig?.lang ??
260
+ memoriLang ??
257
261
  memori?.culture?.split('-')?.[0] ??
258
262
  language ??
263
+ integrationConfig?.uiLang ??
259
264
  i18n.language ??
260
265
  'IT'
261
266
  );
262
- const integrationConfig = integration?.customData
263
- ? JSON.parse(integration.customData)
264
- : null;
265
- const isMultilanguageEnabled = !!integrationConfig?.multilanguage;
266
267
 
267
268
  const [loading, setLoading] = useState(false);
268
269
  const [memoriTyping, setMemoriTyping] = useState(false);
@@ -275,7 +276,7 @@ const MemoriWidget = ({
275
276
  const [showPositionDrawer, setShowPositionDrawer] = useState(false);
276
277
  const [showSettingsDrawer, setShowSettingsDrawer] = useState(false);
277
278
  const [muteSpeaker, setMuteSpeaker] = useState(false);
278
- const [continuousSpeech, setContinuousSpeech] = useState(true);
279
+ const [continuousSpeech, setContinuousSpeech] = useState(false);
279
280
  const [continuousSpeechTimeout, setContinuousSpeechTimeout] = useState(2);
280
281
  const [isPlayingAudio, setIsPlayingAudio] = useState(false);
281
282
  const [controlsPosition, setControlsPosition] = useState<'center' | 'bottom'>(
@@ -289,9 +290,16 @@ const MemoriWidget = ({
289
290
 
290
291
  useEffect(() => {
291
292
  let defaultControlsPosition: 'center' | 'bottom' = 'bottom';
292
- if (window.innerWidth < 768) {
293
+ let microphoneMode = getLocalConfig<string>(
294
+ 'microphoneMode',
295
+ 'HOLD_TO_TALK'
296
+ );
297
+
298
+ if (window.innerWidth <= 768) {
293
299
  // on mobile, default position is bottom
294
300
  defaultControlsPosition = 'bottom';
301
+ // on mobile, keep only HOLD_TO_TALK mode
302
+ microphoneMode = 'HOLD_TO_TALK';
295
303
  } else if (
296
304
  window.matchMedia('(orientation: portrait)').matches ||
297
305
  window.innerHeight > window.innerWidth
@@ -304,7 +312,7 @@ const MemoriWidget = ({
304
312
  }
305
313
 
306
314
  setMuteSpeaker(getLocalConfig('muteSpeaker', false));
307
- setContinuousSpeech(getLocalConfig('continuousSpeech', true));
315
+ setContinuousSpeech(microphoneMode === 'CONTINUOUS');
308
316
  setContinuousSpeechTimeout(getLocalConfig('continuousSpeechTimeout', 2));
309
317
  setControlsPosition(
310
318
  getLocalConfig('controlsPosition', defaultControlsPosition)
@@ -944,6 +952,10 @@ const MemoriWidget = ({
944
952
  }
945
953
  }
946
954
 
955
+ if (memori.enableCompletions) {
956
+ timeout = timeout + 60;
957
+ }
958
+
947
959
  let uiTimeout = setTimeout(handleTimeout, timeout * 1000);
948
960
  setUserInteractionTimeout(uiTimeout);
949
961
  timeoutRef.current = uiTimeout;
@@ -1442,6 +1454,7 @@ const MemoriWidget = ({
1442
1454
 
1443
1455
  clearListening();
1444
1456
  setTranscript('');
1457
+ resetTranscript();
1445
1458
 
1446
1459
  try {
1447
1460
  navigator.mediaDevices
@@ -1498,6 +1511,8 @@ const MemoriWidget = ({
1498
1511
  recognizer.sessionStopped = (_s, _e) => {
1499
1512
  stopListening();
1500
1513
  };
1514
+
1515
+ resetTranscript();
1501
1516
  recognizer.startContinuousRecognitionAsync();
1502
1517
  })
1503
1518
  .catch(console.error);
@@ -1595,7 +1610,8 @@ const MemoriWidget = ({
1595
1610
  'sendOnEnter',
1596
1611
  'keypress'
1597
1612
  );
1598
- setSendOnEnter(stored);
1613
+ if (window.innerWidth <= 768) setSendOnEnter('click');
1614
+ else setSendOnEnter(stored);
1599
1615
  }, []);
1600
1616
  useEffect(() => {
1601
1617
  setLocalConfig('sendOnEnter', sendOnEnter);
@@ -2217,6 +2233,7 @@ const MemoriWidget = ({
2217
2233
  selectReceiverTag={selectReceiverTag}
2218
2234
  preview={preview}
2219
2235
  sendOnEnter={sendOnEnter}
2236
+ microphoneMode={continuousSpeech ? 'CONTINUOUS' : 'HOLD_TO_TALK'}
2220
2237
  setSendOnEnter={setSendOnEnter}
2221
2238
  attachmentsMenuOpen={attachmentsMenuOpen}
2222
2239
  setAttachmentsMenuOpen={setAttachmentsMenuOpen}
@@ -2405,9 +2422,9 @@ const MemoriWidget = ({
2405
2422
  layout={selectedLayout}
2406
2423
  open={!!showSettingsDrawer}
2407
2424
  onClose={() => setShowSettingsDrawer(false)}
2408
- continuousSpeech={continuousSpeech}
2425
+ microphoneMode={continuousSpeech ? 'CONTINUOUS' : 'HOLD_TO_TALK'}
2409
2426
  continuousSpeechTimeout={continuousSpeechTimeout}
2410
- setContinuousSpeech={setContinuousSpeech}
2427
+ setMicrophoneMode={mode => setContinuousSpeech(mode === 'CONTINUOUS')}
2411
2428
  setContinuousSpeechTimeout={setContinuousSpeechTimeout}
2412
2429
  controlsPosition={controlsPosition}
2413
2430
  setControlsPosition={setControlsPosition}
@@ -0,0 +1,101 @@
1
+ .memori-mic-btn-tooltip.memori-tooltip.memori-tooltip--align-topLeft:not(.memori-tooltip--disabled).memori-tooltip--visible .memori-tooltip--content,
2
+ .memori-mic-btn-tooltip.memori-tooltip.memori-tooltip--align-topLeft:not(.memori-tooltip--disabled):not(.memori-tooltip--visible):hover .memori-tooltip--content {
3
+ touch-action: none;
4
+ transform: translateY(-180%) translateX(27%);
5
+ -webkit-user-select: none;
6
+ user-select: none;
7
+ }
8
+
9
+ .memori-chat-inputs--mic {
10
+ z-index: 1;
11
+ margin-left: 0.33rem;
12
+ touch-action: none;
13
+ -webkit-user-select: none;
14
+ user-select: none;
15
+ }
16
+
17
+ .memori-chat-inputs--mic svg {
18
+ color: var(--memori-primary-text, #fff);
19
+ font-size: 1em;
20
+ touch-action: none;
21
+ -webkit-user-select: none;
22
+ user-select: none;
23
+ }
24
+
25
+ .memori-chat-inputs--mic:hover,
26
+ .memori-chat-inputs--mic:active,
27
+ .memori-chat-inputs--mic:focus {
28
+ border-color: var(--memori-primary) !important;
29
+ color: var(--memori-primary-text, #fff);
30
+ }
31
+
32
+ .memori-chat-inputs--mic:active,
33
+ .memori-chat-inputs--mic:focus {
34
+ box-shadow: 0 0.2rem 0.33rem var(--memori-primary) !important;
35
+ }
36
+
37
+ .memori-chat-inputs--mic:not(.memori-chat-inputs--mic--listening):active,
38
+ .memori-chat-inputs--mic:not(.memori-chat-inputs--mic--listening):focus {
39
+ color: var(--memori-primary) !important;
40
+ }
41
+
42
+ @keyframes micBtnActivePulse {
43
+ 0% {
44
+ transform: scale(1.25);
45
+ }
46
+
47
+ 25% {
48
+ transform: scale(1.4);
49
+ }
50
+
51
+ 50% {
52
+ transform: scale(1.3);
53
+ }
54
+
55
+ 75% {
56
+ transform: scale(1.4);
57
+ }
58
+
59
+ 100% {
60
+ transform: scale(1.2);
61
+ }
62
+ }
63
+
64
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening {
65
+ position: relative;
66
+ color: red !important;
67
+ transform: scale(1.5);
68
+ }
69
+
70
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening::before,
71
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening::after {
72
+ position: absolute;
73
+ z-index: -1;
74
+ top: 0;
75
+ left: 0;
76
+ width: 100%;
77
+ height: 100%;
78
+ border-radius: 50%;
79
+ animation: micBtnActivePulse 2s infinite;
80
+ background: var(--memori-primary);
81
+ content: "";
82
+ opacity: 0.2;
83
+ }
84
+
85
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening::after {
86
+ top: 5%;
87
+ left: 5%;
88
+ width: 90%;
89
+ height: 90%;
90
+ animation-delay: 0.3s;
91
+ opacity: 0.3;
92
+ }
93
+
94
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening:active,
95
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening:focus {
96
+ border-color: red !important;
97
+ }
98
+
99
+ .memori-chat-inputs--mic.memori-chat-inputs--mic--listening svg {
100
+ color: red !important;
101
+ }
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { Meta, Story } from '@storybook/react';
3
+ import MicrophoneButton, { Props } from './MicrophoneButton';
4
+
5
+ import './MicrophoneButton.css';
6
+
7
+ const meta: Meta = {
8
+ title: 'Widget/Microphone Button',
9
+ component: MicrophoneButton,
10
+ argTypes: {
11
+ disabled: {
12
+ control: {
13
+ type: 'boolean',
14
+ },
15
+ },
16
+ },
17
+ parameters: {
18
+ controls: { expanded: true },
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+
24
+ const Template: Story<Props> = args => {
25
+ const [listening, setListening] = React.useState(args.listening);
26
+ const startListening = () => setListening(true);
27
+ const stopListening = () => setListening(false);
28
+
29
+ return (
30
+ <div style={{ paddingTop: '10rem', textAlign: 'right' }}>
31
+ <MicrophoneButton
32
+ {...args}
33
+ listening={listening}
34
+ startListening={startListening}
35
+ stopListening={stopListening}
36
+ />
37
+ </div>
38
+ );
39
+ };
40
+
41
+ // By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
42
+ // https://storybook.js.org/docs/react/workflows/unit-testing
43
+ export const Default = Template.bind({});
44
+ Default.args = {
45
+ listening: false,
46
+ stopAudio: () => {},
47
+ startListening: () => {},
48
+ stopListening: () => {},
49
+ };