@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.
- package/dist/Editor/CommonEditor.js +85 -13
- package/dist/Editor/DialogWrapper.js +4 -3
- package/dist/Editor/Editor.css +28 -2
- package/dist/Editor/Elements/AI/AIInput.js +31 -33
- package/dist/Editor/Elements/AI/CustomSelect.js +19 -12
- package/dist/Editor/Elements/AI/PopoverAIInput.js +119 -132
- package/dist/Editor/Elements/AI/Styles.js +2 -2
- package/dist/Editor/Elements/AI/VoiceToText/AudioWave.js +73 -0
- package/dist/Editor/Elements/AI/VoiceToText/index.js +184 -0
- package/dist/Editor/Elements/AI/VoiceToText/style.js +40 -0
- package/dist/Editor/Elements/AI/helper.js +5 -3
- package/dist/Editor/Elements/AppHeader/AppHeader.js +36 -23
- package/dist/Editor/Elements/Button/EditorButton.js +23 -16
- package/dist/Editor/Elements/Carousel/CarouselButton.js +2 -2
- package/dist/Editor/Elements/Color Picker/ColorButtons.js +1 -1
- package/dist/Editor/Elements/Color Picker/Styles.js +1 -0
- package/dist/Editor/Elements/Embed/Image.js +15 -14
- package/dist/Editor/Elements/Embed/Video.js +12 -8
- package/dist/Editor/Elements/Emoji/EmojiButton.js +11 -7
- package/dist/Editor/Elements/Form/Form.js +43 -27
- package/dist/Editor/Elements/Form/FormField.js +21 -10
- package/dist/Editor/Elements/Form/Workflow/index.js +5 -2
- package/dist/Editor/Elements/FreeGrid/FreeGrid.js +437 -0
- package/dist/Editor/Elements/FreeGrid/FreeGridBox.js +206 -0
- package/dist/Editor/Elements/FreeGrid/FreeGridButton.js +23 -0
- package/dist/Editor/Elements/FreeGrid/FreeGridItem.js +236 -0
- package/dist/Editor/Elements/FreeGrid/Options/AddElement.js +44 -0
- package/dist/Editor/Elements/FreeGrid/Options/More.js +24 -0
- package/dist/Editor/Elements/FreeGrid/Options/SectionSettings.js +47 -0
- package/dist/Editor/Elements/FreeGrid/Options/sectionItemOptions.js +19 -0
- package/dist/Editor/Elements/FreeGrid/breakpointConstants.js +75 -0
- package/dist/Editor/Elements/FreeGrid/styles.js +214 -0
- package/dist/Editor/Elements/Grid/Grid.js +12 -8
- package/dist/Editor/Elements/Grid/GridItem.js +31 -21
- package/dist/Editor/Elements/Link/LinkPopup.js +69 -13
- package/dist/Editor/Elements/Link/LinkPopupStyles.js +28 -0
- package/dist/Editor/Elements/NewLine/NewLineButton.js +2 -2
- package/dist/Editor/Elements/Signature/Signature.css +13 -6
- package/dist/Editor/Elements/Signature/SignatureOptions/UploadSignature.js +2 -1
- package/dist/Editor/Elements/Signature/SignaturePopup.js +186 -31
- package/dist/Editor/Elements/SimpleText/index.js +19 -7
- package/dist/Editor/Elements/SimpleText/style.js +44 -1
- package/dist/Editor/ErrorBoundary.js +30 -0
- package/dist/Editor/Styles/EditorStyles.js +28 -0
- package/dist/Editor/Toolbar/FormatTools/Dropdown.js +1 -1
- package/dist/Editor/Toolbar/FormatTools/TextSize.js +2 -2
- package/dist/Editor/Toolbar/Mini/MiniToolbar.js +33 -5
- package/dist/Editor/Toolbar/PopupTool/ButtonTemplatesCard.js +12 -13
- package/dist/Editor/Toolbar/PopupTool/FullViewCard.js +12 -13
- package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/CustomSelectTool.js +3 -0
- package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/SelectSuperSubscript.js +59 -0
- package/dist/Editor/Toolbar/PopupTool/MiniTextFormat/index.js +2 -1
- package/dist/Editor/Toolbar/PopupTool/PopupToolStyle.js +107 -40
- package/dist/Editor/Toolbar/PopupTool/TextFormat.js +57 -61
- package/dist/Editor/Toolbar/PopupTool/index.js +13 -3
- package/dist/Editor/Toolbar/Toolbar.js +7 -0
- package/dist/Editor/Toolbar/toolbarGroups.js +15 -5
- package/dist/Editor/assets/svg/AIIcons.js +153 -1
- package/dist/Editor/common/EditorCmds.js +0 -3
- package/dist/Editor/common/EditorIcons.js +7 -7
- package/dist/Editor/common/Icon.js +39 -30
- package/dist/Editor/common/ImageList.js +16 -3
- package/dist/Editor/common/ImageSelector/ImageSelector.js +30 -9
- package/dist/Editor/common/ImageSelector/Styles.js +2 -1
- package/dist/Editor/common/LinkSettings/index.js +2 -1
- package/dist/Editor/common/LinkSettings/style.js +11 -8
- package/dist/Editor/common/MentionsPopup/Styles.js +1 -1
- package/dist/Editor/common/MentionsPopup/index.js +12 -8
- package/dist/Editor/common/RnD/ContextMenu/CMenus.js +142 -0
- package/dist/Editor/common/RnD/ContextMenu/index.js +38 -0
- package/dist/Editor/common/RnD/ContextMenu/styles.js +21 -0
- package/dist/Editor/common/RnD/DragInfo/index.js +31 -0
- package/dist/Editor/common/RnD/DragInfo/styles.js +15 -0
- package/dist/Editor/common/RnD/DragOver/index.js +55 -0
- package/dist/Editor/common/RnD/DragOver/styles.js +23 -0
- package/dist/Editor/common/RnD/ElementOptions/Actions.js +102 -0
- package/dist/Editor/common/RnD/ElementOptions/Icons/LinkIcon.js +26 -0
- package/dist/Editor/common/RnD/ElementOptions/index.js +95 -0
- package/dist/Editor/common/RnD/ElementOptions/styles.js +41 -0
- package/dist/Editor/common/RnD/ElementSettings/OtherSettings/Link.js +153 -0
- package/dist/Editor/common/RnD/ElementSettings/OtherSettings/SaveAsTemplate.js +36 -0
- package/dist/Editor/common/RnD/ElementSettings/OtherSettings/Settings.js +60 -0
- package/dist/Editor/common/RnD/ElementSettings/OtherSettings/index.js +9 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/AppHeaderSettings.js +47 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/BoxSettings.js +47 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/ButtonSettings.js +47 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/FormSettings.js +48 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/ImageSettings.js +47 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/TextSettings.js +30 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/VideoSettings.js +47 -0
- package/dist/Editor/common/RnD/ElementSettings/Settings/index.js +17 -0
- package/dist/Editor/common/RnD/ElementSettings/index.js +17 -0
- package/dist/Editor/common/RnD/ElementSettings/settingsConstants.js +18 -0
- package/dist/Editor/common/RnD/ElementSettings/styles.js +94 -0
- package/dist/Editor/common/RnD/GuideLines/BoundaryLine.js +52 -0
- package/dist/Editor/common/RnD/GuideLines/index.js +33 -0
- package/dist/Editor/common/RnD/GuideLines/styles.js +62 -0
- package/dist/Editor/common/RnD/OptionsPopup/index.js +50 -0
- package/dist/Editor/common/RnD/OptionsPopup/style.js +36 -0
- package/dist/Editor/common/RnD/RnDCopy.js +23 -0
- package/dist/Editor/common/RnD/ShadowElement.js +34 -0
- package/dist/Editor/common/RnD/SwitchViewport/SwitchViewport.js +40 -0
- package/dist/Editor/common/RnD/SwitchViewport/styles.js +24 -0
- package/dist/Editor/common/RnD/Theme/ViewportStimulator.js +63 -0
- package/dist/Editor/common/RnD/TransformHandles/CornerHandle.js +19 -0
- package/dist/Editor/common/RnD/TransformHandles/Icons/BottomRightIcon.js +13 -0
- package/dist/Editor/common/RnD/TransformHandles/SizeHandle.js +20 -0
- package/dist/Editor/common/RnD/TransformHandles/index.js +67 -0
- package/dist/Editor/common/RnD/Utils/alignmentDetection.js +26 -0
- package/dist/Editor/common/RnD/Utils/calculateDropItem.js +98 -0
- package/dist/Editor/common/RnD/Utils/collisionDetection.js +52 -0
- package/dist/Editor/common/RnD/Utils/gridDropItem.js +181 -0
- package/dist/Editor/common/RnD/Utils/index.js +251 -0
- package/dist/Editor/common/RnD/VirtualElement/index.js +77 -0
- package/dist/Editor/common/RnD/VirtualElement/styles.js +27 -0
- package/dist/Editor/common/RnD/VirtualElement/updateAutoProps.js +28 -0
- package/dist/Editor/common/RnD/index.js +567 -0
- package/dist/Editor/common/RnD/styles.js +4 -0
- package/dist/Editor/common/Section/index.js +21 -12
- package/dist/Editor/common/Section/styles.js +7 -4
- package/dist/Editor/common/Shorthands/elements.js +21 -9
- package/dist/Editor/common/StyleBuilder/boxStyle.js +30 -0
- package/dist/Editor/common/StyleBuilder/fieldTypes/bannerSpacing.js +18 -10
- package/dist/Editor/common/StyleBuilder/fieldTypes/saveAsTemplate.js +18 -5
- package/dist/Editor/common/StyleBuilder/fieldTypes/text.js +4 -2
- package/dist/Editor/common/StyleBuilder/index.js +6 -4
- package/dist/Editor/common/StyleBuilder/sectionStyle.js +13 -2
- package/dist/Editor/common/iconListV2.js +843 -0
- package/dist/Editor/commonStyle.js +6 -0
- package/dist/Editor/helper/RnD/focusOnNewItem.js +39 -0
- package/dist/Editor/helper/RnD/scrollToNewSection.js +24 -0
- package/dist/Editor/helper/breakpoint.js +5 -0
- package/dist/Editor/helper/index.js +139 -0
- package/dist/Editor/helper/theme.js +50 -1
- package/dist/Editor/hooks/useBreakpoints.js +34 -0
- package/dist/Editor/hooks/useMouseMove.js +36 -8
- package/dist/Editor/hooks/useWindowMessage.js +10 -7
- package/dist/Editor/hooks/withCommon.js +2 -1
- package/dist/Editor/hooks/withErrorHandling.js +14 -0
- package/dist/Editor/utils/RnD/RnDCtrlCmds.js +197 -0
- package/dist/Editor/utils/SlateUtilityFunctions.js +36 -4
- package/dist/Editor/utils/events.js +5 -0
- package/dist/Editor/utils/form.js +7 -2
- package/dist/Editor/utils/formfield.js +1 -1
- package/dist/Editor/utils/freegrid.js +91 -0
- package/dist/Editor/utils/helper.js +43 -0
- package/dist/Editor/utils/insertAppHeader.js +47 -40
- 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 {
|
|
4
|
+
import { Fade, Paper, Popper } from "@mui/material";
|
|
5
5
|
import AIInput from "./AIInput";
|
|
6
6
|
import { ReactEditor, useSlate } from "slate-react";
|
|
7
|
-
import {
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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 +
|
|
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
|
-
|
|
46
|
+
insertText(editor, text, {
|
|
35
47
|
at: nextLine.at
|
|
36
48
|
});
|
|
37
|
-
Transforms.
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: [
|
|
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(
|
|
300
|
-
|
|
282
|
+
children: /*#__PURE__*/_jsx(VoiceToText, {
|
|
283
|
+
otherProps: otherProps,
|
|
301
284
|
onSend: onSend,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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:
|
|
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
|
-
|
|
51
|
-
|
|
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,
|