@flozy/editor 3.7.7 → 3.7.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback, useMemo, useRef, useState, useEffect, useImperativeHandle, forwardRef } from "react";
2
2
  import { Editable, Slate, ReactEditor } from 'slate-react';
3
- import { createEditor } from 'slate';
3
+ import { createEditor, Transforms } from 'slate';
4
4
  import { useDebounce } from "use-debounce";
5
5
  import withCommon from "./hooks/withCommon";
6
6
  import { getBlock, getMarked } from "./utils/chatEditor/SlateUtilityFunctions";
@@ -26,7 +26,8 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
26
26
  needLayout = false,
27
27
  toolBar = true,
28
28
  onSave,
29
- onsubmit
29
+ onsubmit,
30
+ onBlur = () => {}
30
31
  } = props;
31
32
  const classes = usePopupStyle(theme);
32
33
  const convertedContent = draftToSlate({
@@ -36,6 +37,7 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
36
37
  const [value, setValue] = useState(convertedContent);
37
38
  const [loadedValue] = useState(value);
38
39
  const [deboundedValue] = useDebounce(value, 500);
40
+ const [isExternalUpdate, setIsExternalUpdate] = useState(false);
39
41
  const editor = useMemo(() => {
40
42
  return withCommon(createEditor(), {
41
43
  needLayout
@@ -46,17 +48,60 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
46
48
  emojiClick: emoji => {
47
49
  if (editor) {
48
50
  insertEmoji(editor, emoji?.native, editor.selection);
51
+ if (editor.selection) {
52
+ // const path = editor.selection.anchor.path;
53
+ // const offset = editor.selection.anchor.offset + emoji?.native.length;
54
+ const position = {
55
+ anchor: {
56
+ path: [0],
57
+ offset: 0
58
+ },
59
+ focus: {
60
+ path: [0],
61
+ offset: 0
62
+ }
63
+ };
64
+ // Create a new selection
65
+ Transforms.select(editor, position);
66
+ }
49
67
  ReactEditor.focus(editor);
50
68
  }
51
69
  },
70
+ setContent: newContent => {
71
+ setIsExternalUpdate(true);
72
+ setValue(newContent);
73
+ ReactEditor.focus(editor);
74
+ },
52
75
  // Focus enable
53
- enableFocus: () => {
54
- if (editor) {
55
- ReactEditor.focus(editor);
76
+ // enableFocus: () => {
77
+ // if (editor) {
78
+ // const position = {
79
+ // anchor: { path: [0], offset: 0 },
80
+ // focus: { path: [0], offset: 0 },
81
+ // };
82
+ // Transforms.select(editor, position);
83
+ // ReactEditor.focus(editor);
84
+ // }
85
+ // },
86
+
87
+ clearAll: () => {
88
+ if (!editor) return;
89
+ while (editor.children.length > 0) {
90
+ Transforms.removeNodes(editor, {
91
+ at: [0]
92
+ });
56
93
  }
94
+ Transforms.insertNodes(editor, {
95
+ type: 'paragraph',
96
+ children: [{
97
+ text: ''
98
+ }]
99
+ });
100
+ ReactEditor.focus(editor);
57
101
  }
58
102
  }));
59
103
  useEffect(() => {
104
+ setIsExternalUpdate(true);
60
105
  setValue(draftToSlate({
61
106
  data: content
62
107
  }));
@@ -123,9 +168,14 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
123
168
  });
124
169
  };
125
170
  const handleEditorChange = newValue => {
126
- setValue(newValue);
127
- if (!isInteracted) {
128
- setIsInteracted(true);
171
+ if (isExternalUpdate) {
172
+ setIsExternalUpdate(false);
173
+ return;
174
+ } else {
175
+ setValue(newValue);
176
+ if (!isInteracted) {
177
+ setIsInteracted(true);
178
+ }
129
179
  }
130
180
  };
131
181
  const Element = props => {
@@ -162,18 +212,36 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
162
212
  event,
163
213
  editor
164
214
  });
165
- } else if (event.key === "Enter" && !event.shiftKey) {
166
- const {
167
- value: strVal,
168
- ...restVal
169
- } = getOnSaveData(value);
170
- onsubmit(false, {
171
- strVal,
172
- restVal
173
- });
215
+ } else if (event.key === "Enter") {
216
+ const isEmpty = value.length === 1 && value[0].type === 'paragraph' && value[0].children.length === 1 && value[0].children[0].text === '';
217
+ if (isEmpty) {
218
+ event.preventDefault();
219
+ return;
220
+ }
221
+ if (!event.shiftKey) {
222
+ const {
223
+ value: strVal,
224
+ ...restVal
225
+ } = getOnSaveData(value);
226
+ onsubmit(false, {
227
+ strVal,
228
+ restVal
229
+ });
230
+ event.preventDefault();
231
+ }
174
232
  }
175
233
  }, [chars, editor, target, mentions, setMentions, search, type, mentionsRef]);
176
234
  const handleClose = () => {};
235
+ const handleBlur = () => {
236
+ const {
237
+ value: strVal,
238
+ ...restVal
239
+ } = getOnSaveData(value);
240
+ onBlur({
241
+ strVal,
242
+ restVal
243
+ });
244
+ };
177
245
  return /*#__PURE__*/_jsx(EditorProvider, {
178
246
  theme: theme,
179
247
  editor: editor,
@@ -192,6 +260,7 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
192
260
  placeholder: "Start typing ...",
193
261
  spellCheck: true,
194
262
  autoFocus: true,
263
+ onBlur: handleBlur,
195
264
  onKeyDown: onKeyDown
196
265
  }), !readOnly ? /*#__PURE__*/_jsx(MentionsPopup, {
197
266
  ref: mentionsRef,
@@ -11,6 +11,8 @@ import CustomSelect from "./CustomSelect";
11
11
  import { editContentOptions, newContentOptions, generatedContentOptions } from "./helper";
12
12
  import useClickOutside from "../../hooks/useClickOutside";
13
13
  import { useEditorContext } from "../../hooks/useMouseMove";
14
+ // import { VoiceToText } from "./VoiceToText";
15
+ import { ChatMicIcon } from "../../assets/svg/AIIcons";
14
16
  import { jsx as _jsx } from "react/jsx-runtime";
15
17
  import { jsxs as _jsxs } from "react/jsx-runtime";
16
18
  import { Fragment as _Fragment } from "react/jsx-runtime";
@@ -36,12 +38,13 @@ function getProps(openAI, generatedText) {
36
38
  }
37
39
  function AIInput({
38
40
  onSend,
39
- loading,
40
41
  generatedText,
41
42
  openAI,
42
43
  inputValue,
43
44
  onInputChange,
44
- onClickOutside
45
+ onClickOutside,
46
+ startRecording,
47
+ ...rest
45
48
  }, ref) {
46
49
  const {
47
50
  theme
@@ -67,6 +70,7 @@ function AIInput({
67
70
  clearTimeout(timeoutId);
68
71
  };
69
72
  }, [openAI]);
73
+ const loading = rest?.loading || rest?.isAILoading;
70
74
  const isSendBtnDisabled = !inputValue || loading;
71
75
  const props = getProps(openAI, generatedText) || {};
72
76
  const fromToolBar = openAI === "fromToolBar";
@@ -132,18 +136,25 @@ function AIInput({
132
136
  handleSendBtnClick();
133
137
  }
134
138
  }
135
- }), fromToolBar ? null : /*#__PURE__*/_jsx(Box, {
139
+ }), fromToolBar ? null : /*#__PURE__*/_jsxs(Box, {
136
140
  component: "div",
137
141
  style: classes.sendIconContainer,
138
142
  className: "icons-elements",
139
- children: /*#__PURE__*/_jsx(IconButton, {
143
+ children: [/*#__PURE__*/_jsx(IconButton
144
+ // sx={
145
+ // isSendBtnDisabled ? classes.sendBtnDisabled : classes.sendBtn
146
+ // }
147
+ , {
148
+ onClick: () => startRecording(),
149
+ children: /*#__PURE__*/_jsx(ChatMicIcon, {})
150
+ }), /*#__PURE__*/_jsx(IconButton, {
140
151
  sx: isSendBtnDisabled ? classes.sendBtnDisabled : classes.sendBtn,
141
152
  onClick: () => handleSendBtnClick(),
142
153
  children: /*#__PURE__*/_jsx(IoSend, {
143
154
  color: "#fff",
144
155
  size: 14
145
156
  })
146
- })
157
+ })]
147
158
  })]
148
159
  })]
