@flozy/editor 4.0.1 → 4.0.2

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.
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, {