@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.
- package/CHANGELOG.md +17 -0
- 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.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/FeedbackButtons/FeedbackButtons.js +1 -1
- package/dist/components/FeedbackButtons/FeedbackButtons.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +23 -13
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/MicrophoneButton/MicrophoneButton.css +101 -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.js +1 -1
- package/dist/components/StartPanel/StartPanel.js.map +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/Tooltip.css +33 -2
- 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/locales/en.json +4 -0
- package/dist/locales/it.json +4 -0
- package/dist/styles.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.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/FeedbackButtons/FeedbackButtons.js +1 -1
- package/esm/components/FeedbackButtons/FeedbackButtons.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +23 -13
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/MicrophoneButton/MicrophoneButton.css +101 -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.js +1 -1
- package/esm/components/StartPanel/StartPanel.js.map +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/Tooltip.css +33 -2
- 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/locales/en.json +4 -0
- package/esm/locales/it.json +4 -0
- package/esm/styles.css +3 -2
- package/package.json +1 -1
- package/src/components/BlockedMemoriBadge/__snapshots__/BlockedMemoriBadge.test.tsx.snap +4 -4
- package/src/components/Chat/Chat.tsx +3 -0
- 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/FeedbackButtons/FeedbackButtons.tsx +1 -1
- package/src/components/Header/Header.stories.tsx +3 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +29 -12
- package/src/components/MicrophoneButton/MicrophoneButton.css +101 -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.tsx +3 -3
- package/src/components/ui/Button.tsx +21 -1
- package/src/components/ui/Tooltip.css +33 -2
- 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/locales/en.json +4 -0
- package/src/locales/it.json +4 -0
- package/src/styles.css +3 -2
|
@@ -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">
|
|
@@ -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>
|
|
@@ -23,7 +23,19 @@ export interface Props {
|
|
|
23
23
|
id?: string;
|
|
24
24
|
htmlType?: 'button' | 'submit' | 'reset';
|
|
25
25
|
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
|
26
|
-
|
|
26
|
+
onMouseDown?: (
|
|
27
|
+
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
28
|
+
) => void;
|
|
29
|
+
onMouseUp?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
|
30
|
+
onMouseLeave?: (
|
|
31
|
+
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
32
|
+
) => void;
|
|
33
|
+
onTouchStart?: (
|
|
34
|
+
event: React.TouchEvent<HTMLButtonElement> | React.MouseEvent
|
|
35
|
+
) => void;
|
|
36
|
+
onTouchEnd?: (
|
|
37
|
+
event: React.TouchEvent<HTMLButtonElement> | React.MouseEvent
|
|
38
|
+
) => void;
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
const Button: FC<Props> = ({
|
|
@@ -42,6 +54,10 @@ const Button: FC<Props> = ({
|
|
|
42
54
|
id,
|
|
43
55
|
htmlType,
|
|
44
56
|
onClick,
|
|
57
|
+
onMouseDown,
|
|
58
|
+
onMouseUp,
|
|
59
|
+
onMouseLeave,
|
|
60
|
+
onTouchStart,
|
|
45
61
|
onTouchEnd,
|
|
46
62
|
children,
|
|
47
63
|
}) => (
|
|
@@ -49,6 +65,10 @@ const Button: FC<Props> = ({
|
|
|
49
65
|
id={id}
|
|
50
66
|
type={htmlType}
|
|
51
67
|
onClick={onClick}
|
|
68
|
+
onMouseDown={onMouseDown}
|
|
69
|
+
onMouseUp={onMouseUp}
|
|
70
|
+
onMouseLeave={onMouseLeave}
|
|
71
|
+
onTouchStart={onTouchStart}
|
|
52
72
|
onTouchEnd={onTouchEnd}
|
|
53
73
|
title={title}
|
|
54
74
|
disabled={loading || disabled}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* stylelint-disable no-descending-specificity */
|
|
2
|
+
|
|
1
3
|
.memori-tooltip {
|
|
2
4
|
position: relative;
|
|
3
5
|
display: inline-block;
|
|
@@ -23,7 +25,8 @@
|
|
|
23
25
|
transition: 0.3s 0.1s all ease;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
.memori-tooltip.memori-tooltip--align-left .memori-tooltip--content
|
|
28
|
+
.memori-tooltip.memori-tooltip--align-left .memori-tooltip--content,
|
|
29
|
+
.memori-tooltip.memori-tooltip--align-topLeft .memori-tooltip--content {
|
|
27
30
|
right: 100%;
|
|
28
31
|
left: initial;
|
|
29
32
|
margin: initial;
|
|
@@ -52,6 +55,15 @@
|
|
|
52
55
|
margin-left: 0;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
.memori-tooltip.memori-tooltip--align-topRight .memori-tooltip--content::before {
|
|
59
|
+
top: 100%;
|
|
60
|
+
right: auto;
|
|
61
|
+
left: 10px;
|
|
62
|
+
border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent;
|
|
63
|
+
margin-top: 10px;
|
|
64
|
+
margin-left: 5px;
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
.memori-tooltip:not(.memori-tooltip--disabled).memori-tooltip--visible .memori-tooltip--content,
|
|
56
68
|
.memori-tooltip:not(.memori-tooltip--disabled).memori-tooltip--visible .memori-tooltip--content::before {
|
|
57
69
|
display: block;
|
|
@@ -69,6 +81,25 @@
|
|
|
69
81
|
opacity: 1;
|
|
70
82
|
}
|
|
71
83
|
|
|
84
|
+
.memori-tooltip.memori-tooltip--align-topRight:not(.memori-tooltip--disabled).memori-tooltip--visible .memori-tooltip--content,
|
|
85
|
+
.memori-tooltip.memori-tooltip--align-topRight:not(.memori-tooltip--disabled):not(.memori-tooltip--visible):hover .memori-tooltip--content {
|
|
86
|
+
transform: translateY(-150%) translateX(-33%);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.memori-tooltip.memori-tooltip--align-topLeft .memori-tooltip--content::before {
|
|
90
|
+
top: 100%;
|
|
91
|
+
right: 10px;
|
|
92
|
+
left: auto;
|
|
93
|
+
border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent;
|
|
94
|
+
margin-top: 10px;
|
|
95
|
+
margin-left: 5px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.memori-tooltip.memori-tooltip--align-topLeft:not(.memori-tooltip--disabled).memori-tooltip--visible .memori-tooltip--content,
|
|
99
|
+
.memori-tooltip.memori-tooltip--align-topLeft:not(.memori-tooltip--disabled):not(.memori-tooltip--visible):hover .memori-tooltip--content {
|
|
100
|
+
transform: translateY(-150%) translateX(33%);
|
|
101
|
+
}
|
|
102
|
+
|
|
72
103
|
.memori-tooltip:not(.memori-tooltip--disabled).memori-tooltip--visible .memori-tooltip--content a,
|
|
73
104
|
.memori-tooltip:not(.memori-tooltip--disabled):not(.memori-tooltip--visible):hover .memori-tooltip--content a {
|
|
74
105
|
color: #fff;
|
|
@@ -77,4 +108,4 @@
|
|
|
77
108
|
|
|
78
109
|
.memori-tooltip.memori-tooltip--disabled {
|
|
79
110
|
cursor: not-allowed;
|
|
80
|
-
}
|
|
111
|
+
}
|
|
@@ -20,9 +20,21 @@ const meta: Meta = {
|
|
|
20
20
|
|
|
21
21
|
export default meta;
|
|
22
22
|
|
|
23
|
-
const Template: Story<Props> = args =>
|
|
23
|
+
const Template: Story<Props> = args => (
|
|
24
|
+
<div
|
|
25
|
+
style={{
|
|
26
|
+
display: 'flex',
|
|
27
|
+
justifyContent: 'flex-start',
|
|
28
|
+
paddingTop: '10rem',
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<Tooltip {...args} />
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
24
34
|
const TemplateRight: Story<Props> = args => (
|
|
25
|
-
<div
|
|
35
|
+
<div
|
|
36
|
+
style={{ display: 'flex', justifyContent: 'flex-end', paddingTop: '10rem' }}
|
|
37
|
+
>
|
|
26
38
|
<Tooltip {...args} />
|
|
27
39
|
</div>
|
|
28
40
|
);
|
|
@@ -68,5 +80,30 @@ export const AlignLeft = TemplateRight.bind({});
|
|
|
68
80
|
AlignLeft.args = {
|
|
69
81
|
content: 'Here is some tooltip content',
|
|
70
82
|
children: <span>Hover me</span>,
|
|
71
|
-
|
|
83
|
+
align: 'left',
|
|
84
|
+
visible: true,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const AlignRight = Template.bind({});
|
|
88
|
+
AlignRight.args = {
|
|
89
|
+
content: 'Here is some tooltip content',
|
|
90
|
+
children: <span>Hover me</span>,
|
|
91
|
+
align: 'right',
|
|
92
|
+
visible: true,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const AlignTopLeft = TemplateRight.bind({});
|
|
96
|
+
AlignTopLeft.args = {
|
|
97
|
+
content: 'Here is some tooltip content',
|
|
98
|
+
children: <span>Hover me</span>,
|
|
99
|
+
align: 'topLeft',
|
|
100
|
+
visible: true,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const AlignTopRight = Template.bind({});
|
|
104
|
+
AlignTopRight.args = {
|
|
105
|
+
content: 'Here is some tooltip content',
|
|
106
|
+
children: <span>Hover me</span>,
|
|
107
|
+
align: 'topRight',
|
|
108
|
+
visible: true,
|
|
72
109
|
};
|
|
@@ -48,3 +48,55 @@ it('renders Tooltip visible unchanged', () => {
|
|
|
48
48
|
);
|
|
49
49
|
expect(container).toMatchSnapshot();
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
it('renders Tooltip aligned left unchanged', () => {
|
|
53
|
+
const { container } = render(
|
|
54
|
+
<Tooltip
|
|
55
|
+
content="Here is some tooltip content by default as I am controlled"
|
|
56
|
+
visible
|
|
57
|
+
align="left"
|
|
58
|
+
>
|
|
59
|
+
Hover me
|
|
60
|
+
</Tooltip>
|
|
61
|
+
);
|
|
62
|
+
expect(container).toMatchSnapshot();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('renders Tooltip aligned top left unchanged', () => {
|
|
66
|
+
const { container } = render(
|
|
67
|
+
<Tooltip
|
|
68
|
+
content="Here is some tooltip content by default as I am controlled"
|
|
69
|
+
visible
|
|
70
|
+
align="topLeft"
|
|
71
|
+
>
|
|
72
|
+
Hover me
|
|
73
|
+
</Tooltip>
|
|
74
|
+
);
|
|
75
|
+
expect(container).toMatchSnapshot();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('renders Tooltip aligned right unchanged', () => {
|
|
79
|
+
const { container } = render(
|
|
80
|
+
<Tooltip
|
|
81
|
+
content="Here is some tooltip content by default as I am controlled"
|
|
82
|
+
visible
|
|
83
|
+
align="right"
|
|
84
|
+
>
|
|
85
|
+
Hover me
|
|
86
|
+
</Tooltip>
|
|
87
|
+
);
|
|
88
|
+
expect(container).toMatchSnapshot();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('renders Tooltip aligned top right unchanged', () => {
|
|
92
|
+
const { container } = render(
|
|
93
|
+
<Tooltip
|
|
94
|
+
content="Here is some tooltip content by default as I am controlled"
|
|
95
|
+
visible
|
|
96
|
+
align="topRight"
|
|
97
|
+
>
|
|
98
|
+
Hover me
|
|
99
|
+
</Tooltip>
|
|
100
|
+
);
|
|
101
|
+
expect(container).toMatchSnapshot();
|
|
102
|
+
});
|
|
@@ -4,7 +4,8 @@ import cx from 'classnames';
|
|
|
4
4
|
export interface Props {
|
|
5
5
|
content: string | JSX.Element | React.ReactNode;
|
|
6
6
|
className?: string;
|
|
7
|
-
|
|
7
|
+
align?: 'left' | 'right' | 'topLeft' | 'topRight';
|
|
8
|
+
alignTop?: boolean;
|
|
8
9
|
disabled?: boolean;
|
|
9
10
|
children: React.ReactNode;
|
|
10
11
|
visible?: boolean;
|
|
@@ -13,17 +14,21 @@ export interface Props {
|
|
|
13
14
|
const Tooltip: FC<Props> = ({
|
|
14
15
|
content,
|
|
15
16
|
className,
|
|
16
|
-
|
|
17
|
+
align = 'right',
|
|
17
18
|
disabled = false,
|
|
18
19
|
visible = false,
|
|
19
20
|
children,
|
|
20
21
|
}) => (
|
|
21
22
|
<div
|
|
22
|
-
className={cx(
|
|
23
|
-
'memori-tooltip
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
className={cx(
|
|
24
|
+
'memori-tooltip',
|
|
25
|
+
`memori-tooltip--align-${align}`,
|
|
26
|
+
className,
|
|
27
|
+
{
|
|
28
|
+
'memori-tooltip--disabled': disabled,
|
|
29
|
+
'memori-tooltip--visible': visible,
|
|
30
|
+
}
|
|
31
|
+
)}
|
|
27
32
|
>
|
|
28
33
|
<div className="memori-tooltip--content">{content}</div>
|
|
29
34
|
<div className="memori-tooltip--trigger">{children}</div>
|