@flozy/editor 4.0.3 → 4.0.5

Sign up to get free protection for your applications and to get access to all the features.
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 +124 -133
  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,80 +36,94 @@ 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
- const updateAnchorEl = (setAnchorEl, editor) => {
100
+ const updateAnchorEl = (setAnchorEl, editor, openAI) => {
93
101
  try {
94
102
  if (!editor.selection) {
95
103
  return;
96
104
  }
97
105
  const selection = window.getSelection();
106
+ if (openAI === "fromToolBar" && selection.anchorOffset !== selection.focusOffset) {
107
+ // to fix some issue in Drag n Drop
108
+ return;
109
+ }
98
110
  if (selection.rangeCount) {
99
111
  let caret;
100
112
  if (getSelectedText(editor)) {
101
113
  // selected text as caret
102
114
  caret = selection.getRangeAt(0);
103
115
  } else {
104
- caret = ReactEditor.toDOMRange(editor, getNextLine(editor).at);
116
+ const sel = getNextLine(editor);
117
+ if (sel) {
118
+ const domElement = ReactEditor.toDOMRange(editor, sel.at);
119
+ const {
120
+ textContent,
121
+ parentElement
122
+ } = domElement?.commonAncestorContainer || {};
123
+ 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
124
+ }
105
125
  }
126
+
106
127
  const getBoundingClientRect = () => {
107
128
  const editorContainer = document.querySelector("#slate-wrapper-scroll-container")?.getBoundingClientRect();
108
129
  const editorEle = document.querySelector(".ed-section-inner")?.getBoundingClientRect();
@@ -144,10 +165,8 @@ function PopoverAIInput({
144
165
  const [generatedText, setGeneratedText] = useState("");
145
166
  const [inputValue, setInputValue] = useState("");
146
167
  const [selectedOption, setSelectedOption] = useState();
147
- const targetRef = useRef();
148
168
  const classes = Styles();
149
169
  const editor = useSlate();
150
- const [size] = useWindowResize();
151
170
  const onClickOutside = () => {
152
171
  setAnchorEl(null);
153
172
  setOpenAI("");
@@ -160,11 +179,11 @@ function PopoverAIInput({
160
179
  };
161
180
  const editorElement = document.querySelector(".ed-section-inner");
162
181
  useEffect(() => {
163
- updateAnchorEl(setAnchorEl, editor);
182
+ updateAnchorEl(setAnchorEl, editor, openAI);
164
183
  }, [openAI, editor.selection]);
165
184
  useEffect(() => {
166
- if (openAI === "fromToolBar") {
167
- scrollToAIInput();
185
+ if (openAI) {
186
+ scrollToAIInput(editor);
168
187
  }
169
188
  }, [openAI]);
170
189
  const onSend = async (type, option) => {
@@ -172,12 +191,35 @@ function PopoverAIInput({
172
191
  onClickOutside();
173
192
  return;
174
193
  }
194
+ if (type === "done") {
195
+ // Get the current selection point
196
+ const {
197
+ anchor
198
+ } = editor.selection;
199
+ const {
200
+ path
201
+ } = anchor;
202
+ const {
203
+ text: selectText
204
+ } = Node.get(editor, path);
205
+ if (selectText?.length) {
206
+ insertAtNextLine(editor, generatedText);
207
+ } else {
208
+ insertText(editor, generatedText);
209
+ }
210
+ onClickOutside();
211
+ return;
212
+ }
175
213
  if (type === "replace_selection") {
176
214
  // replace generated text
177
- Transforms.insertText(editor, generatedText);
215
+ insertText(editor, generatedText);
178
216
  onClickOutside();
179
217
  return;
180
218
  }
219
+ if (type === "speech_to_text") {
220
+ setGeneratedText(option.text);
221
+ return;
222
+ }
181
223
  if (type === "try_again") {
182
224
  // resetting the previous option and try again
183
225
  option = selectedOption;
@@ -188,7 +230,7 @@ function PopoverAIInput({
188
230
  setLoading(true);
189
231
  const payload = {
190
232
  mode: option.mode || 0,
191
- query: inputValue
233
+ query: option?.inputValue || inputValue
192
234
  };
193
235
  if (option.mode === MODES.translate || option.mode === MODES.rephraseTone) {
194
236
  payload.textOptionInput = type;
@@ -214,47 +256,7 @@ function PopoverAIInput({
214
256
  }
215
257
  return;
216
258
  }
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);
259
+ insertText(editor, text);
258
260
 
259
261
  // scrollToAIInput();
260
262
  };
@@ -263,21 +265,7 @@ function PopoverAIInput({
263
265
  setInputValue(e.target.value);
264
266
  };
265
267
  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, {
268
+ children: [/*#__PURE__*/_jsx(Popper, {
281
269
  open: Boolean(openAI),
282
270
  anchorEl: anchorEl,
283
271
  transition: true,
@@ -286,7 +274,6 @@ function PopoverAIInput({
286
274
  ...classes.aiPopper,
287
275
  width: editorElement?.offsetWidth || 400
288
276
  },
289
- ref: targetRef,
290
277
  children: ({
291
278
  TransitionProps
292
279
  }) => /*#__PURE__*/_jsx(Fade, {
@@ -296,21 +283,25 @@ function PopoverAIInput({
296
283
  sx: getSelectedText(editor) ? {
297
284
  marginTop: "6px"
298
285
  } : {},
299
- children: /*#__PURE__*/_jsx(AIInput, {
300
- loading: loading,
286
+ children: /*#__PURE__*/_jsx(VoiceToText, {
287
+ otherProps: otherProps,
301
288
  onSend: onSend,
302
- generatedText: generatedText,
303
- anchorEl: anchorEl,
304
- openAI: openAI,
305
- inputValue: inputValue,
306
- onInputChange: onInputChange,
307
- onClickOutside: onClickOutside
289
+ children: /*#__PURE__*/_jsx(AIInput, {
290
+ loading: loading,
291
+ onSend: onSend,
292
+ generatedText: generatedText,
293
+ anchorEl: anchorEl,
294
+ openAI: openAI,
295
+ inputValue: inputValue,
296
+ onInputChange: onInputChange,
297
+ onClickOutside: onClickOutside
298
+ })
308
299
  })
309
300
  })
310
301
  })
311
302
  }), openAI ? /*#__PURE__*/_jsx("div", {
312
303
  style: {
313
- height: targetRef?.current?.clientHeight > 250 ? targetRef?.current?.clientHeight : 250,
304
+ height: "100vh",
314
305
  background: "transparent"
315
306
  }
316
307
  }) : 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;