@memori.ai/memori-react 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/components/Avatar/Avatar.css +0 -1
- package/dist/components/Blob/Blob.css +6 -1
- package/dist/components/ChangeMode/ChangeMode.css +1 -1
- package/dist/components/Chat/Chat.css +3 -2
- package/dist/components/Chat/Chat.d.ts +1 -0
- package/dist/components/Chat/Chat.js +2 -2
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.css +1 -1
- package/dist/components/ChatBubble/ChatBubble.js +1 -1
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/ChatInputs/ChatInputs.css +1 -41
- package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
- package/dist/components/ChatInputs/ChatInputs.js +9 -3
- package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
- package/dist/components/ChatTextArea/ChatTextArea.css +7 -3
- package/dist/components/DateSelector/DateSelector.css +17 -15
- package/dist/components/ExportHistoryButton/ExportHistoryButton.css +1 -1
- package/dist/components/FeedbackButtons/FeedbackButtons.css +4 -4
- package/dist/components/FeedbackButtons/FeedbackButtons.js +1 -1
- package/dist/components/FeedbackButtons/FeedbackButtons.js.map +1 -1
- package/dist/components/Header/Header.css +2 -1
- package/dist/components/Header/Header.js +1 -1
- package/dist/components/Header/Header.js.map +1 -1
- package/dist/components/ImageUpload/ImageUpload.css +2 -3
- package/dist/components/MediaWidget/MediaItemWidget.css +2 -0
- package/dist/components/MediaWidget/MediaWidget.css +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.css +1 -2
- package/dist/components/MemoriWidget/MemoriWidget.js +23 -13
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/MicrophoneButton/MicrophoneButton.css +107 -0
- package/dist/components/MicrophoneButton/MicrophoneButton.d.ts +9 -0
- package/dist/components/MicrophoneButton/MicrophoneButton.js +46 -0
- package/dist/components/MicrophoneButton/MicrophoneButton.js.map +1 -0
- package/dist/components/SettingsDrawer/SettingsDrawer.d.ts +3 -3
- package/dist/components/SettingsDrawer/SettingsDrawer.js +8 -6
- package/dist/components/SettingsDrawer/SettingsDrawer.js.map +1 -1
- package/dist/components/SettingsDrawer/SettingsDrawer.test.js +7 -7
- package/dist/components/SettingsDrawer/SettingsDrawer.test.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.css +1 -1
- package/dist/components/StartPanel/StartPanel.js +1 -1
- package/dist/components/StartPanel/StartPanel.js.map +1 -1
- package/dist/components/layouts/totem.css +49 -8
- package/dist/components/ui/Button.css +1 -1
- package/dist/components/ui/Button.d.ts +5 -1
- package/dist/components/ui/Button.js +1 -1
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Checkbox.css +0 -2
- package/dist/components/ui/Drawer.css +1 -1
- package/dist/components/ui/Modal.css +1 -1
- package/dist/components/ui/Select.css +17 -16
- package/dist/components/ui/Tooltip.css +38 -3
- package/dist/components/ui/Tooltip.d.ts +2 -1
- package/dist/components/ui/Tooltip.js +1 -2
- package/dist/components/ui/Tooltip.js.map +1 -1
- package/dist/components/ui/Tooltip.test.js +16 -0
- package/dist/components/ui/Tooltip.test.js.map +1 -1
- package/dist/helpers/configuration.js +1 -1
- package/dist/helpers/configuration.js.map +1 -1
- package/dist/helpers/translations.js +1 -2
- package/dist/helpers/translations.js.map +1 -1
- package/dist/locales/en.json +4 -0
- package/dist/locales/it.json +4 -0
- package/dist/styles.css +2 -1
- package/esm/components/Avatar/Avatar.css +0 -1
- package/esm/components/Blob/Blob.css +6 -1
- package/esm/components/ChangeMode/ChangeMode.css +1 -1
- package/esm/components/Chat/Chat.css +3 -2
- package/esm/components/Chat/Chat.d.ts +1 -0
- package/esm/components/Chat/Chat.js +2 -2
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.css +1 -1
- package/esm/components/ChatBubble/ChatBubble.js +1 -1
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/ChatInputs/ChatInputs.css +1 -41
- package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
- package/esm/components/ChatInputs/ChatInputs.js +9 -3
- package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
- package/esm/components/ChatTextArea/ChatTextArea.css +7 -3
- package/esm/components/DateSelector/DateSelector.css +17 -15
- package/esm/components/ExportHistoryButton/ExportHistoryButton.css +1 -1
- package/esm/components/FeedbackButtons/FeedbackButtons.css +4 -4
- package/esm/components/FeedbackButtons/FeedbackButtons.js +1 -1
- package/esm/components/FeedbackButtons/FeedbackButtons.js.map +1 -1
- package/esm/components/Header/Header.css +2 -1
- package/esm/components/Header/Header.js +1 -1
- package/esm/components/Header/Header.js.map +1 -1
- package/esm/components/ImageUpload/ImageUpload.css +2 -3
- package/esm/components/MediaWidget/MediaItemWidget.css +2 -0
- package/esm/components/MediaWidget/MediaWidget.css +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.css +1 -2
- package/esm/components/MemoriWidget/MemoriWidget.js +23 -13
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/MicrophoneButton/MicrophoneButton.css +107 -0
- package/esm/components/MicrophoneButton/MicrophoneButton.d.ts +9 -0
- package/esm/components/MicrophoneButton/MicrophoneButton.js +43 -0
- package/esm/components/MicrophoneButton/MicrophoneButton.js.map +1 -0
- package/esm/components/SettingsDrawer/SettingsDrawer.d.ts +3 -3
- package/esm/components/SettingsDrawer/SettingsDrawer.js +9 -7
- package/esm/components/SettingsDrawer/SettingsDrawer.js.map +1 -1
- package/esm/components/SettingsDrawer/SettingsDrawer.test.js +7 -7
- package/esm/components/SettingsDrawer/SettingsDrawer.test.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.css +1 -1
- package/esm/components/StartPanel/StartPanel.js +1 -1
- package/esm/components/StartPanel/StartPanel.js.map +1 -1
- package/esm/components/layouts/totem.css +49 -8
- package/esm/components/ui/Button.css +1 -1
- package/esm/components/ui/Button.d.ts +5 -1
- package/esm/components/ui/Button.js +1 -1
- package/esm/components/ui/Button.js.map +1 -1
- package/esm/components/ui/Checkbox.css +0 -2
- package/esm/components/ui/Drawer.css +1 -1
- package/esm/components/ui/Modal.css +1 -1
- package/esm/components/ui/Select.css +17 -16
- package/esm/components/ui/Tooltip.css +38 -3
- package/esm/components/ui/Tooltip.d.ts +2 -1
- package/esm/components/ui/Tooltip.js +1 -2
- package/esm/components/ui/Tooltip.js.map +1 -1
- package/esm/components/ui/Tooltip.test.js +16 -0
- package/esm/components/ui/Tooltip.test.js.map +1 -1
- package/esm/helpers/configuration.js +1 -1
- package/esm/helpers/configuration.js.map +1 -1
- package/esm/helpers/translations.js +1 -2
- package/esm/helpers/translations.js.map +1 -1
- package/esm/locales/en.json +4 -0
- package/esm/locales/it.json +4 -0
- package/esm/styles.css +2 -1
- package/package.json +1 -1
- package/src/components/Avatar/Avatar.css +0 -1
- package/src/components/Blob/Blob.css +6 -1
- package/src/components/BlockedMemoriBadge/__snapshots__/BlockedMemoriBadge.test.tsx.snap +4 -4
- package/src/components/ChangeMode/ChangeMode.css +1 -1
- package/src/components/Chat/Chat.css +3 -2
- package/src/components/Chat/Chat.tsx +3 -0
- package/src/components/ChatBubble/ChatBubble.css +1 -1
- package/src/components/ChatBubble/ChatBubble.tsx +1 -1
- package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +1 -1
- package/src/components/ChatInputs/ChatInputs.css +1 -41
- package/src/components/ChatInputs/ChatInputs.stories.tsx +50 -3
- package/src/components/ChatInputs/ChatInputs.tsx +20 -3
- package/src/components/ChatInputs/__snapshots__/ChatInputs.test.tsx.snap +160 -85
- package/src/components/ChatTextArea/ChatTextArea.css +7 -3
- package/src/components/DateSelector/DateSelector.css +17 -15
- package/src/components/ExportHistoryButton/ExportHistoryButton.css +1 -1
- package/src/components/FeedbackButtons/FeedbackButtons.css +4 -4
- package/src/components/FeedbackButtons/FeedbackButtons.tsx +1 -1
- package/src/components/Header/Header.css +2 -1
- package/src/components/Header/Header.stories.tsx +3 -0
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/Header/__snapshots__/Header.test.tsx.snap +1 -1
- package/src/components/ImageUpload/ImageUpload.css +2 -3
- package/src/components/MediaWidget/MediaItemWidget.css +2 -0
- package/src/components/MediaWidget/MediaWidget.css +1 -1
- package/src/components/MemoriWidget/MemoriWidget.css +1 -2
- package/src/components/MemoriWidget/MemoriWidget.tsx +29 -12
- package/src/components/MicrophoneButton/MicrophoneButton.css +107 -0
- package/src/components/MicrophoneButton/MicrophoneButton.stories.tsx +49 -0
- package/src/components/MicrophoneButton/MicrophoneButton.tsx +95 -0
- package/src/components/SettingsDrawer/SettingsDrawer.stories.tsx +6 -4
- package/src/components/SettingsDrawer/SettingsDrawer.test.tsx +14 -14
- package/src/components/SettingsDrawer/SettingsDrawer.tsx +57 -25
- package/src/components/StartPanel/StartPanel.css +1 -1
- package/src/components/StartPanel/StartPanel.tsx +3 -3
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +1 -1
- package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +1 -1
- package/src/components/layouts/totem.css +49 -8
- package/src/components/ui/Button.css +1 -1
- package/src/components/ui/Button.tsx +21 -1
- package/src/components/ui/Checkbox.css +0 -2
- package/src/components/ui/Drawer.css +1 -1
- package/src/components/ui/Modal.css +1 -1
- package/src/components/ui/Select.css +17 -16
- package/src/components/ui/Tooltip.css +38 -3
- package/src/components/ui/Tooltip.stories.tsx +40 -3
- package/src/components/ui/Tooltip.test.tsx +52 -0
- package/src/components/ui/Tooltip.tsx +12 -7
- package/src/components/ui/__snapshots__/Tooltip.test.tsx.snap +80 -4
- package/src/helpers/configuration.ts +1 -1
- package/src/helpers/translations.ts +3 -2
- package/src/locales/en.json +4 -0
- package/src/locales/it.json +4 -0
- package/src/styles.css +2 -1
|
@@ -251,18 +251,19 @@ const MemoriWidget = ({
|
|
|
251
251
|
?.find(c => c.memoriConfigID === memori.memoriConfigurationID)
|
|
252
252
|
?.culture?.split('-')?.[0]
|
|
253
253
|
?.toUpperCase();
|
|
254
|
-
|
|
254
|
+
const integrationConfig = integration?.customData
|
|
255
|
+
? JSON.parse(integration.customData)
|
|
256
|
+
: null;
|
|
257
|
+
const isMultilanguageEnabled = !!integrationConfig?.multilanguage;
|
|
255
258
|
const [userLang, setUserLang] = useState(
|
|
256
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2425
|
+
microphoneMode={continuousSpeech ? 'CONTINUOUS' : 'HOLD_TO_TALK'}
|
|
2409
2426
|
continuousSpeechTimeout={continuousSpeechTimeout}
|
|
2410
|
-
|
|
2427
|
+
setMicrophoneMode={mode => setContinuousSpeech(mode === 'CONTINUOUS')}
|
|
2411
2428
|
setContinuousSpeechTimeout={setContinuousSpeechTimeout}
|
|
2412
2429
|
controlsPosition={controlsPosition}
|
|
2413
2430
|
setControlsPosition={setControlsPosition}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
.memori-mic-btn-tooltip.memori-tooltip.memori-tooltip--align-topLeft:not(
|
|
2
|
+
.memori-tooltip--disabled
|
|
3
|
+
).memori-tooltip--visible
|
|
4
|
+
.memori-tooltip--content,
|
|
5
|
+
.memori-mic-btn-tooltip.memori-tooltip.memori-tooltip--align-topLeft:not(.memori-tooltip--disabled):not(
|
|
6
|
+
.memori-tooltip--visible
|
|
7
|
+
):hover
|
|
8
|
+
.memori-tooltip--content {
|
|
9
|
+
touch-action: none;
|
|
10
|
+
transform: translateY(-180%) translateX(27%);
|
|
11
|
+
-webkit-user-select: none;
|
|
12
|
+
user-select: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.memori-chat-inputs--mic {
|
|
16
|
+
z-index: 1;
|
|
17
|
+
margin-left: 0.33rem;
|
|
18
|
+
touch-action: none;
|
|
19
|
+
-webkit-user-select: none;
|
|
20
|
+
user-select: none;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.memori-chat-inputs--mic svg {
|
|
24
|
+
color: var(--memori-primary-text, #fff);
|
|
25
|
+
font-size: 1em;
|
|
26
|
+
touch-action: none;
|
|
27
|
+
-webkit-user-select: none;
|
|
28
|
+
user-select: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.memori-chat-inputs--mic:hover,
|
|
32
|
+
.memori-chat-inputs--mic:active,
|
|
33
|
+
.memori-chat-inputs--mic:focus {
|
|
34
|
+
border-color: var(--memori-primary) !important;
|
|
35
|
+
color: var(--memori-primary-text, #fff);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.memori-chat-inputs--mic:active,
|
|
39
|
+
.memori-chat-inputs--mic:focus {
|
|
40
|
+
box-shadow: 0 0.2rem 0.33rem var(--memori-primary) !important;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.memori-chat-inputs--mic:not(.memori-chat-inputs--mic--listening):active,
|
|
44
|
+
.memori-chat-inputs--mic:not(.memori-chat-inputs--mic--listening):focus {
|
|
45
|
+
color: var(--memori-primary) !important;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@keyframes micBtnActivePulse {
|
|
49
|
+
0% {
|
|
50
|
+
transform: scale(1.25);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
25% {
|
|
54
|
+
transform: scale(1.4);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
50% {
|
|
58
|
+
transform: scale(1.3);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
75% {
|
|
62
|
+
transform: scale(1.4);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
100% {
|
|
66
|
+
transform: scale(1.2);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening {
|
|
71
|
+
position: relative;
|
|
72
|
+
color: red !important;
|
|
73
|
+
transform: scale(1.5);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening::before,
|
|
77
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening::after {
|
|
78
|
+
position: absolute;
|
|
79
|
+
z-index: -1;
|
|
80
|
+
top: 0;
|
|
81
|
+
left: 0;
|
|
82
|
+
width: 100%;
|
|
83
|
+
height: 100%;
|
|
84
|
+
border-radius: 50%;
|
|
85
|
+
animation: micBtnActivePulse 2s infinite;
|
|
86
|
+
background: var(--memori-primary);
|
|
87
|
+
content: '';
|
|
88
|
+
opacity: 0.2;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening::after {
|
|
92
|
+
top: 5%;
|
|
93
|
+
left: 5%;
|
|
94
|
+
width: 90%;
|
|
95
|
+
height: 90%;
|
|
96
|
+
animation-delay: 0.3s;
|
|
97
|
+
opacity: 0.3;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening:active,
|
|
101
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening:focus {
|
|
102
|
+
border-color: red !important;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.memori-chat-inputs--mic.memori-chat-inputs--mic--listening svg {
|
|
106
|
+
color: red !important;
|
|
107
|
+
}
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
+
import { Props as ChatInputProps } from '../ChatInputs/ChatInputs';
|
|
3
|
+
import Microphone from '../icons/Microphone';
|
|
4
|
+
import Button from '../ui/Button';
|
|
5
|
+
import Tooltip from '../ui/Tooltip';
|
|
6
|
+
import cx from 'classnames';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
|
|
9
|
+
export interface Props {
|
|
10
|
+
listening?: ChatInputProps['listening'];
|
|
11
|
+
stopAudio: ChatInputProps['stopAudio'];
|
|
12
|
+
startListening: ChatInputProps['startListening'];
|
|
13
|
+
stopListening: ChatInputProps['stopListening'];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const MicrophoneButton = ({
|
|
17
|
+
listening,
|
|
18
|
+
stopAudio,
|
|
19
|
+
startListening,
|
|
20
|
+
stopListening,
|
|
21
|
+
}: Props) => {
|
|
22
|
+
const { t } = useTranslation();
|
|
23
|
+
const [micBtnTooltip, setMicBtnTooltip] = useState<string | undefined>();
|
|
24
|
+
|
|
25
|
+
const intervalRef = useRef<any>(null);
|
|
26
|
+
|
|
27
|
+
const startHold = (
|
|
28
|
+
e:
|
|
29
|
+
| React.TouchEvent<HTMLButtonElement>
|
|
30
|
+
| React.MouseEvent<Element, MouseEvent>
|
|
31
|
+
) => {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
|
|
34
|
+
setMicBtnTooltip(t('write_and_speak.holdToSpeak') || 'Hold to record');
|
|
35
|
+
|
|
36
|
+
if (intervalRef.current) return;
|
|
37
|
+
intervalRef.current = setTimeout(() => {
|
|
38
|
+
stopAudio();
|
|
39
|
+
setMicBtnTooltip(
|
|
40
|
+
t('write_and_speak.releaseToEndListening') || 'Release to end listening'
|
|
41
|
+
);
|
|
42
|
+
startListening();
|
|
43
|
+
}, 300);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const stopHold = () => {
|
|
47
|
+
if (intervalRef.current) {
|
|
48
|
+
clearTimeout(intervalRef.current);
|
|
49
|
+
intervalRef.current = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
stopListening();
|
|
53
|
+
setMicBtnTooltip(undefined);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
return () => stopHold();
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Tooltip
|
|
62
|
+
visible={!!micBtnTooltip}
|
|
63
|
+
content={
|
|
64
|
+
<span>
|
|
65
|
+
{micBtnTooltip ||
|
|
66
|
+
t('write_and_speak.pressAndHoldToSpeak') ||
|
|
67
|
+
'Press and hold to speak'}
|
|
68
|
+
</span>
|
|
69
|
+
}
|
|
70
|
+
align="topLeft"
|
|
71
|
+
className="memori-mic-btn-tooltip"
|
|
72
|
+
>
|
|
73
|
+
<Button
|
|
74
|
+
primary
|
|
75
|
+
className={cx('memori-chat-inputs--mic', {
|
|
76
|
+
'memori-chat-inputs--mic--listening': listening,
|
|
77
|
+
})}
|
|
78
|
+
title={
|
|
79
|
+
listening
|
|
80
|
+
? t('write_and_speak.micButtonPopoverListening') || 'Listening'
|
|
81
|
+
: t('write_and_speak.micButtonPopover') || 'Start listening'
|
|
82
|
+
}
|
|
83
|
+
onMouseDown={startHold}
|
|
84
|
+
onTouchStart={startHold}
|
|
85
|
+
onMouseUp={stopHold}
|
|
86
|
+
onMouseLeave={stopHold}
|
|
87
|
+
onTouchEnd={stopHold}
|
|
88
|
+
shape="circle"
|
|
89
|
+
icon={<Microphone />}
|
|
90
|
+
/>
|
|
91
|
+
</Tooltip>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export default MicrophoneButton;
|
|
@@ -21,15 +21,17 @@ const meta: Meta = {
|
|
|
21
21
|
export default meta;
|
|
22
22
|
|
|
23
23
|
const Template: Story<Props> = args => {
|
|
24
|
-
const [
|
|
24
|
+
const [microphoneMode, setMicrophoneMode] = React.useState<
|
|
25
|
+
'HOLD_TO_TALK' | 'CONTINUOUS'
|
|
26
|
+
>('HOLD_TO_TALK');
|
|
25
27
|
const [controlsPosition, setControlsPosition] = React.useState<
|
|
26
|
-
'bottom' | 'center'
|
|
28
|
+
'bottom' | 'center'
|
|
27
29
|
>('bottom');
|
|
28
30
|
return (
|
|
29
31
|
<SettingsDrawer
|
|
30
32
|
{...args}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
microphoneMode={microphoneMode}
|
|
34
|
+
setMicrophoneMode={setMicrophoneMode}
|
|
33
35
|
controlsPosition={controlsPosition}
|
|
34
36
|
setControlsPosition={setControlsPosition}
|
|
35
37
|
/>
|
|
@@ -16,9 +16,9 @@ it('renders SettingsDrawer unchanged', () => {
|
|
|
16
16
|
<SettingsDrawer
|
|
17
17
|
open={false}
|
|
18
18
|
onClose={jest.fn()}
|
|
19
|
-
|
|
19
|
+
microphoneMode="HOLD_TO_TALK"
|
|
20
|
+
setMicrophoneMode={jest.fn()}
|
|
20
21
|
continuousSpeechTimeout={2}
|
|
21
|
-
setContinuousSpeech={jest.fn()}
|
|
22
22
|
setContinuousSpeechTimeout={jest.fn()}
|
|
23
23
|
controlsPosition="bottom"
|
|
24
24
|
setControlsPosition={jest.fn()}
|
|
@@ -34,9 +34,9 @@ it('renders SettingsDrawer open unchanged', () => {
|
|
|
34
34
|
<SettingsDrawer
|
|
35
35
|
open={true}
|
|
36
36
|
onClose={jest.fn()}
|
|
37
|
-
|
|
37
|
+
microphoneMode="HOLD_TO_TALK"
|
|
38
|
+
setMicrophoneMode={jest.fn()}
|
|
38
39
|
continuousSpeechTimeout={2}
|
|
39
|
-
setContinuousSpeech={jest.fn()}
|
|
40
40
|
setContinuousSpeechTimeout={jest.fn()}
|
|
41
41
|
controlsPosition="bottom"
|
|
42
42
|
setControlsPosition={jest.fn()}
|
|
@@ -52,9 +52,9 @@ it('renders SettingsDrawer open with continuous speech enabled unchanged', () =>
|
|
|
52
52
|
<SettingsDrawer
|
|
53
53
|
open={true}
|
|
54
54
|
onClose={jest.fn()}
|
|
55
|
-
|
|
55
|
+
microphoneMode="CONTINUOUS"
|
|
56
|
+
setMicrophoneMode={jest.fn()}
|
|
56
57
|
continuousSpeechTimeout={2}
|
|
57
|
-
setContinuousSpeech={jest.fn()}
|
|
58
58
|
setContinuousSpeechTimeout={jest.fn()}
|
|
59
59
|
controlsPosition="bottom"
|
|
60
60
|
setControlsPosition={jest.fn()}
|
|
@@ -70,9 +70,9 @@ it('renders SettingsDrawer open with non-default continuous speech timeout uncha
|
|
|
70
70
|
<SettingsDrawer
|
|
71
71
|
open={true}
|
|
72
72
|
onClose={jest.fn()}
|
|
73
|
-
|
|
73
|
+
microphoneMode="CONTINUOUS"
|
|
74
|
+
setMicrophoneMode={jest.fn()}
|
|
74
75
|
continuousSpeechTimeout={10}
|
|
75
|
-
setContinuousSpeech={jest.fn()}
|
|
76
76
|
setContinuousSpeechTimeout={jest.fn()}
|
|
77
77
|
controlsPosition="bottom"
|
|
78
78
|
setControlsPosition={jest.fn()}
|
|
@@ -89,9 +89,9 @@ it('renders SettingsDrawer for totem layout open unchanged', () => {
|
|
|
89
89
|
layout="TOTEM"
|
|
90
90
|
open={true}
|
|
91
91
|
onClose={jest.fn()}
|
|
92
|
-
|
|
92
|
+
microphoneMode="HOLD_TO_TALK"
|
|
93
|
+
setMicrophoneMode={jest.fn()}
|
|
93
94
|
continuousSpeechTimeout={2}
|
|
94
|
-
setContinuousSpeech={jest.fn()}
|
|
95
95
|
setContinuousSpeechTimeout={jest.fn()}
|
|
96
96
|
controlsPosition="bottom"
|
|
97
97
|
setControlsPosition={jest.fn()}
|
|
@@ -108,9 +108,9 @@ it('renders SettingsDrawer for totem layout open with controls at center unchang
|
|
|
108
108
|
layout="TOTEM"
|
|
109
109
|
open={true}
|
|
110
110
|
onClose={jest.fn()}
|
|
111
|
-
|
|
111
|
+
microphoneMode="HOLD_TO_TALK"
|
|
112
|
+
setMicrophoneMode={jest.fn()}
|
|
112
113
|
continuousSpeechTimeout={2}
|
|
113
|
-
setContinuousSpeech={jest.fn()}
|
|
114
114
|
setContinuousSpeechTimeout={jest.fn()}
|
|
115
115
|
controlsPosition="center"
|
|
116
116
|
setControlsPosition={jest.fn()}
|
|
@@ -127,9 +127,9 @@ it('renders SettingsDrawer for totem layout with continuous speech and hide emis
|
|
|
127
127
|
layout="TOTEM"
|
|
128
128
|
open={true}
|
|
129
129
|
onClose={jest.fn()}
|
|
130
|
-
|
|
130
|
+
microphoneMode="HOLD_TO_TALK"
|
|
131
|
+
setMicrophoneMode={jest.fn()}
|
|
131
132
|
continuousSpeechTimeout={2}
|
|
132
|
-
setContinuousSpeech={jest.fn()}
|
|
133
133
|
setContinuousSpeechTimeout={jest.fn()}
|
|
134
134
|
controlsPosition="bottom"
|
|
135
135
|
setControlsPosition={jest.fn()}
|
|
@@ -11,9 +11,9 @@ export interface Props {
|
|
|
11
11
|
open: boolean;
|
|
12
12
|
layout?: 'FULLPAGE' | 'TOTEM' | 'DEFAULT';
|
|
13
13
|
onClose: () => void;
|
|
14
|
-
|
|
14
|
+
microphoneMode?: 'HOLD_TO_TALK' | 'CONTINUOUS';
|
|
15
15
|
continuousSpeechTimeout?: number;
|
|
16
|
-
|
|
16
|
+
setMicrophoneMode: (value: 'HOLD_TO_TALK' | 'CONTINUOUS') => void;
|
|
17
17
|
setContinuousSpeechTimeout: (value: number) => void;
|
|
18
18
|
controlsPosition?: 'center' | 'bottom';
|
|
19
19
|
setControlsPosition: (value: 'center' | 'bottom') => void;
|
|
@@ -27,9 +27,9 @@ const SettingsDrawer = ({
|
|
|
27
27
|
open,
|
|
28
28
|
layout = 'DEFAULT',
|
|
29
29
|
onClose,
|
|
30
|
-
|
|
30
|
+
microphoneMode = 'HOLD_TO_TALK',
|
|
31
31
|
continuousSpeechTimeout,
|
|
32
|
-
|
|
32
|
+
setMicrophoneMode,
|
|
33
33
|
setContinuousSpeechTimeout,
|
|
34
34
|
controlsPosition,
|
|
35
35
|
setControlsPosition,
|
|
@@ -46,31 +46,63 @@ const SettingsDrawer = ({
|
|
|
46
46
|
title={t('widget.settings') || 'Settings'}
|
|
47
47
|
description={t('write_and_speak.settingsHeaderLabel')}
|
|
48
48
|
>
|
|
49
|
-
<div className="memori-settings-drawer--field">
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<div className="memori-settings-drawer--field">
|
|
62
|
-
<Select
|
|
63
|
-
label={t('write_and_speak.secondsLabel') || 'Seconds'}
|
|
64
|
-
placeholder={t('write_and_speak.secondsLabel') || 'Seconds'}
|
|
65
|
-
options={silenceSeconds.map(s => ({ value: s, label: s }))}
|
|
66
|
-
value={continuousSpeechTimeout}
|
|
49
|
+
<div className="memori-settings-drawer--field controls">
|
|
50
|
+
<label htmlFor="#microphoneMode">
|
|
51
|
+
{t('write_and_speak.microphoneMode') || 'Microphone mode'}:
|
|
52
|
+
</label>
|
|
53
|
+
<RadioGroup
|
|
54
|
+
id="microphoneMode"
|
|
55
|
+
name="microphoneMode"
|
|
56
|
+
value={microphoneMode}
|
|
57
|
+
defaultValue={microphoneMode}
|
|
58
|
+
className="memori-settings-drawer--microphoneMode-radio"
|
|
67
59
|
onChange={value => {
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
let micMode =
|
|
61
|
+
value === 'CONTINUOUS' ? 'CONTINUOUS' : 'HOLD_TO_TALK';
|
|
62
|
+
|
|
63
|
+
setMicrophoneMode(micMode as 'CONTINUOUS' | 'HOLD_TO_TALK');
|
|
64
|
+
setLocalConfig('microphoneMode', micMode);
|
|
70
65
|
}}
|
|
71
|
-
|
|
66
|
+
>
|
|
67
|
+
<RadioGroup.Option
|
|
68
|
+
value="HOLD_TO_TALK"
|
|
69
|
+
className="memori-settings-drawer--microphoneMode-radio-button"
|
|
70
|
+
>
|
|
71
|
+
{({ checked }) => (
|
|
72
|
+
<Button primary={checked}>
|
|
73
|
+
{t('write_and_speak.holdToSpeak') || 'Hold to speak'}
|
|
74
|
+
</Button>
|
|
75
|
+
)}
|
|
76
|
+
</RadioGroup.Option>
|
|
77
|
+
<RadioGroup.Option
|
|
78
|
+
value="CONTINUOUS"
|
|
79
|
+
className="memori-settings-drawer--microphoneMode-radio-button"
|
|
80
|
+
>
|
|
81
|
+
{({ checked }) => (
|
|
82
|
+
<Button primary={checked}>
|
|
83
|
+
{t('write_and_speak.continuousSpeechLabel') ||
|
|
84
|
+
'Continuous speech'}
|
|
85
|
+
</Button>
|
|
86
|
+
)}
|
|
87
|
+
</RadioGroup.Option>
|
|
88
|
+
</RadioGroup>
|
|
72
89
|
</div>
|
|
73
90
|
|
|
91
|
+
{microphoneMode === 'CONTINUOUS' && (
|
|
92
|
+
<div className="memori-settings-drawer--field">
|
|
93
|
+
<Select
|
|
94
|
+
label={t('write_and_speak.secondsLabel') || 'Seconds'}
|
|
95
|
+
placeholder={t('write_and_speak.secondsLabel') || 'Seconds'}
|
|
96
|
+
options={silenceSeconds.map(s => ({ value: s, label: s }))}
|
|
97
|
+
value={continuousSpeechTimeout}
|
|
98
|
+
onChange={value => {
|
|
99
|
+
setContinuousSpeechTimeout(value);
|
|
100
|
+
setLocalConfig('continuousSpeechTimeout', value);
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
|
|
74
106
|
{layout === 'TOTEM' && (
|
|
75
107
|
<>
|
|
76
108
|
<div className="memori-settings-drawer--field controls">
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
padding: var(--memori-inner-content-pad, 0);
|
|
24
24
|
border-radius: 10px;
|
|
25
25
|
margin-top: 2rem;
|
|
26
|
+
-webkit-backdrop-filter: blur(10px);
|
|
26
27
|
backdrop-filter: blur(10px);
|
|
27
28
|
background-color: var(--memori-inner-bg, transparent);
|
|
28
29
|
color: var(--memori-text-color, rgba(0, 0, 0, 0.85)) !important;
|
|
@@ -68,7 +69,6 @@
|
|
|
68
69
|
box-shadow: 0 0 5px rgba(50, 50, 50, 0.3);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
|
|
72
72
|
.memori--avatar img {
|
|
73
73
|
width: 100%;
|
|
74
74
|
height: 100%;
|
|
@@ -102,7 +102,7 @@ const StartPanel: React.FC<Props> = ({
|
|
|
102
102
|
{!!gamificationLevel?.badge?.length && (
|
|
103
103
|
<div className="memori--gamification-badge">
|
|
104
104
|
<Tooltip
|
|
105
|
-
|
|
105
|
+
align="left"
|
|
106
106
|
content={`${t('gamification.level')} ${
|
|
107
107
|
gamificationLevel.badge
|
|
108
108
|
}, ${gamificationLevel.points} ${t('gamification.points')}`}
|
|
@@ -119,7 +119,7 @@ const StartPanel: React.FC<Props> = ({
|
|
|
119
119
|
)}
|
|
120
120
|
{!!memori.enableCompletions && (
|
|
121
121
|
<div className="memori--completions-enabled">
|
|
122
|
-
<Tooltip
|
|
122
|
+
<Tooltip align="left" content={t('completionsEnabled')}>
|
|
123
123
|
<span aria-label={t('completionsEnabled') || 'Completions'}>
|
|
124
124
|
<AI />
|
|
125
125
|
</span>
|
|
@@ -128,7 +128,7 @@ const StartPanel: React.FC<Props> = ({
|
|
|
128
128
|
)}
|
|
129
129
|
{!!memori.nsfw && (
|
|
130
130
|
<div className="memori--nsfw">
|
|
131
|
-
<Tooltip
|
|
131
|
+
<Tooltip align="left" content={t('nsfw')}>
|
|
132
132
|
<span title={t('nsfw') || 'NSFW'}>🔞</span>
|
|
133
133
|
</Tooltip>
|
|
134
134
|
</div>
|
|
@@ -71,7 +71,7 @@ exports[`renders FullPage layout unchanged 1`] = `
|
|
|
71
71
|
</button>
|
|
72
72
|
</div>
|
|
73
73
|
<button
|
|
74
|
-
class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button"
|
|
74
|
+
class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-settings"
|
|
75
75
|
title="widget.settings"
|
|
76
76
|
>
|
|
77
77
|
<span
|
|
@@ -124,7 +124,7 @@ exports[`renders Totem layout unchanged 1`] = `
|
|
|
124
124
|
</button>
|
|
125
125
|
</div>
|
|
126
126
|
<button
|
|
127
|
-
class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button"
|
|
127
|
+
class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-settings"
|
|
128
128
|
title="widget.settings"
|
|
129
129
|
>
|
|
130
130
|
<span
|