@flozy/editor 4.0.1 → 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. package/dist/Editor/ChatEditor.js +3 -19
  2. package/dist/Editor/CommonEditor.js +181 -109
  3. package/dist/Editor/Editor.css +31 -3
  4. package/dist/Editor/Elements/AI/AIInput.js +31 -33
  5. package/dist/Editor/Elements/AI/CustomSelect.js +19 -12
  6. package/dist/Editor/Elements/AI/PopoverAIInput.js +73 -97
  7. package/dist/Editor/Elements/AI/Styles.js +2 -2
  8. package/dist/Editor/Elements/AI/VoiceToText/AudioWave.js +73 -0
  9. package/dist/Editor/Elements/AI/VoiceToText/index.js +184 -0
  10. package/dist/Editor/Elements/AI/VoiceToText/style.js +40 -0
  11. package/dist/Editor/Elements/AI/helper.js +5 -3
  12. package/dist/Editor/Elements/Accordion/Accordion.js +1 -1
  13. package/dist/Editor/Elements/Accordion/AccordionSummary.js +5 -10
  14. package/dist/Editor/Elements/AppHeader/AppHeader.js +26 -4
  15. package/dist/Editor/Elements/Button/EditorButton.js +28 -16
  16. package/dist/Editor/Elements/Carousel/CarouselButton.js +2 -1
  17. package/dist/Editor/Elements/Color Picker/ColorButtons.js +60 -15
  18. package/dist/Editor/Elements/Color Picker/ColorPicker.css +25 -1
  19. package/dist/Editor/Elements/Color Picker/ColorPicker.js +4 -4
  20. package/dist/Editor/Elements/Color Picker/Styles.js +3 -1
  21. package/dist/Editor/Elements/Emoji/EmojiPicker.js +2 -4
  22. package/dist/Editor/Elements/Form/Workflow/FormWorkflow.js +12 -3
  23. package/dist/Editor/Elements/Form/Workflow/UserInputs.js +2 -1
  24. package/dist/Editor/Elements/Grid/Grid.js +27 -3
  25. package/dist/Editor/Elements/Grid/GridItem.js +3 -1
  26. package/dist/Editor/Elements/Link/Link.js +6 -1
  27. package/dist/Editor/Elements/Link/LinkButton.js +4 -2
  28. package/dist/Editor/Elements/Link/LinkPopup.js +73 -14
  29. package/dist/Editor/Elements/Link/LinkPopupStyles.js +28 -0
  30. package/dist/Editor/Elements/List/CheckList.js +1 -2
  31. package/dist/Editor/Elements/NewLine/NewLineButton.js +2 -1
  32. package/dist/Editor/Elements/PageSettings/PageSettingsButton.js +3 -3
  33. package/dist/Editor/Elements/Redo/RedoButton.js +14 -0
  34. package/dist/Editor/Elements/Signature/Signature.css +13 -6
  35. package/dist/Editor/Elements/Signature/SignatureOptions/UploadSignature.js +2 -1
  36. package/dist/Editor/Elements/Signature/SignaturePopup.js +185 -30
  37. package/dist/Editor/Elements/SimpleText/index.js +11 -1
  38. package/dist/Editor/Elements/SimpleText/style.js +1 -1
  39. package/dist/Editor/Elements/Table/Styles.js +23 -1
  40. package/dist/Editor/Elements/Table/Table.js +2 -1
  41. package/dist/Editor/Elements/Table/TableCell.js +69 -7
  42. package/dist/Editor/Elements/TableContextMenu/TableContextMenu.js +1 -0
  43. package/dist/Editor/Elements/Undo/UndoButton.js +14 -0
  44. package/dist/Editor/MiniEditor.js +3 -1
  45. package/dist/Editor/Styles/EditorStyles.js +1 -1
  46. package/dist/Editor/Toolbar/Basic/index.js +4 -2
  47. package/dist/Editor/Toolbar/FormatTools/Dropdown.js +27 -3
  48. package/dist/Editor/Toolbar/FormatTools/MarkButton.js +2 -2
  49. package/dist/Editor/Toolbar/FormatTools/TextSize.js +31 -20
  50. package/dist/Editor/Toolbar/Mini/MiniToolbar.js +36 -5
  51. package/dist/Editor/Toolbar/Mini/Options/Options.js +10 -0
  52. package/dist/Editor/Toolbar/Mini/Styles.js +7 -0
  53. package/dist/Editor/Toolbar/PopupTool/ButtonTemplatesCard.js +12 -13
  54. package/dist/Editor/Toolbar/PopupTool/FullViewCard.js +12 -13
  55. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/CustomSelectTool.js +3 -0
  56. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/SelectFontSize.js +4 -11
  57. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/SelectSuperSubscript.js +59 -0
  58. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/SelectTypography.js +213 -86
  59. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/index.js +4 -2
  60. package/dist/Editor/Toolbar/PopupTool/PopupToolStyle.js +123 -44
  61. package/dist/Editor/Toolbar/PopupTool/TextFormat.js +106 -44
  62. package/dist/Editor/Toolbar/PopupTool/ThemeTextFormat.js +438 -0
  63. package/dist/Editor/Toolbar/PopupTool/index.js +7 -6
  64. package/dist/Editor/Toolbar/toolbarGroups.js +53 -11
  65. package/dist/Editor/assets/svg/AIIcons.js +153 -1
  66. package/dist/Editor/assets/svg/AddTemplateIcon.js +13 -10
  67. package/dist/Editor/assets/svg/RedoIcon.js +27 -0
  68. package/dist/Editor/assets/svg/SettingsIcon.js +28 -0
  69. package/dist/Editor/assets/svg/TextIcon.js +8 -5
  70. package/dist/Editor/assets/svg/ThemeIcons.js +291 -0
  71. package/dist/Editor/assets/svg/UndoIcon.js +27 -0
  72. package/dist/Editor/common/ColorPickerButton.js +26 -18
  73. package/dist/Editor/common/CustomColorPicker/index.js +106 -0
  74. package/dist/Editor/common/CustomColorPicker/style.js +53 -0
  75. package/dist/Editor/common/CustomDialog/index.js +94 -0
  76. package/dist/Editor/common/CustomDialog/style.js +67 -0
  77. package/dist/Editor/common/CustomSelect.js +33 -0
  78. package/dist/Editor/common/DnD/DragHandleButton.js +56 -47
  79. package/dist/Editor/common/EditorIcons.js +7 -7
  80. package/dist/Editor/common/Icon.js +64 -25
  81. package/dist/Editor/common/ImageList.js +16 -3
  82. package/dist/Editor/common/ImageSelector/ImageSelector.js +30 -9
  83. package/dist/Editor/common/ImageSelector/Styles.js +2 -1
  84. package/dist/Editor/common/LinkSettings/NavComponents.js +5 -2
  85. package/dist/Editor/common/LinkSettings/index.js +4 -2
  86. package/dist/Editor/common/LinkSettings/navOptions.js +7 -2
  87. package/dist/Editor/common/LinkSettings/style.js +11 -8
  88. package/dist/Editor/common/MentionsPopup/Styles.js +1 -1
  89. package/dist/Editor/common/Section/index.js +57 -7
  90. package/dist/Editor/common/Section/styles.js +11 -0
  91. package/dist/Editor/common/Shorthands/elements.js +63 -9
  92. package/dist/Editor/common/StyleBuilder/accordionTitleBtnStyle.js +1 -2
  93. package/dist/Editor/common/StyleBuilder/buttonStyle.js +4 -2
  94. package/dist/Editor/common/StyleBuilder/fieldTypes/bannerSpacing.js +13 -3
  95. package/dist/Editor/common/StyleBuilder/fieldTypes/borderRadius.js +15 -7
  96. package/dist/Editor/common/StyleBuilder/fieldTypes/buttonLink.js +1 -1
  97. package/dist/Editor/common/StyleBuilder/fieldTypes/color.js +29 -7
  98. package/dist/Editor/common/StyleBuilder/fieldTypes/fontSize.js +13 -4
  99. package/dist/Editor/common/StyleBuilder/fieldTypes/textOptions.js +14 -4
  100. package/dist/Editor/common/StyleBuilder/index.js +1 -1
  101. package/dist/Editor/common/iconListV2.js +843 -0
  102. package/dist/Editor/common/iconslist.js +0 -31
  103. package/dist/Editor/commonStyle.js +6 -0
  104. package/dist/Editor/helper/index.js +0 -22
  105. package/dist/Editor/helper/theme.js +189 -3
  106. package/dist/Editor/hooks/useEditorTheme.js +139 -0
  107. package/dist/Editor/hooks/useMouseMove.js +4 -1
  108. package/dist/Editor/hooks/useWindowMessage.js +10 -7
  109. package/dist/Editor/plugins/withEmbeds.js +1 -1
  110. package/dist/Editor/plugins/withHTML.js +1 -1
  111. package/dist/Editor/plugins/withTable.js +1 -1
  112. package/dist/Editor/theme/ThemeList.js +50 -173
  113. package/dist/Editor/theme/index.js +144 -0
  114. package/dist/Editor/themeSettings/ActiveTheme.js +72 -0
  115. package/dist/Editor/themeSettings/buttons/index.js +290 -0
  116. package/dist/Editor/themeSettings/buttons/style.js +21 -0
  117. package/dist/Editor/themeSettings/colorTheme/index.js +290 -0
  118. package/dist/Editor/themeSettings/colorTheme/style.js +77 -0
  119. package/dist/Editor/themeSettings/fonts/PreviewElement.js +123 -0
  120. package/dist/Editor/themeSettings/fonts/index.js +213 -0
  121. package/dist/Editor/themeSettings/fonts/style.js +44 -0
  122. package/dist/Editor/themeSettings/icons.js +60 -0
  123. package/dist/Editor/themeSettings/index.js +320 -0
  124. package/dist/Editor/themeSettings/style.js +152 -0
  125. package/dist/Editor/themeSettingsAI/icons.js +96 -0
  126. package/dist/Editor/themeSettingsAI/index.js +356 -0
  127. package/dist/Editor/themeSettingsAI/saveTheme.js +190 -0
  128. package/dist/Editor/themeSettingsAI/style.js +247 -0
  129. package/dist/Editor/utils/SlateUtilityFunctions.js +169 -27
  130. package/dist/Editor/utils/button.js +1 -17
  131. package/dist/Editor/utils/events.js +54 -2
  132. package/dist/Editor/utils/font.js +40 -37
  133. package/dist/Editor/utils/helper.js +31 -2
  134. package/dist/Editor/utils/table.js +51 -43
  135. package/package.json +4 -3
