@flozy/editor 4.0.3 → 4.0.4

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 (148) hide show
  1. package/dist/Editor/CommonEditor.js +85 -13
  2. package/dist/Editor/DialogWrapper.js +4 -3
  3. package/dist/Editor/Editor.css +28 -2
  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 +119 -132
  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/AppHeader/AppHeader.js +36 -23
  13. package/dist/Editor/Elements/Button/EditorButton.js +23 -16
  14. package/dist/Editor/Elements/Carousel/CarouselButton.js +2 -2
  15. package/dist/Editor/Elements/Color Picker/ColorButtons.js +1 -1
  16. package/dist/Editor/Elements/Color Picker/Styles.js +1 -0
  17. package/dist/Editor/Elements/Embed/Image.js +15 -14
  18. package/dist/Editor/Elements/Embed/Video.js +12 -8
  19. package/dist/Editor/Elements/Emoji/EmojiButton.js +11 -7
  20. package/dist/Editor/Elements/Form/Form.js +43 -27
  21. package/dist/Editor/Elements/Form/FormField.js +21 -10
  22. package/dist/Editor/Elements/Form/Workflow/index.js +5 -2
  23. package/dist/Editor/Elements/FreeGrid/FreeGrid.js +437 -0
  24. package/dist/Editor/Elements/FreeGrid/FreeGridBox.js +206 -0
  25. package/dist/Editor/Elements/FreeGrid/FreeGridButton.js +23 -0
  26. package/dist/Editor/Elements/FreeGrid/FreeGridItem.js +236 -0
  27. package/dist/Editor/Elements/FreeGrid/Options/AddElement.js +44 -0
  28. package/dist/Editor/Elements/FreeGrid/Options/More.js +24 -0
  29. package/dist/Editor/Elements/FreeGrid/Options/SectionSettings.js +47 -0
  30. package/dist/Editor/Elements/FreeGrid/Options/sectionItemOptions.js +19 -0
  31. package/dist/Editor/Elements/FreeGrid/breakpointConstants.js +75 -0
  32. package/dist/Editor/Elements/FreeGrid/styles.js +214 -0
  33. package/dist/Editor/Elements/Grid/Grid.js +12 -8
  34. package/dist/Editor/Elements/Grid/GridItem.js +31 -21
  35. package/dist/Editor/Elements/Link/LinkPopup.js +69 -13
  36. package/dist/Editor/Elements/Link/LinkPopupStyles.js +28 -0
  37. package/dist/Editor/Elements/NewLine/NewLineButton.js +2 -2
  38. package/dist/Editor/Elements/Signature/Signature.css +13 -6
  39. package/dist/Editor/Elements/Signature/SignatureOptions/UploadSignature.js +2 -1
  40. package/dist/Editor/Elements/Signature/SignaturePopup.js +186 -31
  41. package/dist/Editor/Elements/SimpleText/index.js +19 -7
  42. package/dist/Editor/Elements/SimpleText/style.js +44 -1
  43. package/dist/Editor/ErrorBoundary.js +30 -0
  44. package/dist/Editor/Styles/EditorStyles.js +28 -0
  45. package/dist/Editor/Toolbar/FormatTools/Dropdown.js +1 -1
  46. package/dist/Editor/Toolbar/FormatTools/TextSize.js +2 -2
  47. package/dist/Editor/Toolbar/Mini/MiniToolbar.js +33 -5
  48. package/dist/Editor/Toolbar/PopupTool/ButtonTemplatesCard.js +12 -13
  49. package/dist/Editor/Toolbar/PopupTool/FullViewCard.js +12 -13
  50. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/CustomSelectTool.js +3 -0
  51. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/SelectSuperSubscript.js +59 -0
  52. package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/index.js +2 -1
  53. package/dist/Editor/Toolbar/PopupTool/PopupToolStyle.js +107 -40
  54. package/dist/Editor/Toolbar/PopupTool/TextFormat.js +57 -61
  55. package/dist/Editor/Toolbar/PopupTool/index.js +13 -3
  56. package/dist/Editor/Toolbar/Toolbar.js +7 -0
  57. package/dist/Editor/Toolbar/toolbarGroups.js +15 -5
  58. package/dist/Editor/assets/svg/AIIcons.js +153 -1
  59. package/dist/Editor/common/EditorCmds.js +0 -3
  60. package/dist/Editor/common/EditorIcons.js +7 -7
  61. package/dist/Editor/common/Icon.js +39 -30
  62. package/dist/Editor/common/ImageList.js +16 -3
  63. package/dist/Editor/common/ImageSelector/ImageSelector.js +30 -9
  64. package/dist/Editor/common/ImageSelector/Styles.js +2 -1
  65. package/dist/Editor/common/LinkSettings/index.js +2 -1
  66. package/dist/Editor/common/LinkSettings/style.js +11 -8
  67. package/dist/Editor/common/MentionsPopup/Styles.js +1 -1
  68. package/dist/Editor/common/MentionsPopup/index.js +12 -8
  69. package/dist/Editor/common/RnD/ContextMenu/CMenus.js +142 -0
  70. package/dist/Editor/common/RnD/ContextMenu/index.js +38 -0
  71. package/dist/Editor/common/RnD/ContextMenu/styles.js +21 -0
  72. package/dist/Editor/common/RnD/DragInfo/index.js +31 -0
  73. package/dist/Editor/common/RnD/DragInfo/styles.js +15 -0
  74. package/dist/Editor/common/RnD/DragOver/index.js +55 -0
  75. package/dist/Editor/common/RnD/DragOver/styles.js +23 -0
  76. package/dist/Editor/common/RnD/ElementOptions/Actions.js +102 -0
  77. package/dist/Editor/common/RnD/ElementOptions/Icons/LinkIcon.js +26 -0
  78. package/dist/Editor/common/RnD/ElementOptions/index.js +95 -0
  79. package/dist/Editor/common/RnD/ElementOptions/styles.js +41 -0
  80. package/dist/Editor/common/RnD/ElementSettings/OtherSettings/Link.js +153 -0
  81. package/dist/Editor/common/RnD/ElementSettings/OtherSettings/SaveAsTemplate.js +36 -0
  82. package/dist/Editor/common/RnD/ElementSettings/OtherSettings/Settings.js +60 -0
  83. package/dist/Editor/common/RnD/ElementSettings/OtherSettings/index.js +9 -0
  84. package/dist/Editor/common/RnD/ElementSettings/Settings/AppHeaderSettings.js +47 -0
  85. package/dist/Editor/common/RnD/ElementSettings/Settings/BoxSettings.js +47 -0
  86. package/dist/Editor/common/RnD/ElementSettings/Settings/ButtonSettings.js +47 -0
  87. package/dist/Editor/common/RnD/ElementSettings/Settings/FormSettings.js +48 -0
  88. package/dist/Editor/common/RnD/ElementSettings/Settings/ImageSettings.js +47 -0
  89. package/dist/Editor/common/RnD/ElementSettings/Settings/TextSettings.js +30 -0
  90. package/dist/Editor/common/RnD/ElementSettings/Settings/VideoSettings.js +47 -0
  91. package/dist/Editor/common/RnD/ElementSettings/Settings/index.js +17 -0
  92. package/dist/Editor/common/RnD/ElementSettings/index.js +17 -0
  93. package/dist/Editor/common/RnD/ElementSettings/settingsConstants.js +18 -0
  94. package/dist/Editor/common/RnD/ElementSettings/styles.js +94 -0
  95. package/dist/Editor/common/RnD/GuideLines/BoundaryLine.js +52 -0
  96. package/dist/Editor/common/RnD/GuideLines/index.js +33 -0
  97. package/dist/Editor/common/RnD/GuideLines/styles.js +62 -0
  98. package/dist/Editor/common/RnD/OptionsPopup/index.js +50 -0
  99. package/dist/Editor/common/RnD/OptionsPopup/style.js +36 -0
  100. package/dist/Editor/common/RnD/RnDCopy.js +23 -0
  101. package/dist/Editor/common/RnD/ShadowElement.js +34 -0
  102. package/dist/Editor/common/RnD/SwitchViewport/SwitchViewport.js +40 -0
  103. package/dist/Editor/common/RnD/SwitchViewport/styles.js +24 -0
  104. package/dist/Editor/common/RnD/Theme/ViewportStimulator.js +63 -0
  105. package/dist/Editor/common/RnD/TransformHandles/CornerHandle.js +19 -0
  106. package/dist/Editor/common/RnD/TransformHandles/Icons/BottomRightIcon.js +13 -0
  107. package/dist/Editor/common/RnD/TransformHandles/SizeHandle.js +20 -0
  108. package/dist/Editor/common/RnD/TransformHandles/index.js +67 -0
  109. package/dist/Editor/common/RnD/Utils/alignmentDetection.js +26 -0
  110. package/dist/Editor/common/RnD/Utils/calculateDropItem.js +98 -0
  111. package/dist/Editor/common/RnD/Utils/collisionDetection.js +52 -0
  112. package/dist/Editor/common/RnD/Utils/gridDropItem.js +181 -0
  113. package/dist/Editor/common/RnD/Utils/index.js +251 -0
  114. package/dist/Editor/common/RnD/VirtualElement/index.js +77 -0
  115. package/dist/Editor/common/RnD/VirtualElement/styles.js +27 -0
  116. package/dist/Editor/common/RnD/VirtualElement/updateAutoProps.js +28 -0
  117. package/dist/Editor/common/RnD/index.js +567 -0
  118. package/dist/Editor/common/RnD/styles.js +4 -0
  119. package/dist/Editor/common/Section/index.js +21 -12
  120. package/dist/Editor/common/Section/styles.js +7 -4
  121. package/dist/Editor/common/Shorthands/elements.js +21 -9
  122. package/dist/Editor/common/StyleBuilder/boxStyle.js +30 -0
  123. package/dist/Editor/common/StyleBuilder/fieldTypes/bannerSpacing.js +18 -10
  124. package/dist/Editor/common/StyleBuilder/fieldTypes/saveAsTemplate.js +18 -5
  125. package/dist/Editor/common/StyleBuilder/fieldTypes/text.js +4 -2
  126. package/dist/Editor/common/StyleBuilder/index.js +6 -4
  127. package/dist/Editor/common/StyleBuilder/sectionStyle.js +13 -2
  128. package/dist/Editor/common/iconListV2.js +843 -0
  129. package/dist/Editor/commonStyle.js +6 -0
  130. package/dist/Editor/helper/RnD/focusOnNewItem.js +39 -0
  131. package/dist/Editor/helper/RnD/scrollToNewSection.js +24 -0
  132. package/dist/Editor/helper/breakpoint.js +5 -0
  133. package/dist/Editor/helper/index.js +139 -0
  134. package/dist/Editor/helper/theme.js +50 -1
  135. package/dist/Editor/hooks/useBreakpoints.js +34 -0
  136. package/dist/Editor/hooks/useMouseMove.js +36 -8
  137. package/dist/Editor/hooks/useWindowMessage.js +10 -7
  138. package/dist/Editor/hooks/withCommon.js +2 -1
  139. package/dist/Editor/hooks/withErrorHandling.js +14 -0
  140. package/dist/Editor/utils/RnD/RnDCtrlCmds.js +197 -0
  141. package/dist/Editor/utils/SlateUtilityFunctions.js +36 -4
  142. package/dist/Editor/utils/events.js +5 -0
  143. package/dist/Editor/utils/form.js +7 -2
  144. package/dist/Editor/utils/formfield.js +1 -1
  145. package/dist/Editor/utils/freegrid.js +91 -0
  146. package/dist/Editor/utils/helper.js +43 -0
  147. package/dist/Editor/utils/insertAppHeader.js +47 -40
  148. package/package.json +6 -2
