@flozy/editor 3.7.7 → 3.7.9

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.
@@ -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"