@@ -1,4 +1,4 @@
1
- import { Box, Button, IconButton, Popover, Typography } from "@mui/material";
1
+ import { Box, Button, IconButton, Popper, Typography } from "@mui/material";
2
2
  import React, { useRef, useState } from "react";
3
3
  import { FaChevronRight } from "react-icons/fa";
4
4
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -49,9 +49,17 @@ function DisplayOption({
49
49
  } = option;
50
50
  const [open, setOpen] = useState(false);
51
51
  const optionRef = useRef();
52
+ const openOptions = e => {
53
+ if (option.options?.length && !open) {
54
+ setOpen(e.currentTarget);
55
+ return;
56
+ }
57
+ };
52
58
  return /*#__PURE__*/_jsxs(Box, {
53
59
  sx: classes.optionWrapper,
54
60
  ref: optionRef,
61
+ onMouseEnter: openOptions,
62
+ onMouseLeave: () => setOpen(null),
55
63
  children: [/*#__PURE__*/_jsxs(Button, {
56
64
  sx: classes.optionBtn,
57
65
  onClick: e => {
@@ -59,7 +67,7 @@ function DisplayOption({
59
67
 
60
68
  // is having child options
61
69
  if (option.options?.length) {
62
- setOpen(e.currentTarget);
70
+ openOptions(e);
63
71
  return;
64
72
  }
65
73
  setOpen(null);
@@ -77,25 +85,24 @@ function DisplayOption({
77
85
  size: 12
78
86
  })
79
87
  })]
80
- }), /*#__PURE__*/_jsx(Popover, {
88
+ }), /*#__PURE__*/_jsx(Popper, {
81
89
  open: open && option.options,
82
90
  anchorEl: open,
83
91
  sx: {
84
92
  zIndex: 9001,
85
93
  background: "transparent"
86
94
  },
87
- anchorOrigin: {
88
- vertical: "top",
89
- horizontal: "right"
90
- },
91
95
  onClose: () => {
92
96
  setOpen(null);
93
97
  },
94
- children: /*#__PURE__*/_jsx(CustomSelect, {
95
- options: option.options,
96
- onSend: onSend,
97
- classes: classes,
98
- show: open
98
+ placement: "right-start",
99
+ children: /*#__PURE__*/_jsx(Box, {
100
+ children: /*#__PURE__*/_jsx(CustomSelect, {
101
+ options: option.options,
102
+ onSend: onSend,
103
+ classes: classes,
104
+ show: open
105
+ })
99
106
  })
100
107
  })]
101
108
  });
@@ -1,26 +1,33 @@
1
1
  import { useEffect, useRef, useState } from "react";
2
2
  import { useEditorContext } from "../../hooks/useMouseMove";
3
3
  import Styles from "./Styles";
4
- import { Box, Fade, Paper, Popper } from "@mui/material";
4
+ import { Fade, Paper, Popper } from "@mui/material";
5
5
  import AIInput from "./AIInput";
6
6
  import { ReactEditor, useSlate } from "slate-react";
7
- import { Editor, Node, Path, Transforms } from "slate";
8
- import useWindowResize from "../../hooks/useWindowResize";
7
+ import { Node, Transforms } from "slate";
9
8
  import { MODES } from "./helper";
10
9
  import { getSelectedText } from "../../utils/helper";
10
+ import { VoiceToText } from "./VoiceToText";
11
+ import deserialize from "../../helper/deserialize";
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  import { jsxs as _jsxs } from "react/jsx-runtime";
13
- const scrollToAIInput = () => {
14
+ const scrollToAIInput = editor => {
14
15
  try {
15
16
  setTimeout(() => {
16
17
  const slateWrapper = document.getElementById("slate-wrapper-scroll-container");
17
- const selectionRect = window.getSelection().getRangeAt(0).getBoundingClientRect();
18
- const halfOfWrapper = slateWrapper.clientHeight / 2;
19
- const selectionScollTop = selectionRect.y + selectionRect.height;
20
- if (selectionScollTop > halfOfWrapper) {
21
- // scroll to half of the slateWrapper
18
+ let selectionRect;
19
+ if (getSelectedText(editor)) {
20
+ selectionRect = window.getSelection().getRangeAt(0).getBoundingClientRect();
21
+ } else {
22
+ selectionRect = ReactEditor.toDOMRange(editor, getNextLine(editor).at).getBoundingClientRect();
23
+ }
24
+ const selectionScrollBottom = selectionRect.bottom;
25
+
26
+ // if the cursor or selection top position is greater than 80
27
+ if (selectionScrollBottom > 80) {
28
+ // scroll to top of the slateWrapper
22
29
  slateWrapper.scrollTo({
23
- top: slateWrapper.scrollTop + selectionScollTop - halfOfWrapper,
30
+ top: slateWrapper.scrollTop + selectionScrollBottom - 80,
24
31
  behavior: "smooth"
25
32
  });
26
33
  }
@@ -29,26 +36,19 @@ const scrollToAIInput = () => {
29
36
  console.log(err);
30
37
  }
31
38
  };
39
+ const insertText = (editor, text, options) => {
40
+ const parsed = new DOMParser().parseFromString(text, "text/html");
41
+ const fragment = deserialize(parsed.body);
42
+ Transforms.insertFragment(editor, fragment, options);
43
+ };
32
44
  const insertAtNextLine = (editor, text) => {
33
45
  const nextLine = getNextLine(editor);
34
- Transforms.splitNodes(editor, {
46
+ insertText(editor, text, {
35
47
  at: nextLine.at
36
48
  });
37
- Transforms.insertNodes(editor, {
38
- type: "paragraph",
39
- children: [{
40
- text
41
- }]
42
- }, {
49
+ Transforms.splitNodes(editor, {
43
50
  at: nextLine.at
44
51
  });
45
- const currentPath = Path.parent(nextLine.at.focus.path);
46
- const nextPath = Path.next(currentPath);
47
- ReactEditor.focus(editor);
48
- Transforms.select(editor, {
49
- anchor: Editor.start(editor, nextPath),
50
- focus: Editor.end(editor, nextPath)
51
- });
52
52
  };
53
53
  const getNextLine = editor => {
54
54
  const {
@@ -101,8 +101,14 @@ const updateAnchorEl = (setAnchorEl, editor) => {
101
101
  // selected text as caret
102
102
  caret = selection.getRangeAt(0);
103
103
  } else {
104
- caret = ReactEditor.toDOMRange(editor, getNextLine(editor).at);
104
+ const domElement = ReactEditor.toDOMRange(editor, getNextLine(editor).at);
105
+ const {
106
+ textContent,
107
+ parentElement
108
+ } = domElement?.commonAncestorContainer || {};
109
+ caret = textContent ? domElement : parentElement; // in mobile, if textContent in not available, it is pointing some <br> tag (getBoundingClientRect not working correctly for <br>), to avoid that, we are pointing the parent element as caret
105
110
  }
111
+
106
112
  const getBoundingClientRect = () => {
107
113
  const editorContainer = document.querySelector("#slate-wrapper-scroll-container")?.getBoundingClientRect();
108
114
  const editorEle = document.querySelector(".ed-section-inner")?.getBoundingClientRect();
@@ -144,10 +150,8 @@ function PopoverAIInput({
144
150
  const [generatedText, setGeneratedText] = useState("");
145
151
  const [inputValue, setInputValue] = useState("");
146
152
  const [selectedOption, setSelectedOption] = useState();
147
- const targetRef = useRef();
148
153
  const classes = Styles();
149
154
  const editor = useSlate();
150
- const [size] = useWindowResize();
151
155
  const onClickOutside = () => {
152
156
  setAnchorEl(null);
153
157
  setOpenAI("");
@@ -163,8 +167,8 @@ function PopoverAIInput({
163
167
  updateAnchorEl(setAnchorEl, editor);
164
168
  }, [openAI, editor.selection]);
165
169
  useEffect(() => {
166
- if (openAI === "fromToolBar") {
167
- scrollToAIInput();
170
+ if (openAI) {
171
+ scrollToAIInput(editor);
168
172
  }
169
173
  }, [openAI]);
170
174
  const onSend = async (type, option) => {
@@ -172,12 +176,35 @@ function PopoverAIInput({
172
176
  onClickOutside();
173
177
  return;
174
178
  }
179
+ if (type === "done") {
180
+ // Get the current selection point
181
+ const {
182
+ anchor
183
+ } = editor.selection;
184
+ const {
185
+ path
186
+ } = anchor;
187
+ const {
188
+ text: selectText
189
+ } = Node.get(editor, path);
190
+ if (selectText?.length) {
191
+ insertAtNextLine(editor, generatedText);
192
+ } else {
193
+ insertText(editor, generatedText);
194
+ }
195
+ onClickOutside();
196
+ return;
197
+ }
175
198
  if (type === "replace_selection") {
176
199
  // replace generated text
177
- Transforms.insertText(editor, generatedText);
200
+ insertText(editor, generatedText);
178
201
  onClickOutside();
179
202
  return;
180
203
  }
204
+ if (type === "speech_to_text") {
205
+ setGeneratedText(option.text);
206
+ return;
207
+ }
181
208
  if (type === "try_again") {
182
209
  // resetting the previous option and try again
183
210
  option = selectedOption;
@@ -188,7 +215,7 @@ function PopoverAIInput({
188
215
  setLoading(true);
189
216
  const payload = {
190
217
  mode: option.mode || 0,
191
- query: inputValue
218
+ query: option?.inputValue || inputValue
192
219
  };
193
220
  if (option.mode === MODES.translate || option.mode === MODES.rephraseTone) {
194
221
  payload.textOptionInput = type;
@@ -214,47 +241,7 @@ function PopoverAIInput({
214
241
  }
215
242
  return;
216
243
  }
217
-
218
- // Get the current selection point
219
- const {
220
- anchor
221
- } = editor.selection;
222
- const {
223
- path
224
- } = anchor;
225
- const {
226
- text: selectText
227
- } = Node.get(editor, path);
228
- const insertInNewLine = option.isSendBtn && selectText?.length || type === "continue_writing";
229
- if (insertInNewLine) {
230
- if (getSelectedText(editor)) {
231
- const currentPath = Path.parent(editor.selection.focus.path);
232
- const nextPath = Path.next(currentPath);
233
- Transforms.insertNodes(editor, {
234
- type: "paragraph",
235
- children: [{
236
- text
237
- }]
238
- }, {
239
- at: nextPath,
240
- select: true
241
- });
242
- } else {
243
- insertAtNextLine(editor, text);
244
- return;
245
- }
246
- } else {
247
- Transforms.insertText(editor, text);
248
- }
249
- const range = {
250
- ...editor.selection,
251
- anchor: {
252
- ...anchor,
253
- offset: openAI === "fromToolBar" ? anchor.offset : 0
254
- }
255
- };
256
- ReactEditor.focus(editor);
257
- Transforms.select(editor, range);
244
+ insertText(editor, text);
258
245
 
259
246
  // scrollToAIInput();
260
247
  };
@@ -263,21 +250,7 @@ function PopoverAIInput({
263
250
  setInputValue(e.target.value);
264
251
  };
265
252
  return /*#__PURE__*/_jsxs("div", {
266
- children: [size.device === "xs" && openAI ? /*#__PURE__*/_jsx(Box, {
267
- component: "div",
268
- sx: classes.mobileAIInputWrapper,
269
- ref: targetRef,
270
- children: /*#__PURE__*/_jsx(AIInput, {
271
- loading: loading,
272
- onSend: onSend,
273
- generatedText: generatedText,
274
- anchorEl: anchorEl,
275
- openAI: openAI,
276
- inputValue: inputValue,
277
- onInputChange: onInputChange,
278
- onClickOutside: onClickOutside
279
- })
280
- }) : /*#__PURE__*/_jsx(Popper, {
253
+ children: [/*#__PURE__*/_jsx(Popper, {
281
254
  open: Boolean(openAI),
282
255
  anchorEl: anchorEl,
283
256
  transition: true,
@@ -286,7 +259,6 @@ function PopoverAIInput({
286
259
  ...classes.aiPopper,
287
260
  width: editorElement?.offsetWidth || 400
288
261
  },
289
- ref: targetRef,
290
262
  children: ({
291
263
  TransitionProps
292
264
  }) => /*#__PURE__*/_jsx(Fade, {
@@ -296,21 +268,25 @@ function PopoverAIInput({
296
268
  sx: getSelectedText(editor) ? {
297
269
  marginTop: "6px"
298
270
  } : {},
299
- children: /*#__PURE__*/_jsx(AIInput, {
300
- loading: loading,
271
+ children: /*#__PURE__*/_jsx(VoiceToText, {
272
+ otherProps: otherProps,
301
273
  onSend: onSend,
302
- generatedText: generatedText,
303
- anchorEl: anchorEl,
304
- openAI: openAI,
305
- inputValue: inputValue,
306
- onInputChange: onInputChange,
307
- onClickOutside: onClickOutside
274
+ children: /*#__PURE__*/_jsx(AIInput, {
275
+ loading: loading,
276
+ onSend: onSend,
277
+ generatedText: generatedText,
278
+ anchorEl: anchorEl,
279
+ openAI: openAI,
280
+ inputValue: inputValue,
281
+ onInputChange: onInputChange,
282
+ onClickOutside: onClickOutside
283
+ })
308
284
  })
309
285
  })
310
286
  })
311
287
  }), openAI ? /*#__PURE__*/_jsx("div", {
312
288
  style: {
313
- height: targetRef?.current?.clientHeight > 250 ? targetRef?.current?.clientHeight : 250,
289
+ height: "100vh",
314
290
  background: "transparent"
315
291
  }
316
292
  }) : null]
@@ -91,7 +91,6 @@ const Styles = theme => ({
91
91
  },
92
92
  generatedText: {
93
93
  margin: "8px",
94
- maxHeight: "100px",
95
94
  overflow: "auto",
96
95
  fontSize: "inherit"
97
96
  },
@@ -167,7 +166,8 @@ const Styles = theme => ({
167
166
  sendIconContainer: {
168
167
  alignSelf: "flex-end",
169
168
  display: "flex",
170
- alignItems: "center"
169
+ alignItems: "center",
170
+ gap: "6px"
171
171
  }
172
172
  });
173
173
  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,184 @@
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 { jsx as _jsx } from "react/jsx-runtime";
8
+ import { jsxs as _jsxs } from "react/jsx-runtime";
9
+ function STT(props) {
10
+ const {
11
+ otherProps,
12
+ onSend,
13
+ setIsRecording
14
+ } = props;
15
+ const {
16
+ services
17
+ } = otherProps;
18
+ const classes = STTStyles();
19
+ const [mediaRecorder, setMediaRecorder] = useState(null);
20
+ const [audioChunks, setAudioChunks] = useState([]);
21
+ const [chunkIndex, setChunkIndex] = useState(0);
22
+ const audioChunksRef = useRef([]);
23
+ const [transcription, setTranscription] = useState("");
24
+ const [showPause, setShowPause] = useState(true);
25
+ const setChunk = event => {
26
+ if (event.data.size > 0) {
27
+ setAudioChunks(prev => {
28
+ const updatedChunks = [...prev, event.data];
29
+ audioChunksRef.current = updatedChunks; // Update ref manually
30
+ return updatedChunks;
31
+ });
32
+ }
33
+ };
34
+ const sendChunck = async (isLast = false) => {
35
+ if (audioChunksRef.current.length > 0) {
36
+ const audioBlob = new Blob(audioChunksRef.current, {
37
+ type: "audio/webm"
38
+ });
39
+ const formData = new FormData();
40
+ formData.append("audio", audioBlob, `audio_chunk_${chunkIndex}.wav`);
41
+ formData.append("chunkIndex", chunkIndex); // Send chunk index to the backend
42
+ if (isLast) {
43
+ formData.append("isLastChunk", true); // Send chunk index to the backend
44
+ } else {
45
+ formData.append("isLastChunk", false);
46
+ setChunkIndex(prevIndex => prevIndex + 1);
47
+ }
48
+ const result = await services("speechToText", {
49
+ formData
50
+ });
51
+ setTranscription(result?.data || "");
52
+ await sendChunck();
53
+ }
54
+ };
55
+ const handleStopRecording = () => {
56
+ sendChunck(true);
57
+ setAudioChunks([]);
58
+ };
59
+ const startRecording = async () => {
60
+ setTranscription("");
61
+ const stream = await navigator.mediaDevices.getUserMedia({
62
+ audio: true
63
+ });
64
+ const recorder = new MediaRecorder(stream);
65
+ setMediaRecorder(recorder);
66
+ recorder.ondataavailable = setChunk;
67
+ recorder.onstop = handleStopRecording;
68
+ recorder.start(100);
69
+ setIsRecording(true);
70
+ setTimeout(() => {
71
+ sendChunck();
72
+ }, 2000);
73
+ };
74
+ useEffect(() => {
75
+ startRecording();
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
+ setIsRecording(false);
91
+ await onSend("", {
92
+ inputValue: transcription
93
+ });
94
+ stopRecording();
95
+ setShowPause(true);
96
+ };
97
+ const closeRecording = () => {
98
+ setAudioChunks([]);
99
+ stopRecording();
100
+ setIsRecording(false);
101
+ setShowPause(true);
102
+ setTranscription("");
103
+ };
104
+ useEffect(() => {
105
+ audioChunksRef.current = audioChunks;
106
+ }, [audioChunks]);
107
+ const transcriptionText = typeof transcription === "string" && transcription?.replace(/\s+/g, "")?.length; // Remove all whitespace characters like \n \t
108
+
109
+ return /*#__PURE__*/_jsxs(Grid, {
110
+ xs: 12,
111
+ sx: classes.AudioVizualizerContainer,
112
+ children: [transcriptionText ? /*#__PURE__*/_jsx(Grid, {
113
+ xs: 12,
114
+ sx: classes.TranscriptionContainer,
115
+ children: /*#__PURE__*/_jsx("pre", {
116
+ style: {
117
+ whiteSpace: "pre-wrap",
118
+ wordWrap: "break-word",
119
+ fontFamily: "inherit",
120
+ margin: 0
121
+ },
122
+ children: transcription
123
+ })
124
+ }) : null, /*#__PURE__*/_jsxs(Grid, {
125
+ xs: 12,
126
+ sx: classes.AudioVizualizerContent,
127
+ children: [/*#__PURE__*/_jsx(Box, {
128
+ children: /*#__PURE__*/_jsx(IconButton, {
129
+ onClick: closeRecording,
130
+ children: /*#__PURE__*/_jsx(CloseGreyCircle, {})
131
+ })
132
+ }), /*#__PURE__*/_jsx(Box, {
133
+ sx: classes.AudioVisualiser,
134
+ children: /*#__PURE__*/_jsx(AudioWave, {
135
+ audioChunks: audioChunks
136
+ })
137
+ }), /*#__PURE__*/_jsx(Box, {
138
+ children: showPause ? /*#__PURE__*/_jsx(IconButton, {
139
+ onClick: stopRecording,
140
+ children: /*#__PURE__*/_jsx(PauseRecordingIcon, {})
141
+ }) : /*#__PURE__*/_jsx(IconButton, {
142
+ onClick: sendToInfiniti,
143
+ disabled: !transcriptionText,
144
+ style: !transcriptionText ? {
145
+ opacity: 0.5
146
+ } : {},
147
+ children: /*#__PURE__*/_jsx(TickBlueCircle, {})
148
+ })
149
+ })]
150
+ })]
151
+ });
152
+ }
153
+ const withHOC = STT => {
154
+ const Container = props => {
155
+ const classes = STTStyles();
156
+ const {
157
+ children
158
+ } = props;
159
+ const [isRecording, setIsRecording] = useState(false);
160
+ return /*#__PURE__*/_jsx(Grid, {
161
+ xs: 12,
162
+ children: /*#__PURE__*/_jsx(Grid, {
163
+ className: classes.SttContainer,
164
+ children: !isRecording ? /*#__PURE__*/_jsx(Grid, {
165
+ xs: 12,
166
+ children: /*#__PURE__*/cloneElement(children, {
167
+ startRecording: () => setIsRecording(true)
168
+ })
169
+ }) : /*#__PURE__*/_jsx(STT, {
170
+ ...props,
171
+ setIsRecording: setIsRecording
172
+ })
173
+ })
174
+ });
175
+ };
176
+ return Container;
177
+ };
178
+ STT.defaultProps = {
179
+ classes: {}
180
+ };
181
+ STT.propTypes = {
182
+ classes: PropTypes.object
183
+ };
184
+ export const VoiceToText = withHOC(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;
@@ -47,10 +47,12 @@ export const newContentOptions = [{
47
47
  groupLabel: "",
48
48
  options: [
49
49
  // improveWriting,
50
- ...commonOptions.map(o => ({
51
- ...o,
50
+ {
51
+ label: "Done",
52
+ value: "done",
53
+ Icon: CheckIcon,
52
54
  replace: true
53
- })), {
55
+ }, ...commonOptions, {
54
56
  label: "Close",
55
57
  value: "close",
56
58
  Icon: CloseIcon,
@@ -160,7 +160,7 @@ const Accordion = props => {
160
160
  children: [/*#__PURE__*/_jsxs("div", {
161
161
  className: "accordion-title",
162
162
  style: {
163
- background: bgColor
163
+ backgroundColor: bgColor
164
164
  },
165
165
  onClick: onToggle,
166
166
  children: [/*#__PURE__*/_jsx(Box, {