149
160
  }), size.device === "xs" ? null : /*#__PURE__*/_jsx(Box, {
@@ -8,6 +8,7 @@ import { Editor, Node, Path, Transforms } from "slate";
8
8
  import useWindowResize from "../../hooks/useWindowResize";
9
9
  import { MODES } from "./helper";
10
10
  import { getSelectedText } from "../../utils/helper";
11
+ import { VoiceToText } from "./VoiceToText";
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  import { jsxs as _jsxs } from "react/jsx-runtime";
13
14
  const scrollToAIInput = () => {
@@ -178,6 +179,11 @@ function PopoverAIInput({
178
179
  onClickOutside();
179
180
  return;
180
181
  }
182
+ if (type === "speech_to_text") {
183
+ Transforms.insertText(editor, option.text);
184
+ onClickOutside();
185
+ return;
186
+ }
181
187
  if (type === "try_again") {
182
188
  // resetting the previous option and try again
183
189
  option = selectedOption;
@@ -188,7 +194,7 @@ function PopoverAIInput({
188
194
  setLoading(true);
189
195
  const payload = {
190
196
  mode: option.mode || 0,
191
- query: inputValue
197
+ query: option?.inputValue || inputValue
192
198
  };
193
199
  if (option.mode === MODES.translate || option.mode === MODES.rephraseTone) {
194
200
  payload.textOptionInput = type;
@@ -267,15 +273,19 @@ function PopoverAIInput({
267
273
  component: "div",
268
274
  sx: classes.mobileAIInputWrapper,
269
275
  ref: targetRef,
270
- children: /*#__PURE__*/_jsx(AIInput, {
271
- loading: loading,
276
+ children: /*#__PURE__*/_jsx(VoiceToText, {
277
+ otherProps: otherProps,
272
278
  onSend: onSend,
273
- generatedText: generatedText,
274
- anchorEl: anchorEl,
275
- openAI: openAI,
276
- inputValue: inputValue,
277
- onInputChange: onInputChange,
278
- onClickOutside: onClickOutside
279
+ children: /*#__PURE__*/_jsx(AIInput, {
280
+ loading: loading,
281
+ onSend: onSend,
282
+ generatedText: generatedText,
283
+ anchorEl: anchorEl,
284
+ openAI: openAI,
285
+ inputValue: inputValue,
286
+ onInputChange: onInputChange,
287
+ onClickOutside: onClickOutside
288
+ })
279
289
  })
280
290
  }) : /*#__PURE__*/_jsx(Popper, {
281
291
  open: Boolean(openAI),
@@ -296,15 +306,19 @@ function PopoverAIInput({
296
306
  sx: getSelectedText(editor) ? {
297
307
  marginTop: "6px"
298
308
  } : {},
299
- children: /*#__PURE__*/_jsx(AIInput, {
300
- loading: loading,
309
+ children: /*#__PURE__*/_jsx(VoiceToText, {
310
+ otherProps: otherProps,
301
311
  onSend: onSend,
302
- generatedText: generatedText,
303
- anchorEl: anchorEl,
304
- openAI: openAI,
305
- inputValue: inputValue,
306
- onInputChange: onInputChange,
307
- onClickOutside: onClickOutside
312
+ children: /*#__PURE__*/_jsx(AIInput, {
313
+ loading: loading,
314
+ onSend: onSend,
315
+ generatedText: generatedText,
316
+ anchorEl: anchorEl,
317
+ openAI: openAI,
318
+ inputValue: inputValue,
319
+ onInputChange: onInputChange,
320
+ onClickOutside: onClickOutside
321
+ })
308
322
  })
309
323
  })
310
324
  })
@@ -167,7 +167,8 @@ const Styles = theme => ({
167
167
  sendIconContainer: {
168
168
  alignSelf: "flex-end",
169
169
  display: "flex",
170
- alignItems: "center"
170
+ alignItems: "center",
171
+ gap: "6px"
171
172
  }
172
173
  });
173
174
  export default Styles;
@@ -0,0 +1,73 @@
1
+ import { Box } from "@mui/material";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import WaveSurfer from "wavesurfer.js";
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ const SoundWave = props => {
6
+ const {
7
+ audioChunks = null
8
+ } = props; // Initialize to null if not provided
9
+ const waveContent = useRef(null);
10
+ const wavesurfer = useRef(null);
11
+ const [playOnce, setPlayOnce] = useState(false);
12
+ useEffect(() => {
13
+ if (waveContent.current) {
14
+ if (wavesurfer.current) {
15
+ wavesurfer.current.destroy();
16
+ }
17
+ wavesurfer.current = WaveSurfer.create({
18
+ container: waveContent.current,
19
+ waveColor: "#2563EB",
20
+ progressColor: "#2563EB",
21
+ cursorWidth: 0,
22
+ // Disable the cursor
23
+ barWidth: 2,
24
+ barGap: 1,
25
+ barRadius: 2,
26
+ scrollParent: false,
27
+ // Prevent scrolling
28
+ height: waveContent.current.clientHeight // Set height to fit container
29
+ });
30
+
31
+ // Fit the waveform to the container width
32
+ const resize = () => {
33
+ if (wavesurfer.current) {
34
+ const containerWidth = waveContent.current.clientWidth;
35
+ const duration = wavesurfer.current.getDuration();
36
+ if (duration > 0) {
37
+ const newZoom = containerWidth / duration;
38
+ wavesurfer.current.zoom(newZoom);
39
+ }
40
+ }
41
+ };
42
+ window.addEventListener("resize", resize);
43
+ resize();
44
+ return () => {
45
+ window.removeEventListener("resize", resize);
46
+ };
47
+ }
48
+ }, []);
49
+ useEffect(() => {
50
+ if (wavesurfer.current && audioChunks) {
51
+ const audioBlob = new Blob(audioChunks, {
52
+ type: "audio/webm"
53
+ });
54
+ const recordedUrl = URL.createObjectURL(audioBlob);
55
+ wavesurfer.current.load(recordedUrl).then().catch(e => console.error("Error loading audio: ", e));
56
+ if (!playOnce) {
57
+ setPlayOnce(true);
58
+ }
59
+ } else if (wavesurfer.current && !audioChunks) {
60
+ // Clear the waveform when audioChunks is null
61
+ wavesurfer.current.empty();
62
+ }
63
+ }, [audioChunks, playOnce]);
64
+ return /*#__PURE__*/_jsx(Box, {
65
+ ref: waveContent,
66
+ style: {
67
+ width: "100%",
68
+ height: "100%",
69
+ overflow: "hidden"
70
+ }
71
+ });
72
+ };
73
+ export const AudioWave = SoundWave;
@@ -0,0 +1,167 @@
1
+ import { useState, useEffect, useRef, cloneElement } from "react";
2
+ import PropTypes from "prop-types";
3
+ import STTStyles from "./style";
4
+ import { Grid, IconButton, Box } from "@mui/material";
5
+ import { AudioWave } from "./AudioWave";
6
+ import { CloseGreyCircle, PauseRecordingIcon, TickBlueCircle } from "../../../assets/svg/AIIcons";
7
+ import { MODES } from "../helper";
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ import { jsxs as _jsxs } from "react/jsx-runtime";
10
+ function STT(props) {
11
+ const {
12
+ children,
13
+ otherProps,
14
+ onSend
15
+ } = props;
16
+ const {
17
+ services
18
+ } = otherProps;
19
+ const classes = STTStyles();
20
+ const [isRecording, setIsRecording] = useState(false);
21
+ const [mediaRecorder, setMediaRecorder] = useState(null);
22
+ const [audioChunks, setAudioChunks] = useState([]);
23
+ const [chunkIndex, setChunkIndex] = useState(0);
24
+ const audioChunksRef = useRef([]);
25
+ const [transcription, setTranscription] = useState("");
26
+ const [showPause, setShowPause] = useState(true);
27
+ const [isAILoading, setAILoading] = useState(false);
28
+ const setChunk = event => {
29
+ if (event.data.size > 0) {
30
+ setAudioChunks(prev => {
31
+ const updatedChunks = [...prev, event.data];
32
+ audioChunksRef.current = updatedChunks; // Update ref manually
33
+ return updatedChunks;
34
+ });
35
+ }
36
+ };
37
+ const sendChunck = async (isLast = false) => {
38
+ if (audioChunksRef.current.length > 0) {
39
+ const audioBlob = new Blob(audioChunksRef.current, {
40
+ type: "audio/webm"
41
+ });
42
+ const formData = new FormData();
43
+ formData.append("audio", audioBlob, `audio_chunk_${chunkIndex}.wav`);
44
+ formData.append("chunkIndex", chunkIndex); // Send chunk index to the backend
45
+ if (isLast) {
46
+ formData.append("isLastChunk", true); // Send chunk index to the backend
47
+ } else {
48
+ formData.append("isLastChunk", false);
49
+ setChunkIndex(prevIndex => prevIndex + 1);
50
+ }
51
+ const result = await services("speechToText", {
52
+ formData
53
+ });
54
+ setTranscription(result?.data);
55
+ await sendChunck();
56
+ }
57
+ };
58
+ const handleStopRecording = () => {
59
+ sendChunck(true);
60
+ setAudioChunks([]);
61
+ };
62
+ const startRecording = async () => {
63
+ setTranscription("");
64
+ const stream = await navigator.mediaDevices.getUserMedia({
65
+ audio: true
66
+ });
67
+ const recorder = new MediaRecorder(stream);
68
+ setMediaRecorder(recorder);
69
+ recorder.ondataavailable = setChunk;
70
+ recorder.onstop = handleStopRecording;
71
+ recorder.start(100);
72
+ setIsRecording(true);
73
+ setTimeout(() => {
74
+ sendChunck();
75
+ }, 2000);
76
+ };
77
+ const stopRecording = () => {
78
+ if (mediaRecorder) {
79
+ mediaRecorder.stop();
80
+
81
+ // Stop all tracks to release the microphone
82
+ if (mediaRecorder.stream) {
83
+ mediaRecorder.stream.getTracks().forEach(track => track.stop());
84
+ }
85
+ setChunkIndex(0);
86
+ setShowPause(false);
87
+ }
88
+ };
89
+ const sendToInfiniti = async () => {
90
+ setAILoading(true);
91
+ setIsRecording(false);
92
+ const result = await services("infinityAI", {
93
+ mode: MODES.default,
94
+ query: transcription
95
+ });
96
+ const text = result?.data || "";
97
+ onSend("speech_to_text", {
98
+ text
99
+ });
100
+ stopRecording();
101
+ setAILoading(false);
102
+ };
103
+ const closeRecording = () => {
104
+ setAudioChunks([]);
105
+ stopRecording();
106
+ setIsRecording(false);
107
+ setShowPause(true);
108
+ setTranscription("");
109
+ };
110
+ useEffect(() => {
111
+ audioChunksRef.current = audioChunks;
112
+ }, [audioChunks]);
113
+ return /*#__PURE__*/_jsx(Grid, {
114
+ xs: 12,
115
+ children: /*#__PURE__*/_jsx(Grid, {
116
+ className: classes.SttContainer,
117
+ children: !isRecording ? /*#__PURE__*/_jsx(Grid, {
118
+ xs: 12,
119
+ children: /*#__PURE__*/cloneElement(children, {
120
+ startRecording,
121
+ isAILoading
122
+ })
123
+ }) : /*#__PURE__*/_jsxs(Grid, {
124
+ xs: 12,
125
+ sx: classes.AudioVizualizerContainer,
126
+ children: [transcription ? /*#__PURE__*/_jsx(Grid, {
127
+ xs: 12,
128
+ sx: classes.TranscriptionContainer,
129
+ children: transcription
130
+ }) : null, /*#__PURE__*/_jsxs(Grid, {
131
+ xs: 12,
132
+ sx: classes.AudioVizualizerContent,
133
+ children: [/*#__PURE__*/_jsx(Box, {
134
+ children: /*#__PURE__*/_jsx(IconButton, {
135
+ onClick: closeRecording,
136
+ children: /*#__PURE__*/_jsx(CloseGreyCircle, {})
137
+ })
138
+ }), /*#__PURE__*/_jsx(Box, {
139
+ sx: classes.AudioVisualiser,
140
+ children: /*#__PURE__*/_jsx(AudioWave, {
141
+ audioChunks: audioChunks
142
+ })
143
+ }), /*#__PURE__*/_jsx(Box, {
144
+ children: showPause ? /*#__PURE__*/_jsx(IconButton, {
145
+ onClick: stopRecording,
146
+ children: /*#__PURE__*/_jsx(PauseRecordingIcon, {})
147
+ }) : /*#__PURE__*/_jsx(IconButton, {
148
+ onClick: sendToInfiniti,
149
+ disabled: !transcription,
150
+ style: !transcription ? {
151
+ opacity: 0.5
152
+ } : {},
153
+ children: /*#__PURE__*/_jsx(TickBlueCircle, {})
154
+ })
155
+ })]
156
+ })]
157
+ })
158
+ })
159
+ });
160
+ }
161
+ STT.defaultProps = {
162
+ classes: {}
163
+ };
164
+ STT.propTypes = {
165
+ classes: PropTypes.object
166
+ };
167
+ export const VoiceToText = STT;
@@ -0,0 +1,40 @@
1
+ const styles = () => ({
2
+ SttContainer: {
3
+ display: "flex",
4
+ width: "100%",
5
+ padding: "12px",
6
+ zIndex: 1
7
+ },
8
+ STTInput: {
9
+ width: "100%",
10
+ borderRadius: "8px",
11
+ "&& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline": {
12
+ borderColor: "#2563EB"
13
+ },
14
+ "&& .MuiOutlinedInput-root": {
15
+ background: "rgba(252, 250, 255, 1)"
16
+ }
17
+ },
18
+ AudioVizualizerContainer: {
19
+ width: "100%",
20
+ display: "flex",
21
+ background: "rgba(252, 250, 255, 1)",
22
+ borderRadius: "8px",
23
+ border: "1px solid #2563EB",
24
+ alignItems: "center",
25
+ flexWrap: "wrap"
26
+ },
27
+ AudioVizualizerContent: {
28
+ display: "flex",
29
+ height: "50px",
30
+ width: "100%"
31
+ },
32
+ AudioVisualiser: {
33
+ flexGrow: "1",
34
+ height: "100%"
35
+ },
36
+ TranscriptionContainer: {
37
+ padding: "12px"
38
+ }
39
+ });
40
+ export default styles;
@@ -232,13 +232,15 @@ const EditorButton = props => {
232
232
  style: {
233
233
  paddingLeft: "4px",
234
234
  paddingRight: "4px"
235
- }
235
+ },
236
+ props: customProps
236
237
  }), label || "My Button", BtnIcon && iconPosition === "end" && /*#__PURE__*/_jsx(MUIIcon, {
237
238
  iconName: buttonIcon,
238
239
  style: {
239
240
  paddingLeft: "4px",
240
241
  paddingRight: "4px"
241
- }
242
+ },
243
+ props: customProps
242
244
  })]
243
245
  }), !readOnly && isTrigger ? /*#__PURE__*/_jsx(IconButton, {
244
246
  className: "workflow-icon-btn",
@@ -89,7 +89,8 @@ const ChipText = props => {
89
89
  display: "inline-block",
90
90
  verticalAlign: "middle"
91
91
  },
92
- onClick: handleStyle
92
+ onClick: handleStyle,
93
+ props: customProps
93
94
  }), /*#__PURE__*/_jsx("div", {
94
95
  contentEditable: false,
95
96
  style: {
@@ -71,11 +71,11 @@ const FormWorkflow = props => {
71
71
  children: [/*#__PURE__*/_jsx(Grid, {
72
72
  item: true,
73
73
  sx: classes.radioBtn,
74
- children: /*#__PURE__*/_jsxs(RadioGroup, {
74
+ children: /*#__PURE__*/_jsx(RadioGroup, {
75
75
  name: "set timing",
76
76
  value: schedule,
77
77
  defaultValue: 1,
78
- children: [/*#__PURE__*/_jsx(FormControlLabel, {
78
+ children: /*#__PURE__*/_jsx(FormControlLabel, {
79
79
  value: "immediately",
80
80
  label: "Immediately",
81
81
  onChange: () => {
@@ -84,16 +84,7 @@ const FormWorkflow = props => {
84
84
  control: /*#__PURE__*/_jsx(Radio, {
85
85
  size: "small"
86
86
  })
87
- }), /*#__PURE__*/_jsx(FormControlLabel, {
88
- value: "after",
89
- label: "After",
90
- onChange: () => {
91
- setSchedule("after");
92
- },
93
- control: /*#__PURE__*/_jsx(Radio, {
94
- size: "small"
95
- })
96
- })]
87
+ })
97
88
  })
98
89
  }), schedule === "after" && /*#__PURE__*/_jsx(Grid, {
99
90
  item: true,
@@ -183,7 +183,7 @@ const Table = props => {
183
183
  children: [/*#__PURE__*/_jsx(TableComp, {
184
184
  sx: classes.table,
185
185
  style: {
186
- backgroundColor: bgColor,
186
+ background: bgColor,
187
187
  border: `1px solid ${borderColor}`,
188
188
  width: "auto"
189
189
  },
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useState } from "react";
2
- import { Popper, Fade, Paper } from "@mui/material";
2
+ import { Popper, Fade, Paper, ClickAwayListener } from "@mui/material";
3
3
  import { Editor, Range } from "slate";
4
- import { useSlate, useFocused } from "slate-react";
4
+ import { useSlate } from "slate-react";
5
5
  import useDrag from "../../hooks/useDrag";
6
6
  import { TableUtil } from "../../utils/table";
7
7
  import useWindowResize from "../../hooks/useWindowResize";
@@ -9,7 +9,6 @@ import MiniTextFormat from "./MiniTextFormat";
9
9
  import { useEditorContext } from "../../hooks/useMouseMove";
10
10
  import usePopupStyles from "../PopupTool/PopupToolStyle";
11
11
  import { jsx as _jsx } from "react/jsx-runtime";
12
- import { Fragment as _Fragment } from "react/jsx-runtime";
13
12
  const PopupTool = props => {
14
13
  const {
15
14
  theme,
@@ -24,7 +23,6 @@ const PopupTool = props => {
24
23
  const [anchorEl, setAnchorEl] = useState(null);
25
24
  const [open, setOpen] = useState(false);
26
25
  const editor = useSlate();
27
- const inFocus = useFocused();
28
26
  const {
29
27
  selection
30
28
  } = editor;
@@ -32,11 +30,6 @@ const PopupTool = props => {
32
30
  const id = open ? "popup-edit-tool" : "";
33
31
  const table = new TableUtil(editor);
34
32
  const [size] = useWindowResize();
35
- useEffect(() => {
36
- if (!inFocus) {
37
- setAnchorEl(null);
38
- }
39
- }, [inFocus]);
40
33
  useEffect(() => {
41
34
  if (event === "end" && anchorEl && !open) {
42
35
  // for table cell selection
@@ -53,7 +46,7 @@ const PopupTool = props => {
53
46
  }
54
47
  }, [event, anchorEl]);
55
48
  useEffect(() => {
56
- if (!selection || !inFocus || Range.isCollapsed(selection) || Editor.string(editor, selection) === "") {
49
+ if (!selection || Range.isCollapsed(selection) || Editor.string(editor, selection) === "") {
57
50
  setAnchorEl(null);
58
51
  } else {
59
52
  updateAnchorEl();
@@ -84,7 +77,14 @@ const PopupTool = props => {
84
77
  setOpen(false);
85
78
  setPopupType("");
86
79
  };
87
- return open && !openAI ? /*#__PURE__*/_jsx(_Fragment, {
80
+ return open && !openAI ? /*#__PURE__*/_jsx(ClickAwayListener, {
81
+ onClickAway: e => {
82
+ // close the mini toolbar, if user clicks outside the editor (in Flozy app.)
83
+ if (e.target !== document.body) {
84
+ // e.target returns body, if the user clicks material ui select popup inside the tool bar, on that time, we don't need to close
85
+ handleClose();
86
+ }
87
+ },
88
88
  children: size.device === "xs" ? /*#__PURE__*/_jsx("div", {
89
89
  className: "mobileMiniTextWrapper",
90
90
  children: /*#__PURE__*/_jsx(MiniTextFormat, {
@@ -435,4 +435,156 @@ export function DeleteIcon(props) {
435
435
  strokeLinejoin: "round"
436
436
  })]
437
437
  });
438
- }
438
+ }
439
+ export const PauseRecordingIcon = () => /*#__PURE__*/_jsxs("svg", {
440
+ width: "30",
441
+ height: "30",
442
+ viewBox: "0 0 30 30",
443
+ fill: "none",
444
+ xmlns: "http://www.w3.org/2000/svg",
445
+ children: [/*#__PURE__*/_jsx("circle", {
446
+ cx: "15",
447
+ cy: "15",
448
+ r: "14.5",
449
+ fill: "white",
450
+ stroke: "url(#paint0_linear_29403_449555)"
451
+ }), /*#__PURE__*/_jsx("path", {
452
+ d: "M13.6916 21.125H10.8817C10.5953 21.125 10.3447 20.8744 10.3447 20.5881V9.84943C10.3447 9.54517 10.5953 9.3125 10.8817 9.3125H13.6916C13.932 9.3125 14.2285 9.54517 14.2285 9.84943V20.5881C14.2285 20.8744 13.932 21.125 13.6916 21.125Z",
453
+ fill: "url(#paint1_linear_29403_449555)"
454
+ }), /*#__PURE__*/_jsx("path", {
455
+ d: "M20.1346 21.125H17.3426C17.0383 21.125 16.8057 20.8744 16.8057 20.5881V9.84943C16.8057 9.54517 17.0383 9.3125 17.3426 9.3125H20.1525C20.4568 9.3125 20.6895 9.54517 20.6895 9.84943V20.5881C20.6716 20.8744 20.4389 21.125 20.1346 21.125Z",
456
+ fill: "url(#paint2_linear_29403_449555)"
457
+ }), /*#__PURE__*/_jsxs("defs", {
458
+ children: [/*#__PURE__*/_jsxs("linearGradient", {
459
+ id: "paint0_linear_29403_449555",
460
+ x1: "15",
461
+ y1: "0",
462
+ x2: "15",
463
+ y2: "30",
464
+ gradientUnits: "userSpaceOnUse",
465
+ children: [/*#__PURE__*/_jsx("stop", {
466
+ stopColor: "#8061FD"
467
+ }), /*#__PURE__*/_jsx("stop", {
468
+ offset: "1",
469
+ stopColor: "#2C64ED"
470
+ })]
471
+ }), /*#__PURE__*/_jsxs("linearGradient", {
472
+ id: "paint1_linear_29403_449555",
473
+ x1: "12.2866",
474
+ y1: "9.3125",
475
+ x2: "12.2866",
476
+ y2: "21.125",
477
+ gradientUnits: "userSpaceOnUse",
478
+ children: [/*#__PURE__*/_jsx("stop", {
479
+ stopColor: "#8161FD"
480
+ }), /*#__PURE__*/_jsx("stop", {
481
+ offset: "1",
482
+ stopColor: "#2A64EC"
483
+ })]
484
+ }), /*#__PURE__*/_jsxs("linearGradient", {
485
+ id: "paint2_linear_29403_449555",
486
+ x1: "18.7476",
487
+ y1: "9.3125",
488
+ x2: "18.7476",
489
+ y2: "21.125",
490
+ gradientUnits: "userSpaceOnUse",
491
+ children: [/*#__PURE__*/_jsx("stop", {
492
+ stopColor: "#8161FD"
493
+ }), /*#__PURE__*/_jsx("stop", {
494
+ offset: "1",
495
+ stopColor: "#2A64EC"
496
+ })]
497
+ })]
498
+ })]
499
+ });
500
+ export const CloseGreyCircle = () => /*#__PURE__*/_jsxs("svg", {
501
+ width: "30",
502
+ height: "30",
503
+ viewBox: "0 0 30 30",
504
+ fill: "none",
505
+ xmlns: "http://www.w3.org/2000/svg",
506
+ children: [/*#__PURE__*/_jsx("rect", {
507
+ width: "30",
508
+ height: "30",
509
+ rx: "15",
510
+ fill: "#DAE4ED"
511
+ }), /*#__PURE__*/_jsx("path", {
512
+ d: "M19.1245 10.875L10.8749 19.1246",
513
+ stroke: "#2563EB",
514
+ strokeWidth: "1.5",
515
+ strokeLinecap: "round",
516
+ strokeLinejoin: "round"
517
+ }), /*#__PURE__*/_jsx("path", {
518
+ d: "M10.875 10.875L19.1246 19.1246",
519
+ stroke: "#2563EB",
520
+ strokeWidth: "1.5",
521
+ strokeLinecap: "round",
522
+ strokeLinejoin: "round"
523
+ })]
524
+ });
525
+ export const TickBlueCircle = () => /*#__PURE__*/_jsxs("svg", {
526
+ width: "30",
527
+ height: "30",
528
+ viewBox: "0 0 30 30",
529
+ fill: "none",
530
+ xmlns: "http://www.w3.org/2000/svg",
531
+ children: [/*#__PURE__*/_jsx("rect", {
532
+ width: "30",
533
+ height: "30",
534
+ rx: "15",
535
+ fill: "url(#paint0_linear_30220_64249)"
536
+ }), /*#__PURE__*/_jsx("path", {
537
+ d: "M9 15L13.0011 19L21 11",
538
+ stroke: "white",
539
+ strokeWidth: "1.5",
540
+ strokeLinecap: "round",
541
+ strokeLinejoin: "round"
542
+ }), /*#__PURE__*/_jsx("defs", {
543
+ children: /*#__PURE__*/_jsxs("linearGradient", {
544
+ id: "paint0_linear_30220_64249",
545
+ x1: "15",
546
+ y1: "0",
547
+ x2: "15",
548
+ y2: "30",
549
+ gradientUnits: "userSpaceOnUse",
550
+ children: [/*#__PURE__*/_jsx("stop", {
551
+ stopColor: "#8360FD"
552
+ }), /*#__PURE__*/_jsx("stop", {
553
+ offset: "1",
554
+ stopColor: "#2563EB"
555
+ })]
556
+ })
557
+ })]
558
+ });
559
+ export const ChatMicIcon = props => /*#__PURE__*/_jsxs("svg", {
560
+ width: "26",
561
+ height: "26",
562
+ viewBox: "0 0 26 26",
563
+ fill: "none",
564
+ xmlns: "http://www.w3.org/2000/svg",
565
+ children: [/*#__PURE__*/_jsx("path", {
566
+ d: "M13 19.3194C15.9882 19.3194 18.4166 16.8909 18.4166 13.9028V9.38887C18.4166 6.40067 15.9882 3.9722 13 3.9722C10.0118 3.9722 7.58331 6.40067 7.58331 9.38887V13.9028C7.58331 16.8909 10.0118 19.3194 13 19.3194Z",
567
+ stroke: "#94A3B8",
568
+ strokeWidth: "1.4",
569
+ strokeLinecap: "round",
570
+ strokeLinejoin: "round"
571
+ }), /*#__PURE__*/_jsx("path", {
572
+ d: "M4.875 12.0972V13.9028C4.875 18.3896 8.51319 22.0278 13 22.0278C17.4868 22.0278 21.125 18.3896 21.125 13.9028V12.0972",
573
+ stroke: "#94A3B8",
574
+ strokeWidth: "1.4",
575
+ strokeLinecap: "round",
576
+ strokeLinejoin: "round"
577
+ }), /*#__PURE__*/_jsx("path", {
578
+ d: "M10.3913 8.91914C11.9982 8.33233 13.7496 8.33233 15.3565 8.91914",
579
+ stroke: "#94A3B8",
580
+ strokeWidth: "1.4",
581
+ strokeLinecap: "round",
582
+ strokeLinejoin: "round"
583
+ }), /*#__PURE__*/_jsx("path", {
584
+ d: "M11.2218 11.6295C12.3051 11.3316 13.4516 11.3316 14.535 11.6295",
585
+ stroke: "#94A3B8",
586
+ strokeWidth: "1.4",
587
+ strokeLinecap: "round",
588
+ strokeLinejoin: "round"
589
+ })]
590
+ });
@@ -1,9 +1,14 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
  import { Box } from "@mui/material";
3
3
  import { jsx as _jsx } from "react/jsx-runtime";
4
- const iconLoader = async iconName => {
4
+ const iconLoader = async (iconName, ...props) => {
5
5
  try {
6
- const iconResponse = await fetch(`${process.env.ICON_API}/icon/${iconName}`);
6
+ const [{
7
+ props: {
8
+ ICON_API
9
+ }
10
+ }] = props;
11
+ const iconResponse = await fetch(`${ICON_API}/icon/${iconName}`);
7
12
  const icon = await iconResponse.text();
8
13
  return icon;
9
14
  } catch (error) {
@@ -19,7 +24,7 @@ const DynamicIcon = ({
19
24
  const [icon, setIcon] = useState("");
20
25
  useEffect(() => {
21
26
  let mounted = true;
22
- iconLoader(iconName).then(iconHTML => {
27
+ iconLoader(iconName, props).then(iconHTML => {
23
28
  if (mounted) {
24
29
  setIcon(iconHTML);
25
30
  }
@@ -10,7 +10,7 @@ const usePopupStyles = theme => ({
10
10
  papper: {
11
11
  boxShadow: "none",
12
12
  width: "300px",
13
- height: "auto",
13
+ maxHeight: "300px",
14
14
  overflow: "auto",
15
15
  padding: "8px",
16
16
  margin: "0px",
@@ -9,7 +9,8 @@ const Icons = props => {
9
9
  const {
10
10
  value,
11
11
  data,
12
- onChange
12
+ onChange,
13
+ customProps
13
14
  } = props;
14
15
  const {
15
16
  key
@@ -74,7 +75,8 @@ const Icons = props => {
74
75
  children: /*#__PURE__*/_jsx(IconButton, {
75
76
  onClick: onRemoveIcon,
76
77
  children: /*#__PURE__*/_jsx(MUIIcon, {
77
- iconName: value
78
+ iconName: value,
79
+ props: customProps
78
80
  })
79
81
  })
80
82
  }) : ""
@@ -96,7 +98,8 @@ const Icons = props => {
96
98
  children: /*#__PURE__*/_jsx(IconButton, {
97
99
  onClick: onSelectIcon(m),
98
100
  children: /*#__PURE__*/_jsx(MUIIcon, {
99
- iconName: m
101
+ iconName: m,
102
+ props: customProps
100
103
  })
101
104
  })
102
105
  }, `mui_ico_${m}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flozy/editor",
3
- "version": "3.7.7",
3
+ "version": "3.7.9",
4
4
  "description": "An Editor for flozy app brain",
5
5
  "files": [
6
6
  "dist"
@@ -46,6 +46,7 @@
46
46
  "slate-react": "^0.98.3",
47
47
  "styled-components": "^5.3.11",
48
48
  "use-debounce": "^10.0.0",
49
+ "wavesurfer.js": "^7.8.6",
49
50
  "web-vitals": "^2.1.4",
50
51
  "y-websocket": "^1.5.0",
51
52
  "yjs": "^13.6.8"