@flozy/editor 2.0.6 → 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor/CommonEditor.js +1 -1
- package/dist/Editor/Editor.css +7 -0
- package/dist/Editor/Elements/Grid/Grid.js +1 -1
- package/dist/Editor/Elements/Grid/GridItem.js +0 -1
- package/dist/Editor/Toolbar/FormatTools/BlockButton.js +16 -8
- package/dist/Editor/Toolbar/PopupTool/index.js +7 -0
- package/dist/Editor/Toolbar/toolbarGroups.js +2 -2
- package/dist/Editor/common/Icon.js +6 -2
- package/dist/Editor/common/ImageSelector/ImageSelector.js +2 -1
- package/dist/Editor/helper/deserialize/index.js +107 -0
- package/dist/Editor/hooks/useKeys.js +21 -0
- package/dist/Editor/hooks/withCommon.js +2 -3
- package/dist/Editor/plugins/withHTML.js +41 -0
- package/dist/Editor/plugins/withTable.js +11 -9
- package/dist/Editor/utils/SlateUtilityFunctions.js +12 -35
- package/dist/Editor/utils/accordion.js +3 -1
- package/dist/Editor/utils/helper.js +13 -0
- package/package.json +2 -1
@@ -1,6 +1,6 @@
|
|
1
1
|
/* eslint-disable no-unused-vars */
|
2
2
|
import React, { useRef, useCallback, useEffect, useMemo, useState, forwardRef, useImperativeHandle } from "react";
|
3
|
-
import { createEditor,
|
3
|
+
import { createEditor, Transforms } from "slate";
|
4
4
|
import { Slate, Editable, ReactEditor } from "slate-react";
|
5
5
|
import { useDebounce } from "use-debounce";
|
6
6
|
import { getMarked, getBlock } from "./utils/SlateUtilityFunctions";
|
package/dist/Editor/Editor.css
CHANGED
@@ -51,7 +51,6 @@ const GridItem = props => {
|
|
51
51
|
const selected = hoverPath === path.join(",");
|
52
52
|
const [showTool] = useEditorSelection(editor);
|
53
53
|
const isEmpty = !readOnly && isEmptyNode(editor, element?.children, path) ? "empty" : "";
|
54
|
-
console.log(cellGHeight);
|
55
54
|
const GridItemToolbar = () => {
|
56
55
|
return selected && !showTool ? /*#__PURE__*/_jsx("div", {
|
57
56
|
contentEditable: false,
|
@@ -1,19 +1,27 @@
|
|
1
1
|
import React from "react";
|
2
2
|
import Icon from "../../common/Icon";
|
3
3
|
import Button from "../../common/Button";
|
4
|
-
import { toggleBlock, isBlockActive } from "../../utils/SlateUtilityFunctions.js";
|
4
|
+
import { toggleBlock, isBlockActive, isMarkActive, toggleMark } from "../../utils/SlateUtilityFunctions.js";
|
5
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
6
|
-
const
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
const MARK_TYPES = ["doublequote"];
|
7
|
+
const BlockButton = props => {
|
8
|
+
const {
|
9
|
+
editor,
|
10
|
+
format,
|
11
|
+
title
|
12
|
+
} = props;
|
13
|
+
const isMark = MARK_TYPES?.indexOf(format) >= 0;
|
14
|
+
const isActive = isMark ? isMarkActive(editor, format) : isBlockActive(editor, format);
|
11
15
|
return /*#__PURE__*/_jsx(Button, {
|
12
|
-
active:
|
16
|
+
active: isActive,
|
13
17
|
format: format,
|
14
18
|
onMouseDown: e => {
|
15
19
|
e.preventDefault();
|
16
|
-
|
20
|
+
if (isMark) {
|
21
|
+
toggleMark(editor, format);
|
22
|
+
} else {
|
23
|
+
toggleBlock(editor, format);
|
24
|
+
}
|
17
25
|
},
|
18
26
|
title: title,
|
19
27
|
children: /*#__PURE__*/_jsx(Icon, {
|
@@ -8,6 +8,7 @@ import useDrag from "../../hooks/useDrag";
|
|
8
8
|
import PopperHeader from "./PopperHeader";
|
9
9
|
import { TableUtil } from "../../utils/table";
|
10
10
|
import useWindowResize from "../../hooks/useWindowResize";
|
11
|
+
import useEvent from "../../hooks/useKeys";
|
11
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
12
13
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
13
14
|
const PopupTool = props => {
|
@@ -26,6 +27,7 @@ const PopupTool = props => {
|
|
26
27
|
const id = open ? "popup-edit-tool" : "";
|
27
28
|
const table = new TableUtil(editor);
|
28
29
|
const [size] = useWindowResize();
|
30
|
+
const [eventKey] = useEvent();
|
29
31
|
useEffect(() => {
|
30
32
|
if (event === "end" && anchorEl && !open) {
|
31
33
|
// for table cell selection
|
@@ -37,6 +39,11 @@ const PopupTool = props => {
|
|
37
39
|
setOpen(false);
|
38
40
|
}
|
39
41
|
}, [event, anchorEl]);
|
42
|
+
useEffect(() => {
|
43
|
+
if (eventKey) {
|
44
|
+
setOpen(false);
|
45
|
+
}
|
46
|
+
}, [eventKey]);
|
40
47
|
useEffect(() => {
|
41
48
|
if (!selection || !inFocus || Range.isCollapsed(selection) || Editor.string(editor, selection) === "") {
|
42
49
|
setAnchorEl(null);
|
@@ -103,9 +103,9 @@ export const toolbarGroups = [[{
|
|
103
103
|
group: "typography"
|
104
104
|
}, {
|
105
105
|
id: 14,
|
106
|
-
format: "
|
106
|
+
format: "doublequote",
|
107
107
|
type: "block",
|
108
|
-
title: "
|
108
|
+
title: "Double Quote",
|
109
109
|
group: "typography"
|
110
110
|
}], [{
|
111
111
|
id: 15,
|
@@ -8,8 +8,8 @@ import { SiLatex } from "react-icons/si";
|
|
8
8
|
import { RiDeleteColumn, RiDeleteRow } from "react-icons/ri";
|
9
9
|
import { IoIosImage } from "react-icons/io";
|
10
10
|
import { GridIcon, AccordionIcon, SignatureIcon, ButtonIcon, Carousal, FormIcon, BoldIcon, FontFamilyIcon, FontSizeIcon, ImageIcon, ItalicIcon, LinkIcon, StrikethroughIcon, TableIcon, UnderLineIcon, VideoIcon, CheckboxIcon, AppHeader, MoreHorizontal, UploadImage, DocsUpload, LeftArrow, RightArrow, CheckListButton, CheckListButtonActive, ExcelIcon, CsvIcon, DividerIcon } from "./iconslist";
|
11
|
-
import ArrowRightIcon from
|
12
|
-
import ArrowDropDownIcon from
|
11
|
+
import ArrowRightIcon from "@mui/icons-material/ArrowRight";
|
12
|
+
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
14
14
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
15
15
|
const iconList = {
|
@@ -51,6 +51,10 @@ const iconList = {
|
|
51
51
|
size: 20,
|
52
52
|
fill: "#64748B"
|
53
53
|
}),
|
54
|
+
doublequote: /*#__PURE__*/_jsx(MdFormatQuote, {
|
55
|
+
size: 20,
|
56
|
+
fill: "#64748B"
|
57
|
+
}),
|
54
58
|
superscript: /*#__PURE__*/_jsx(FaSuperscript, {
|
55
59
|
size: 15,
|
56
60
|
fill: "#64748B"
|
@@ -69,8 +69,9 @@ const ImageSelector = props => {
|
|
69
69
|
children: /*#__PURE__*/_jsxs(Tabs, {
|
70
70
|
sx: classes.tabs,
|
71
71
|
onChange: handleTabChange,
|
72
|
-
orientation: "horizontal",
|
73
72
|
value: tabValue,
|
73
|
+
variant: "scrollable",
|
74
|
+
scrollButtons: "auto",
|
74
75
|
children: [/*#__PURE__*/_jsx(Tab, {
|
75
76
|
className: `${isActive("upload")} ${TAB_SHOW[title].indexOf("upload") === -1 ? "hidden" : ""}`,
|
76
77
|
sx: classes.tab,
|
@@ -0,0 +1,107 @@
|
|
1
|
+
import { jsx } from "slate-hyperscript";
|
2
|
+
const ELEMENT_TAGS = {
|
3
|
+
A: el => ({
|
4
|
+
type: "link",
|
5
|
+
url: el.getAttribute("href")
|
6
|
+
}),
|
7
|
+
BLOCKQUOTE: () => ({
|
8
|
+
type: "quote"
|
9
|
+
}),
|
10
|
+
H1: () => ({
|
11
|
+
type: "headingOne"
|
12
|
+
}),
|
13
|
+
H2: () => ({
|
14
|
+
type: "headingTwo"
|
15
|
+
}),
|
16
|
+
H3: () => ({
|
17
|
+
type: "headingThree"
|
18
|
+
}),
|
19
|
+
H4: () => ({
|
20
|
+
type: "headingFour"
|
21
|
+
}),
|
22
|
+
H5: () => ({
|
23
|
+
type: "headingFive"
|
24
|
+
}),
|
25
|
+
H6: () => ({
|
26
|
+
type: "headingSix"
|
27
|
+
}),
|
28
|
+
IMG: el => ({
|
29
|
+
type: "image",
|
30
|
+
url: el.getAttribute("src")
|
31
|
+
}),
|
32
|
+
LI: () => ({
|
33
|
+
type: "list-item"
|
34
|
+
}),
|
35
|
+
UL: () => ({
|
36
|
+
type: "unorderedList"
|
37
|
+
}),
|
38
|
+
OL: () => ({
|
39
|
+
type: "orderedList"
|
40
|
+
}),
|
41
|
+
P: () => ({
|
42
|
+
type: "paragraph"
|
43
|
+
}),
|
44
|
+
PRE: () => ({
|
45
|
+
type: "code"
|
46
|
+
})
|
47
|
+
};
|
48
|
+
|
49
|
+
// COMPAT: `B` is omitted here because Google Docs uses `<b>` in weird ways.
|
50
|
+
const TEXT_TAGS = {
|
51
|
+
CODE: () => ({
|
52
|
+
code: true
|
53
|
+
}),
|
54
|
+
DEL: () => ({
|
55
|
+
strikethrough: true
|
56
|
+
}),
|
57
|
+
EM: () => ({
|
58
|
+
italic: true
|
59
|
+
}),
|
60
|
+
I: () => ({
|
61
|
+
italic: true
|
62
|
+
}),
|
63
|
+
S: () => ({
|
64
|
+
strikethrough: true
|
65
|
+
}),
|
66
|
+
STRONG: () => ({
|
67
|
+
bold: true
|
68
|
+
}),
|
69
|
+
U: () => ({
|
70
|
+
underline: true
|
71
|
+
})
|
72
|
+
};
|
73
|
+
const deserialize = el => {
|
74
|
+
if (el.nodeType === 3) {
|
75
|
+
return el.textContent;
|
76
|
+
} else if (el.nodeType !== 1) {
|
77
|
+
return null;
|
78
|
+
} else if (el.nodeName === "BR") {
|
79
|
+
return "\n";
|
80
|
+
}
|
81
|
+
const {
|
82
|
+
nodeName
|
83
|
+
} = el;
|
84
|
+
let parent = el;
|
85
|
+
if (nodeName === "PRE" && el.childNodes[0] && el.childNodes[0].nodeName === "CODE") {
|
86
|
+
parent = el.childNodes[0];
|
87
|
+
}
|
88
|
+
let children = Array.from(parent.childNodes).map(deserialize).flat();
|
89
|
+
if (children.length === 0) {
|
90
|
+
children = [{
|
91
|
+
text: ""
|
92
|
+
}];
|
93
|
+
}
|
94
|
+
if (el.nodeName === "BODY") {
|
95
|
+
return jsx("fragment", {}, children);
|
96
|
+
}
|
97
|
+
if (ELEMENT_TAGS[nodeName]) {
|
98
|
+
const attrs = ELEMENT_TAGS[nodeName](el);
|
99
|
+
return jsx("element", attrs, children);
|
100
|
+
}
|
101
|
+
if (TEXT_TAGS[nodeName]) {
|
102
|
+
const attrs = TEXT_TAGS[nodeName](el);
|
103
|
+
return children.map(child => jsx("text", attrs, child));
|
104
|
+
}
|
105
|
+
return children;
|
106
|
+
};
|
107
|
+
export default deserialize;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { useEffect, useState } from "react";
|
2
|
+
const useEvent = () => {
|
3
|
+
const [event, setEvent] = useState("");
|
4
|
+
useEffect(() => {
|
5
|
+
addListener();
|
6
|
+
return () => {
|
7
|
+
removeListener();
|
8
|
+
};
|
9
|
+
}, []);
|
10
|
+
const onKeyUp = e => {
|
11
|
+
setEvent(e.keyCode);
|
12
|
+
};
|
13
|
+
const addListener = () => {
|
14
|
+
document.addEventListener("keyup", onKeyUp);
|
15
|
+
};
|
16
|
+
const removeListener = () => {
|
17
|
+
document.removeEventListener("keyup", onKeyUp);
|
18
|
+
};
|
19
|
+
return [event];
|
20
|
+
};
|
21
|
+
export default useEvent;
|
@@ -6,9 +6,8 @@ import withEmbeds from "../plugins/withEmbeds";
|
|
6
6
|
import withEquation from "../plugins/withEquation";
|
7
7
|
import withMentions from "../plugins/withMentions";
|
8
8
|
import withLayout from "../plugins/withLayout";
|
9
|
-
|
10
|
-
|
9
|
+
import withHtml from "../plugins/withHTML";
|
11
10
|
const withCommon = (props, rest = {}) => {
|
12
|
-
return rest.needLayout ? withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props)))))))) : withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props)))))));
|
11
|
+
return rest.needLayout ? withHtml(withEquation(withLayout(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props))))))))) : withHtml(withEquation(withHistory(withEmbeds(withTables(withLinks(withMentions(withReact(props))))))));
|
13
12
|
};
|
14
13
|
export default withCommon;
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { Transforms, Editor, Element } from "slate";
|
2
|
+
import deserialize from "../helper/deserialize";
|
3
|
+
const withHtml = editor => {
|
4
|
+
const {
|
5
|
+
insertData,
|
6
|
+
isInline,
|
7
|
+
isVoid
|
8
|
+
} = editor;
|
9
|
+
editor.isInline = element => {
|
10
|
+
return element.type === "link" ? true : isInline(element);
|
11
|
+
};
|
12
|
+
editor.isVoid = element => {
|
13
|
+
return element.type === "image" ? true : isVoid(element);
|
14
|
+
};
|
15
|
+
editor.insertData = data => {
|
16
|
+
const slateHTML = data?.getData("application/x-slate-fragment");
|
17
|
+
const html = data?.getData("text/html");
|
18
|
+
if (slateHTML) {
|
19
|
+
const [tableNode] = Editor.nodes(editor, {
|
20
|
+
match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === "table"
|
21
|
+
});
|
22
|
+
// do not paste table cell inside table cell
|
23
|
+
// only plain text for internal paste
|
24
|
+
if (tableNode && tableNode[0]) {
|
25
|
+
const text = data?.getData("text/plain");
|
26
|
+
Transforms.insertText(editor, text);
|
27
|
+
} else {
|
28
|
+
insertData(data);
|
29
|
+
}
|
30
|
+
} else if (html) {
|
31
|
+
const parsed = new DOMParser().parseFromString(html, "text/html");
|
32
|
+
const fragment = deserialize(parsed.body);
|
33
|
+
Transforms.insertFragment(editor, fragment);
|
34
|
+
return;
|
35
|
+
} else {
|
36
|
+
insertData(data);
|
37
|
+
}
|
38
|
+
};
|
39
|
+
return editor;
|
40
|
+
};
|
41
|
+
export default withHtml;
|
@@ -5,15 +5,17 @@ const withTable = editor => {
|
|
5
5
|
deleteBackward,
|
6
6
|
deleteForward
|
7
7
|
} = editor;
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
}
|
8
|
+
|
9
|
+
// editor.insertData = (data) => {
|
10
|
+
// try {
|
11
|
+
// // const text = data.getData("text/plain");
|
12
|
+
// Transforms.insertFragment(editor, data);
|
13
|
+
// return;
|
14
|
+
// } catch (err) {
|
15
|
+
// console.log(err);
|
16
|
+
// }
|
17
|
+
// };
|
18
|
+
|
17
19
|
editor.deleteBackward = unit => {
|
18
20
|
const {
|
19
21
|
selection
|
@@ -39,6 +39,7 @@ import { getBreakPointsValue } from "../helper/theme";
|
|
39
39
|
import Variables from "../Elements/Variables/Variable";
|
40
40
|
import insertNewLine from "./insertNewLine";
|
41
41
|
import Divider from "../Elements/Divider/Divider";
|
42
|
+
import { getBorderColor } from "./helper";
|
42
43
|
import { jsx as _jsx } from "react/jsx-runtime";
|
43
44
|
const alignment = ["alignLeft", "alignRight", "alignCenter"];
|
44
45
|
const list_types = ["orderedList", "unorderedList"];
|
@@ -160,6 +161,7 @@ export const activeMark = (editor, format) => {
|
|
160
161
|
}
|
161
162
|
};
|
162
163
|
export const getMarked = (leaf, children) => {
|
164
|
+
const className = leaf?.doublequote ? "doublequote" : "";
|
163
165
|
if (leaf.bold) {
|
164
166
|
children = /*#__PURE__*/_jsx("strong", {
|
165
167
|
children: children
|
@@ -198,7 +200,9 @@ export const getMarked = (leaf, children) => {
|
|
198
200
|
children: children
|
199
201
|
});
|
200
202
|
}
|
201
|
-
|
203
|
+
// cover under single span
|
204
|
+
if (leaf.color || leaf.bgColor || leaf.fontSize || leaf.fontFamily || leaf.fontWeight) {
|
205
|
+
const family = fontFamilyMap[leaf?.fontFamily];
|
202
206
|
const textStyles = leaf?.color?.indexOf("gradient") >= 0 ? {
|
203
207
|
background: leaf?.color?.concat("text"),
|
204
208
|
WebkitBackgroundClip: "text",
|
@@ -206,45 +210,17 @@ export const getMarked = (leaf, children) => {
|
|
206
210
|
} : {
|
207
211
|
color: leaf.color
|
208
212
|
};
|
209
|
-
children = /*#__PURE__*/_jsx("span", {
|
210
|
-
style: {
|
211
|
-
...textStyles
|
212
|
-
},
|
213
|
-
children: children
|
214
|
-
});
|
215
|
-
}
|
216
|
-
if (leaf.bgColor) {
|
217
|
-
children = /*#__PURE__*/_jsx("span", {
|
218
|
-
style: {
|
219
|
-
background: leaf.bgColor
|
220
|
-
},
|
221
|
-
children: children
|
222
|
-
});
|
223
|
-
}
|
224
|
-
if (leaf.fontSize) {
|
225
213
|
children = /*#__PURE__*/_jsx(Box, {
|
214
|
+
className: className,
|
226
215
|
component: "span",
|
227
216
|
sx: {
|
228
217
|
fontSize: {
|
229
218
|
lg: sizeMap[leaf.fontSize] || leaf.fontSize,
|
230
219
|
...getBreakPointsValue(leaf.fontSize, null, "overrideText")
|
231
|
-
}
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
}
|
236
|
-
if (leaf.fontFamily) {
|
237
|
-
const family = fontFamilyMap[leaf.fontFamily];
|
238
|
-
children = /*#__PURE__*/_jsx("span", {
|
239
|
-
style: {
|
240
|
-
fontFamily: family
|
241
|
-
},
|
242
|
-
children: children
|
243
|
-
});
|
244
|
-
}
|
245
|
-
if (leaf.fontWeight) {
|
246
|
-
children = /*#__PURE__*/_jsx("span", {
|
247
|
-
style: {
|
220
|
+
},
|
221
|
+
background: leaf.bgColor,
|
222
|
+
...textStyles,
|
223
|
+
fontFamily: family,
|
248
224
|
fontWeight: leaf.fontWeight
|
249
225
|
},
|
250
226
|
children: children
|
@@ -300,7 +276,8 @@ export const getBlock = props => {
|
|
300
276
|
...attributes,
|
301
277
|
...element.attr,
|
302
278
|
style: {
|
303
|
-
borderColor: element?.color || "transparent",
|
279
|
+
// borderColor: element?.color || "transparent",
|
280
|
+
...getBorderColor(element?.color || "transparent", 3),
|
304
281
|
background: element?.bgColor || "none",
|
305
282
|
padding: `${element?.bgColor ? "16px" : "0px"} 8px`,
|
306
283
|
borderRadius: `${element?.color ? "0px" : "12px"} 12px 12px ${element?.color ? "0px" : "12px"}`,
|
@@ -1,7 +1,9 @@
|
|
1
1
|
import { Transforms } from "slate";
|
2
2
|
import insertNewLine from "./insertNewLine";
|
3
|
+
import { getSelectedText } from "./helper";
|
3
4
|
export const insertAccordion = (editor, path) => {
|
4
5
|
try {
|
6
|
+
const selectedText = getSelectedText(editor);
|
5
7
|
const accordion = {
|
6
8
|
type: "accordion",
|
7
9
|
children: [{
|
@@ -9,7 +11,7 @@ export const insertAccordion = (editor, path) => {
|
|
9
11
|
children: [{
|
10
12
|
type: "paragraph",
|
11
13
|
children: [{
|
12
|
-
text: ""
|
14
|
+
text: selectedText || ""
|
13
15
|
}]
|
14
16
|
}]
|
15
17
|
}, {
|
@@ -43,6 +43,19 @@ export const gradientBorder = color => {
|
|
43
43
|
};
|
44
44
|
}
|
45
45
|
};
|
46
|
+
export const getBorderColor = (color, borderWidth = 3) => {
|
47
|
+
if (color?.indexOf("linear") > -1) {
|
48
|
+
return {
|
49
|
+
borderImage: `${color} ${borderWidth}`,
|
50
|
+
borderWidth: `0px 0px 0px ${borderWidth}px`,
|
51
|
+
borderStyle: "solid"
|
52
|
+
};
|
53
|
+
} else {
|
54
|
+
return {
|
55
|
+
borderColor: color || "transparent"
|
56
|
+
};
|
57
|
+
}
|
58
|
+
};
|
46
59
|
export const absoluteLink = url => {
|
47
60
|
try {
|
48
61
|
if (url?.indexOf("://") === -1) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@flozy/editor",
|
3
|
-
"version": "2.0.
|
3
|
+
"version": "2.0.8",
|
4
4
|
"description": "An Editor for flozy app brain",
|
5
5
|
"files": [
|
6
6
|
"dist"
|
@@ -41,6 +41,7 @@
|
|
41
41
|
"react-slick": "^0.29.0",
|
42
42
|
"slate": "^0.94.1",
|
43
43
|
"slate-history": "^0.93.0",
|
44
|
+
"slate-hyperscript": "^0.100.0",
|
44
45
|
"slate-react": "^0.98.3",
|
45
46
|
"styled-components": "^5.3.11",
|
46
47
|
"use-debounce": "^10.0.0",
|