@@ -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,65 +36,66 @@ 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
- const {
55
- selection
56
- } = editor;
57
- const {
58
- focus
59
- } = selection;
60
- const {
61
- text = ""
62
- } = Node.get(editor, focus.path);
63
- let nextLineIndex = 0;
64
- let indexOfNextLine = 0;
65
- if (text?.length) {
66
- // split the text based on caret position
67
- const textBeforeCaret = text.substring(0, focus.offset);
68
- const textAfterCaret = text.substring(focus.offset);
54
+ try {
55
+ const {
56
+ selection
57
+ } = editor;
58
+ const {
59
+ focus
60
+ } = selection;
61
+ if (focus?.path?.length > 0) {
62
+ const {
63
+ text = ""
64
+ } = Node.get(editor, focus.path);
65
+ let nextLineIndex = 0;
66
+ let indexOfNextLine = 0;
67
+ if (text?.length) {
68
+ // split the text based on caret position
69
+ const textBeforeCaret = text.substring(0, focus.offset);
70
+ const textAfterCaret = text.substring(focus.offset);
69
71
 
70
- // getting the index of the next line after the caret position
71
- indexOfNextLine = textAfterCaret?.indexOf("\n");
72
- if (indexOfNextLine >= 0) {
73
- // index of next line
74
- nextLineIndex = textBeforeCaret?.length + indexOfNextLine;
75
- } else {
76
- nextLineIndex = text?.length;
72
+ // getting the index of the next line after the caret position
73
+ indexOfNextLine = textAfterCaret?.indexOf("\n");
74
+ if (indexOfNextLine >= 0) {
75
+ // index of next line
76
+ nextLineIndex = textBeforeCaret?.length + indexOfNextLine;
77
+ } else {
78
+ nextLineIndex = text?.length;
79
+ }
80
+ }
81
+ const data = {
82
+ ...focus,
83
+ offset: nextLineIndex
84
+ };
85
+ const at = {
86
+ anchor: data,
87
+ focus: data
88
+ };
89
+ return {
90
+ at,
91
+ indexOfNextLine
92
+ };
77
93
  }
94
+ return null;
95
+ } catch (err) {
96
+ console.log(err);
97
+ return null;
78
98
  }
79
- const data = {
80
- ...focus,
81
- offset: nextLineIndex
82
- };
83
- const at = {
84
- anchor: data,
85
- focus: data
86
- };
87
- return {
88
- at,
89
- indexOfNextLine
90
- };
91
99
  };
92
100
  const updateAnchorEl = (setAnchorEl, editor) => {
93
101
  try {
@@ -95,14 +103,23 @@ const updateAnchorEl = (setAnchorEl, editor) => {
95
103
  return;
96
104
  }
97
105
  const selection = window.getSelection();
98
- if (selection.rangeCount) {
106
+ if (selection.rangeCount && selection.anchorOffset !== selection.focusOffset) {
99
107
  let caret;
100
108
  if (getSelectedText(editor)) {
101
109
  // selected text as caret
102
110
  caret = selection.getRangeAt(0);
103
111
  } else {
104
- caret = ReactEditor.toDOMRange(editor, getNextLine(editor).at);
112
+ const sel = getNextLine(editor);
113
+ if (sel) {
114
+ const domElement = ReactEditor.toDOMRange(editor, sel.at);
115
+ const {
116
+ textContent,
117
+ parentElement
118
+ } = domElement?.commonAncestorContainer || {};
119
+ 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
120
+ }
105
121
  }
122
+
106
123
  const getBoundingClientRect = () => {
107
124
  const editorContainer = document.querySelector("#slate-wrapper-scroll-container")?.getBoundingClientRect();
108
125
  const editorEle = document.querySelector(".ed-section-inner")?.getBoundingClientRect();
@@ -144,10 +161,8 @@ function PopoverAIInput({
144
161
  const [generatedText, setGeneratedText] = useState("");
145
162
  const [inputValue, setInputValue] = useState("");
146
163
  const [selectedOption, setSelectedOption] = useState();
147
- const targetRef = useRef();
148
164
  const classes = Styles();
149
165
  const editor = useSlate();
150
- const [size] = useWindowResize();
151
166
  const onClickOutside = () => {
152
167
  setAnchorEl(null);
153
168
  setOpenAI("");
@@ -163,8 +178,8 @@ function PopoverAIInput({
163
178
  updateAnchorEl(setAnchorEl, editor);
164
179
  }, [openAI, editor.selection]);
165
180
  useEffect(() => {
166
- if (openAI === "fromToolBar") {
167
- scrollToAIInput();
181
+ if (openAI) {
182
+ scrollToAIInput(editor);
168
183
  }
169
184
  }, [openAI]);
170
185
  const onSend = async (type, option) => {
@@ -172,12 +187,35 @@ function PopoverAIInput({
172
187
  onClickOutside();
173
188
  return;
174
189
  }
190
+ if (type === "done") {
191
+ // Get the current selection point
192
+ const {
193
+ anchor
194
+ } = editor.selection;
195
+ const {
196
+ path
197
+ } = anchor;
198
+ const {
199
+ text: selectText
200
+ } = Node.get(editor, path);
201
+ if (selectText?.length) {
202
+ insertAtNextLine(editor, generatedText);
203
+ } else {
204
+ insertText(editor, generatedText);
205
+ }
206
+ onClickOutside();
207
+ return;
208
+ }
175
209
  if (type === "replace_selection") {
176
210
  // replace generated text
177
- Transforms.insertText(editor, generatedText);
211
+ insertText(editor, generatedText);
178
212
  onClickOutside();
179
213
  return;
180
214
  }
215
+ if (type === "speech_to_text") {
216
+ setGeneratedText(option.text);
217
+ return;
218
+ }
181
219
  if (type === "try_again") {
182
220
  // resetting the previous option and try again
183
221
  option = selectedOption;
@@ -188,7 +226,7 @@ function PopoverAIInput({
188
226
  setLoading(true);
189
227
  const payload = {
190
228
  mode: option.mode || 0,
191
- query: inputValue
229
+ query: option?.inputValue || inputValue
192
230
  };
193
231
  if (option.mode === MODES.translate || option.mode === MODES.rephraseTone) {
194
232
  payload.textOptionInput = type;
@@ -214,47 +252,7 @@ function PopoverAIInput({
214
252
  }
215
253
  return;
216
254
  }
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);
255
+ insertText(editor, text);
258
256
 
259
257
  // scrollToAIInput();
260
258
  };
@@ -263,21 +261,7 @@ function PopoverAIInput({
263
261
  setInputValue(e.target.value);
264
262
  };
265
263
  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, {
264
+ children: [/*#__PURE__*/_jsx(Popper, {
281
265
  open: Boolean(openAI),
282
266
  anchorEl: anchorEl,
283
267
  transition: true,
@@ -286,7 +270,6 @@ function PopoverAIInput({
286
270
  ...classes.aiPopper,
287
271
  width: editorElement?.offsetWidth || 400
288
272
  },
289
- ref: targetRef,
290
273
  children: ({
291
274
  TransitionProps
292
275
  }) => /*#__PURE__*/_jsx(Fade, {
@@ -296,21 +279,25 @@ function PopoverAIInput({
296
279
  sx: getSelectedText(editor) ? {
297
280
  marginTop: "6px"
298
281
  } : {},
299
- children: /*#__PURE__*/_jsx(AIInput, {
300
- loading: loading,
282
+ children: /*#__PURE__*/_jsx(VoiceToText, {
283
+ otherProps: otherProps,
301
284
  onSend: onSend,
302
- generatedText: generatedText,
303
- anchorEl: anchorEl,
304
- openAI: openAI,
305
- inputValue: inputValue,
306
- onInputChange: onInputChange,
307
- onClickOutside: onClickOutside
285
+ children: /*#__PURE__*/_jsx(AIInput, {
286
+ loading: loading,
287
+ onSend: onSend,
288
+ generatedText: generatedText,
289
+ anchorEl: anchorEl,
290
+ openAI: openAI,
291
+ inputValue: inputValue,
292
+ onInputChange: onInputChange,
293
+ onClickOutside: onClickOutside
294
+ })
308
295
  })
309
296
  })
310
297
  })
311
298
  }), openAI ? /*#__PURE__*/_jsx("div", {
312
299
  style: {
313
- height: targetRef?.current?.clientHeight > 250 ? targetRef?.current?.clientHeight : 250,
300
+ height: "100vh",
314
301
  background: "transparent"
315
302
  }
316
303
  }) : 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,