@flozy/editor 1.0.5 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor/CollaborativeEditor.js +116 -0
- package/dist/Editor/CommonEditor.js +132 -0
- package/dist/Editor/Editor.css +115 -0
- package/dist/Editor/Elements/CodeToText/CodeToText.css +57 -0
- package/dist/Editor/Elements/CodeToText/CodeToText.js +112 -0
- package/dist/Editor/Elements/CodeToText/CodeToTextButton.js +18 -0
- package/dist/Editor/Elements/CodeToText/HtmlCode.js +54 -0
- package/dist/Editor/Elements/CodeToText/HtmlContextMenu.js +39 -0
- package/dist/Editor/Elements/Color Picker/ColorPicker.css +38 -0
- package/dist/Editor/Elements/Color Picker/ColorPicker.js +116 -0
- package/dist/Editor/Elements/Color Picker/defaultColors.js +1 -0
- package/dist/Editor/Elements/Embed/Embed.css +14 -0
- package/dist/Editor/Elements/Embed/Embed.js +94 -0
- package/dist/Editor/Elements/Embed/Image.js +70 -0
- package/dist/Editor/Elements/Embed/Video.js +62 -0
- package/dist/Editor/Elements/Equation/Equation.js +24 -0
- package/dist/Editor/Elements/Equation/EquationButton.js +66 -0
- package/dist/Editor/Elements/Equation/styles.css +4 -0
- package/dist/Editor/Elements/Grid/Grid.js +53 -0
- package/dist/Editor/Elements/Grid/GridButton.js +19 -0
- package/dist/Editor/Elements/Grid/GridItem.js +53 -0
- package/dist/Editor/Elements/ID/Id.js +56 -0
- package/dist/Editor/Elements/Link/Link.js +34 -0
- package/dist/Editor/Elements/Link/LinkButton.js +77 -0
- package/dist/Editor/Elements/Link/styles.css +20 -0
- package/dist/Editor/Elements/Mentions/Mentions.js +34 -0
- package/dist/Editor/Elements/NewLine/NewLineButton.js +22 -0
- package/dist/Editor/Elements/Table/Table.js +15 -0
- package/dist/Editor/Elements/Table/TableSelector.css +18 -0
- package/dist/Editor/Elements/Table/TableSelector.js +93 -0
- package/dist/Editor/Elements/TableContextMenu/TableContextMenu.js +91 -0
- package/dist/Editor/Elements/TableContextMenu/styles.css +18 -0
- package/dist/Editor/RemoteCursorOverlay/Overlay.js +75 -0
- package/dist/Editor/Toolbar/Toolbar.js +166 -0
- package/dist/Editor/Toolbar/styles.css +28 -0
- package/dist/Editor/Toolbar/toolbarGroups.js +131 -0
- package/dist/Editor/Toolbar/toolbarIcons/align-center.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/align-left.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/align-right.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/blockquote.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/bold.png +0 -0
- package/dist/Editor/Toolbar/toolbarIcons/fontColor.svg +4 -0
- package/dist/Editor/Toolbar/toolbarIcons/headingOne.svg +3 -0
- package/dist/Editor/Toolbar/toolbarIcons/headingTwo.svg +3 -0
- package/dist/Editor/Toolbar/toolbarIcons/italic.png +0 -0
- package/dist/Editor/Toolbar/toolbarIcons/link.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/orderedList.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/strikethrough.png +0 -0
- package/dist/Editor/Toolbar/toolbarIcons/subscript.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/superscript.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/textColor.png +0 -0
- package/dist/Editor/Toolbar/toolbarIcons/underline.png +0 -0
- package/dist/Editor/Toolbar/toolbarIcons/unlink.svg +1 -0
- package/dist/Editor/Toolbar/toolbarIcons/unorderedList.svg +1 -0
- package/dist/Editor/YjsProvider.js +9 -0
- package/dist/Editor/common/Button.js +21 -0
- package/dist/Editor/common/Icon.js +114 -0
- package/dist/Editor/common/MentionsPopup.js +54 -0
- package/dist/Editor/hooks/useMentions.js +44 -0
- package/dist/Editor/hooks/withCollaborative.js +15 -0
- package/dist/Editor/hooks/withCommon.js +11 -0
- package/dist/Editor/plugins/withEmbeds.js +29 -0
- package/dist/Editor/plugins/withEquation.js +8 -0
- package/dist/Editor/plugins/withLinks.js +8 -0
- package/dist/Editor/plugins/withMentions.js +18 -0
- package/dist/Editor/plugins/withTable.js +61 -0
- package/dist/Editor/utils/SlateUtilityFunctions.js +224 -0
- package/dist/Editor/utils/customHooks/useContextMenu.js +37 -0
- package/dist/Editor/utils/customHooks/useFormat.js +21 -0
- package/dist/Editor/utils/customHooks/usePopup.js +21 -0
- package/dist/Editor/utils/customHooks/useResize.js +47 -0
- package/dist/Editor/utils/draftToSlate.js +111 -0
- package/dist/Editor/utils/embed.js +24 -0
- package/dist/Editor/utils/equation.js +23 -0
- package/dist/Editor/utils/events.js +76 -0
- package/dist/Editor/utils/grid.js +13 -0
- package/dist/Editor/utils/gridItem.js +19 -0
- package/dist/Editor/utils/link.js +52 -0
- package/dist/Editor/utils/mentions.js +12 -0
- package/dist/Editor/utils/paragraph.js +6 -0
- package/dist/Editor/utils/serializer.js +28 -0
- package/dist/Editor/utils/table.js +129 -0
- package/dist/index.js +4 -0
- package/package.json +18 -8
@@ -0,0 +1,224 @@
|
|
1
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2
|
+
import { Editor, Transforms, Element as SlateElement } from "slate";
|
3
|
+
import Link from "../Elements/Link/Link";
|
4
|
+
import Image from "../Elements/Embed/Image";
|
5
|
+
import Video from "../Elements/Embed/Video";
|
6
|
+
import Equation from "../Elements/Equation/Equation";
|
7
|
+
import HtmlCode from "../Elements/CodeToText/HtmlCode";
|
8
|
+
import Table from "../Elements/Table/Table";
|
9
|
+
import Mentions from "../Elements/Mentions/Mentions";
|
10
|
+
import Grid from "../Elements/Grid/Grid";
|
11
|
+
import GridItem from "../Elements/Grid/GridItem";
|
12
|
+
const alignment = ["alignLeft", "alignRight", "alignCenter"];
|
13
|
+
const list_types = ["orderedList", "unorderedList"];
|
14
|
+
export const sizeMap = {
|
15
|
+
small: "0.75em",
|
16
|
+
normal: "1em",
|
17
|
+
medium: "1.75em",
|
18
|
+
huge: "2.5em"
|
19
|
+
};
|
20
|
+
export const fontFamilyMap = {
|
21
|
+
sans: "Helvetica,Arial, sans serif",
|
22
|
+
serif: "Georgia, Times New Roaman,serif",
|
23
|
+
monospace: "Monaco, Courier New,monospace"
|
24
|
+
};
|
25
|
+
export const toggleBlock = (editor, format) => {
|
26
|
+
const isActive = isBlockActive(editor, format);
|
27
|
+
const isList = list_types.includes(format);
|
28
|
+
const isIndent = alignment.includes(format);
|
29
|
+
const isAligned = alignment.some(alignmentType => isBlockActive(editor, alignmentType));
|
30
|
+
|
31
|
+
/*If the node is already aligned and change in indent is called we should unwrap it first and split the node to prevent
|
32
|
+
messy, nested DOM structure and bugs due to that.*/
|
33
|
+
if (isAligned && isIndent) {
|
34
|
+
Transforms.unwrapNodes(editor, {
|
35
|
+
match: n => alignment.includes(!Editor.isEditor(n) && SlateElement.isElement(n) && n.type),
|
36
|
+
split: true
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
40
|
+
/* Wraping the nodes for alignment, to allow it to co-exist with other block level operations*/
|
41
|
+
if (isIndent) {
|
42
|
+
Transforms.wrapNodes(editor, {
|
43
|
+
type: format,
|
44
|
+
children: []
|
45
|
+
});
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
Transforms.unwrapNodes(editor, {
|
49
|
+
match: n => list_types.includes(!Editor.isEditor(n) && SlateElement.isElement(n) && n.type),
|
50
|
+
split: true
|
51
|
+
});
|
52
|
+
Transforms.setNodes(editor, {
|
53
|
+
type: isActive ? "paragraph" : isList ? "list-item" : format
|
54
|
+
});
|
55
|
+
if (isList && !isActive) {
|
56
|
+
Transforms.wrapNodes(editor, {
|
57
|
+
type: format,
|
58
|
+
children: []
|
59
|
+
});
|
60
|
+
}
|
61
|
+
};
|
62
|
+
export const addMarkData = (editor, data) => {
|
63
|
+
Editor.addMark(editor, data.format, data.value);
|
64
|
+
};
|
65
|
+
export const toggleMark = (editor, format) => {
|
66
|
+
const isActive = isMarkActive(editor, format);
|
67
|
+
if (isActive) {
|
68
|
+
Editor.removeMark(editor, format);
|
69
|
+
} else {
|
70
|
+
Editor.addMark(editor, format, true);
|
71
|
+
}
|
72
|
+
};
|
73
|
+
export const isMarkActive = (editor, format) => {
|
74
|
+
const marks = Editor.marks(editor);
|
75
|
+
return marks ? marks[format] === true : false;
|
76
|
+
};
|
77
|
+
export const isBlockActive = (editor, format) => {
|
78
|
+
const [match] = Editor.nodes(editor, {
|
79
|
+
match: n => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === format
|
80
|
+
});
|
81
|
+
return !!match;
|
82
|
+
};
|
83
|
+
export const activeMark = (editor, format) => {
|
84
|
+
const defaultMarkData = {
|
85
|
+
color: "black",
|
86
|
+
bgColor: "black",
|
87
|
+
fontSize: "normal",
|
88
|
+
fontFamily: "sans"
|
89
|
+
};
|
90
|
+
const marks = Editor.marks(editor);
|
91
|
+
const defaultValue = defaultMarkData[format];
|
92
|
+
return marks?.[format] ?? defaultValue;
|
93
|
+
};
|
94
|
+
export const getMarked = (leaf, children) => {
|
95
|
+
if (leaf.bold) {
|
96
|
+
children = /*#__PURE__*/React.createElement("strong", null, children);
|
97
|
+
}
|
98
|
+
if (leaf.code) {
|
99
|
+
children = /*#__PURE__*/React.createElement("code", null, children);
|
100
|
+
}
|
101
|
+
if (leaf.italic) {
|
102
|
+
children = /*#__PURE__*/React.createElement("em", null, children);
|
103
|
+
}
|
104
|
+
if (leaf.strikethrough) {
|
105
|
+
children = /*#__PURE__*/React.createElement("span", {
|
106
|
+
style: {
|
107
|
+
textDecoration: "line-through"
|
108
|
+
}
|
109
|
+
}, children);
|
110
|
+
}
|
111
|
+
if (leaf.underline) {
|
112
|
+
children = /*#__PURE__*/React.createElement("u", null, children);
|
113
|
+
}
|
114
|
+
if (leaf.superscript) {
|
115
|
+
children = /*#__PURE__*/React.createElement("sup", null, children);
|
116
|
+
}
|
117
|
+
if (leaf.subscript) {
|
118
|
+
children = /*#__PURE__*/React.createElement("sub", null, children);
|
119
|
+
}
|
120
|
+
if (leaf.color) {
|
121
|
+
children = /*#__PURE__*/React.createElement("span", {
|
122
|
+
style: {
|
123
|
+
color: leaf.color
|
124
|
+
}
|
125
|
+
}, children);
|
126
|
+
}
|
127
|
+
if (leaf.bgColor) {
|
128
|
+
children = /*#__PURE__*/React.createElement("span", {
|
129
|
+
style: {
|
130
|
+
backgroundColor: leaf.bgColor
|
131
|
+
}
|
132
|
+
}, children);
|
133
|
+
}
|
134
|
+
if (leaf.fontSize) {
|
135
|
+
const size = sizeMap[leaf.fontSize];
|
136
|
+
children = /*#__PURE__*/React.createElement("span", {
|
137
|
+
style: {
|
138
|
+
fontSize: size
|
139
|
+
}
|
140
|
+
}, children);
|
141
|
+
}
|
142
|
+
if (leaf.fontFamily) {
|
143
|
+
const family = fontFamilyMap[leaf.fontFamily];
|
144
|
+
children = /*#__PURE__*/React.createElement("span", {
|
145
|
+
style: {
|
146
|
+
fontFamily: family
|
147
|
+
}
|
148
|
+
}, children);
|
149
|
+
}
|
150
|
+
return children;
|
151
|
+
};
|
152
|
+
export const getBlock = props => {
|
153
|
+
const {
|
154
|
+
element,
|
155
|
+
children
|
156
|
+
} = props;
|
157
|
+
const attributes = props.attributes ?? {};
|
158
|
+
switch (element.type) {
|
159
|
+
case "headingOne":
|
160
|
+
return /*#__PURE__*/React.createElement("h1", _extends({}, attributes, element.attr), children);
|
161
|
+
case "headingTwo":
|
162
|
+
return /*#__PURE__*/React.createElement("h2", _extends({}, attributes, element.attr), children);
|
163
|
+
case "headingThree":
|
164
|
+
return /*#__PURE__*/React.createElement("h3", _extends({}, attributes, element.attr), children);
|
165
|
+
case "blockquote":
|
166
|
+
return /*#__PURE__*/React.createElement("blockquote", _extends({}, attributes, element.attr), children);
|
167
|
+
case "alignLeft":
|
168
|
+
return /*#__PURE__*/React.createElement("div", _extends({
|
169
|
+
style: {
|
170
|
+
listStylePosition: "inside"
|
171
|
+
}
|
172
|
+
}, attributes, element.attr), children);
|
173
|
+
case "alignCenter":
|
174
|
+
return /*#__PURE__*/React.createElement("div", _extends({
|
175
|
+
style: {
|
176
|
+
display: "flex",
|
177
|
+
alignItems: "center",
|
178
|
+
listStylePosition: "inside",
|
179
|
+
flexDirection: "column"
|
180
|
+
}
|
181
|
+
}, attributes, element.attr), children);
|
182
|
+
case "alignRight":
|
183
|
+
return /*#__PURE__*/React.createElement("div", _extends({
|
184
|
+
style: {
|
185
|
+
display: "flex",
|
186
|
+
alignItems: "flex-end",
|
187
|
+
listStylePosition: "inside",
|
188
|
+
flexDirection: "column"
|
189
|
+
}
|
190
|
+
}, attributes, element.attr), children);
|
191
|
+
case "list-item":
|
192
|
+
return /*#__PURE__*/React.createElement("li", _extends({}, attributes, element.attr), children);
|
193
|
+
case "orderedList":
|
194
|
+
return /*#__PURE__*/React.createElement("ol", _extends({
|
195
|
+
type: "1"
|
196
|
+
}, attributes), children);
|
197
|
+
case "unorderedList":
|
198
|
+
return /*#__PURE__*/React.createElement("ul", attributes, children);
|
199
|
+
case "link":
|
200
|
+
return /*#__PURE__*/React.createElement(Link, props);
|
201
|
+
case "table":
|
202
|
+
return /*#__PURE__*/React.createElement(Table, props);
|
203
|
+
case "table-row":
|
204
|
+
return /*#__PURE__*/React.createElement("tr", attributes, children);
|
205
|
+
case "table-cell":
|
206
|
+
return /*#__PURE__*/React.createElement("td", _extends({}, element.attr, attributes), children);
|
207
|
+
case "image":
|
208
|
+
return /*#__PURE__*/React.createElement(Image, props);
|
209
|
+
case "video":
|
210
|
+
return /*#__PURE__*/React.createElement(Video, props);
|
211
|
+
case "equation":
|
212
|
+
return /*#__PURE__*/React.createElement(Equation, props);
|
213
|
+
case "htmlCode":
|
214
|
+
return /*#__PURE__*/React.createElement(HtmlCode, props);
|
215
|
+
case "mention":
|
216
|
+
return /*#__PURE__*/React.createElement(Mentions, props);
|
217
|
+
case "grid":
|
218
|
+
return /*#__PURE__*/React.createElement(Grid, props);
|
219
|
+
case "grid-item":
|
220
|
+
return /*#__PURE__*/React.createElement(GridItem, props);
|
221
|
+
default:
|
222
|
+
return /*#__PURE__*/React.createElement("div", _extends({}, element.attr, attributes), children);
|
223
|
+
}
|
224
|
+
};
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { useState, useEffect } from 'react';
|
2
|
+
import useFormat from './useFormat.js';
|
3
|
+
|
4
|
+
//This hook returns should we show the custom context menu and where to show it.
|
5
|
+
const useContextMenu = (editor, format, setSelection) => {
|
6
|
+
const isFormat = useFormat(editor, format);
|
7
|
+
const [showMenu, setShowMenu] = useState(false);
|
8
|
+
const [menuLocation, setMenuLocation] = useState({
|
9
|
+
top: '0px',
|
10
|
+
left: '0px'
|
11
|
+
});
|
12
|
+
const handleClick = () => {
|
13
|
+
setShowMenu(false);
|
14
|
+
};
|
15
|
+
const handleContextMenu = e => {
|
16
|
+
if (!isFormat) return;
|
17
|
+
setSelection(editor.selection);
|
18
|
+
e.preventDefault();
|
19
|
+
setShowMenu(true);
|
20
|
+
const xPos = e.pageX + "px";
|
21
|
+
const yPos = e.pageY + "px";
|
22
|
+
setMenuLocation({
|
23
|
+
top: yPos,
|
24
|
+
left: xPos
|
25
|
+
});
|
26
|
+
};
|
27
|
+
useEffect(() => {
|
28
|
+
document.addEventListener('click', handleClick);
|
29
|
+
document.addEventListener('contextmenu', handleContextMenu);
|
30
|
+
return () => {
|
31
|
+
document.removeEventListener('click', handleClick);
|
32
|
+
document.removeEventListener('contextmenu', handleContextMenu);
|
33
|
+
};
|
34
|
+
}, [isFormat]);
|
35
|
+
return [showMenu, menuLocation];
|
36
|
+
};
|
37
|
+
export default useContextMenu;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
import { Editor, Element } from 'slate';
|
3
|
+
|
4
|
+
// This hook returns if the node in the current selection matches the format passed to it.
|
5
|
+
const useFormat = (editor, format) => {
|
6
|
+
const [isFormat, setIsFormat] = useState(false);
|
7
|
+
useEffect(() => {
|
8
|
+
if (editor.selection) {
|
9
|
+
// It matches at the editor.selection location by default, so if null handle it seperately.
|
10
|
+
const [node] = Editor.nodes(editor, {
|
11
|
+
match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === format
|
12
|
+
});
|
13
|
+
setIsFormat(!!node);
|
14
|
+
} else {
|
15
|
+
setIsFormat(false);
|
16
|
+
}
|
17
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
18
|
+
}, [editor.selection]);
|
19
|
+
return isFormat;
|
20
|
+
};
|
21
|
+
export default useFormat;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { useState, useEffect } from 'react';
|
2
|
+
|
3
|
+
//This hook returns if the click was inside the popUp ref or outside it .
|
4
|
+
function usePopup(popupRef) {
|
5
|
+
const [showPopup, setShowPopup] = useState(false);
|
6
|
+
useEffect(() => {
|
7
|
+
const handleDocumentClick = e => {
|
8
|
+
const clickedComponent = e.target;
|
9
|
+
if (!popupRef?.current?.contains(clickedComponent)) {
|
10
|
+
setShowPopup(false);
|
11
|
+
}
|
12
|
+
};
|
13
|
+
document.addEventListener('click', handleDocumentClick);
|
14
|
+
return () => {
|
15
|
+
document.removeEventListener('click', handleDocumentClick);
|
16
|
+
};
|
17
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
18
|
+
}, []);
|
19
|
+
return [showPopup, setShowPopup];
|
20
|
+
}
|
21
|
+
export default usePopup;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import { useState } from "react";
|
2
|
+
const useResize = ({
|
3
|
+
parentDOM,
|
4
|
+
size: defaultSize
|
5
|
+
}) => {
|
6
|
+
const {
|
7
|
+
width
|
8
|
+
} = parentDOM?.getBoundingClientRect() || {
|
9
|
+
...defaultSize
|
10
|
+
};
|
11
|
+
const [size, setSize] = useState({
|
12
|
+
height: 300,
|
13
|
+
widthInPercent: 100,
|
14
|
+
...defaultSize
|
15
|
+
});
|
16
|
+
const [resizing, setResizing] = useState(false);
|
17
|
+
const onLoad = dom => {
|
18
|
+
setSize({
|
19
|
+
widthInPercent: 100,
|
20
|
+
height: 300,
|
21
|
+
...defaultSize
|
22
|
+
});
|
23
|
+
};
|
24
|
+
const onMouseDown = () => {
|
25
|
+
document.addEventListener("pointermove", onMouseMove);
|
26
|
+
document.addEventListener("pointerup", onMouseUp);
|
27
|
+
setResizing(true);
|
28
|
+
};
|
29
|
+
const onMouseUp = () => {
|
30
|
+
document.removeEventListener("pointermove", onMouseMove);
|
31
|
+
document.removeEventListener("pointerup", onMouseUp);
|
32
|
+
setResizing(false);
|
33
|
+
};
|
34
|
+
const onMouseMove = e => {
|
35
|
+
setSize(currentSize => {
|
36
|
+
const widthInPX = currentSize.widthInPercent / 100 * width;
|
37
|
+
const calcWidth = widthInPX + e.movementX;
|
38
|
+
return {
|
39
|
+
width: calcWidth,
|
40
|
+
height: currentSize.height + e.movementY,
|
41
|
+
widthInPercent: calcWidth / width * 100
|
42
|
+
};
|
43
|
+
});
|
44
|
+
};
|
45
|
+
return [size, onMouseDown, resizing, onLoad];
|
46
|
+
};
|
47
|
+
export default useResize;
|
@@ -0,0 +1,111 @@
|
|
1
|
+
const getStyle = (text, inlineStyle, data) => {
|
2
|
+
if (inlineStyle?.style) {
|
3
|
+
switch (inlineStyle?.style) {
|
4
|
+
case "BOLD":
|
5
|
+
return {
|
6
|
+
text,
|
7
|
+
bold: true
|
8
|
+
};
|
9
|
+
case "ITALIC":
|
10
|
+
return {
|
11
|
+
text,
|
12
|
+
italic: true
|
13
|
+
};
|
14
|
+
default:
|
15
|
+
return {
|
16
|
+
text
|
17
|
+
};
|
18
|
+
}
|
19
|
+
} else if (inlineStyle?.key !== undefined) {
|
20
|
+
const entityData = data?.entityMap[inlineStyle?.key];
|
21
|
+
switch (entityData?.type) {
|
22
|
+
case "mention":
|
23
|
+
return {
|
24
|
+
character: text,
|
25
|
+
type: entityData?.type,
|
26
|
+
data: entityData?.data,
|
27
|
+
children: [{
|
28
|
+
text: ""
|
29
|
+
}]
|
30
|
+
};
|
31
|
+
default:
|
32
|
+
return {
|
33
|
+
text
|
34
|
+
};
|
35
|
+
}
|
36
|
+
} else {
|
37
|
+
return {
|
38
|
+
text
|
39
|
+
};
|
40
|
+
}
|
41
|
+
};
|
42
|
+
const splitInlineStyleRanges = (text, inlineStyleRanges, data) => {
|
43
|
+
if (inlineStyleRanges.length > 0) {
|
44
|
+
let currentOffset = 0;
|
45
|
+
let allRanges = [];
|
46
|
+
for (let i = 0; i < inlineStyleRanges.length; i++) {
|
47
|
+
const {
|
48
|
+
offset,
|
49
|
+
length
|
50
|
+
} = inlineStyleRanges[i];
|
51
|
+
if (currentOffset < offset) {
|
52
|
+
allRanges.push({
|
53
|
+
offset: currentOffset,
|
54
|
+
length: offset - currentOffset
|
55
|
+
});
|
56
|
+
allRanges.push({
|
57
|
+
offset,
|
58
|
+
length
|
59
|
+
});
|
60
|
+
currentOffset = offset + length;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
// last line push
|
64
|
+
if (currentOffset < text.length) {
|
65
|
+
allRanges.push({
|
66
|
+
offset: currentOffset,
|
67
|
+
length: text.length - currentOffset
|
68
|
+
});
|
69
|
+
}
|
70
|
+
const splits = allRanges.reduce((a, b) => {
|
71
|
+
a.push({
|
72
|
+
...getStyle(text.substr(b.offset, b.length), inlineStyleRanges.find(f => f.offset === b.offset && f.length === b.length), data)
|
73
|
+
});
|
74
|
+
return a;
|
75
|
+
}, []);
|
76
|
+
return splits;
|
77
|
+
} else {
|
78
|
+
return [text];
|
79
|
+
}
|
80
|
+
};
|
81
|
+
export const draftToSlate = props => {
|
82
|
+
const {
|
83
|
+
data
|
84
|
+
} = props;
|
85
|
+
if (data?.blocks && data?.blocks?.length > 0) {
|
86
|
+
const converted = data?.blocks?.reduce((a, b) => {
|
87
|
+
if (b?.text !== undefined) {
|
88
|
+
const blocks = splitInlineStyleRanges(b?.text, [...b?.inlineStyleRanges, ...b?.entityRanges], data).map(m => {
|
89
|
+
return {
|
90
|
+
...m
|
91
|
+
};
|
92
|
+
});
|
93
|
+
a.push({
|
94
|
+
type: "paragraph",
|
95
|
+
children: blocks
|
96
|
+
});
|
97
|
+
}
|
98
|
+
return a;
|
99
|
+
}, []);
|
100
|
+
return converted;
|
101
|
+
} else if (data?.length) {
|
102
|
+
return data;
|
103
|
+
} else {
|
104
|
+
return [{
|
105
|
+
type: "paragraph",
|
106
|
+
children: [{
|
107
|
+
text: ""
|
108
|
+
}]
|
109
|
+
}];
|
110
|
+
}
|
111
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
import { createParagraph } from "./paragraph";
|
3
|
+
export const createEmbedNode = (type, {
|
4
|
+
url,
|
5
|
+
alt
|
6
|
+
}) => ({
|
7
|
+
type,
|
8
|
+
alt,
|
9
|
+
url,
|
10
|
+
children: [{
|
11
|
+
text: ""
|
12
|
+
}]
|
13
|
+
});
|
14
|
+
export const insertEmbed = (editor, embedData, format) => {
|
15
|
+
const {
|
16
|
+
url
|
17
|
+
} = embedData;
|
18
|
+
if (!url) return;
|
19
|
+
const embed = createEmbedNode(format, embedData);
|
20
|
+
Transforms.insertNodes(editor, embed, {
|
21
|
+
select: true
|
22
|
+
});
|
23
|
+
Transforms.insertNodes(editor, createParagraph(""));
|
24
|
+
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { Transforms, Range } from "slate";
|
2
|
+
const createEquationNode = (math, inline) => ({
|
3
|
+
type: 'equation',
|
4
|
+
inline,
|
5
|
+
math,
|
6
|
+
children: [{
|
7
|
+
text: ''
|
8
|
+
}]
|
9
|
+
});
|
10
|
+
export const insertEquation = (editor, math, inline) => {
|
11
|
+
const equation = createEquationNode(math, inline);
|
12
|
+
const {
|
13
|
+
selection
|
14
|
+
} = editor;
|
15
|
+
if (!!selection) {
|
16
|
+
if (Range.isExpanded(selection)) Transforms.collapse(editor, {
|
17
|
+
edge: 'end'
|
18
|
+
});
|
19
|
+
Transforms.insertNodes(editor, equation, {
|
20
|
+
select: true
|
21
|
+
});
|
22
|
+
}
|
23
|
+
};
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { Transforms, Editor } from "slate";
|
2
|
+
import { insertMention } from "./mentions";
|
3
|
+
const HOTKEYS = {
|
4
|
+
b: "bold",
|
5
|
+
i: "italic",
|
6
|
+
u: "underline"
|
7
|
+
};
|
8
|
+
export const mentionsEvent = props => {
|
9
|
+
const {
|
10
|
+
event,
|
11
|
+
mentions,
|
12
|
+
setMentions,
|
13
|
+
chars,
|
14
|
+
editor
|
15
|
+
} = props;
|
16
|
+
const {
|
17
|
+
index,
|
18
|
+
target
|
19
|
+
} = mentions;
|
20
|
+
switch (event.key) {
|
21
|
+
case "ArrowDown":
|
22
|
+
event.preventDefault();
|
23
|
+
const prevIndex = index >= chars.length - 1 ? 0 : index + 1;
|
24
|
+
setMentions({
|
25
|
+
...mentions,
|
26
|
+
index: prevIndex
|
27
|
+
});
|
28
|
+
break;
|
29
|
+
case "ArrowUp":
|
30
|
+
event.preventDefault();
|
31
|
+
const nextIndex = index <= 0 ? chars.length - 1 : index - 1;
|
32
|
+
setMentions({
|
33
|
+
...mentions,
|
34
|
+
index: nextIndex
|
35
|
+
});
|
36
|
+
break;
|
37
|
+
case "Tab":
|
38
|
+
case "Enter":
|
39
|
+
event.preventDefault();
|
40
|
+
Transforms.select(editor, target);
|
41
|
+
insertMention(editor, chars[index]);
|
42
|
+
setMentions({
|
43
|
+
...mentions,
|
44
|
+
target: null
|
45
|
+
});
|
46
|
+
break;
|
47
|
+
case "Escape":
|
48
|
+
event.preventDefault();
|
49
|
+
setMentions({
|
50
|
+
...mentions,
|
51
|
+
target: null
|
52
|
+
});
|
53
|
+
break;
|
54
|
+
default:
|
55
|
+
break;
|
56
|
+
}
|
57
|
+
};
|
58
|
+
const isMarkActive = (editor, format) => {
|
59
|
+
const marks = Editor.marks(editor);
|
60
|
+
return marks ? marks[format] === true : false;
|
61
|
+
};
|
62
|
+
export const commands = props => {
|
63
|
+
const {
|
64
|
+
event,
|
65
|
+
editor
|
66
|
+
} = props;
|
67
|
+
if (HOTKEYS[event.key]) {
|
68
|
+
event.preventDefault();
|
69
|
+
const isActive = isMarkActive(editor, HOTKEYS[event.key]);
|
70
|
+
if (isActive) {
|
71
|
+
Editor.removeMark(editor, HOTKEYS[event.key]);
|
72
|
+
} else {
|
73
|
+
Editor.addMark(editor, HOTKEYS[event.key], true);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
import { gridItem } from "./gridItem";
|
3
|
+
export const insertGrid = editor => {
|
4
|
+
const grid = {
|
5
|
+
type: "grid",
|
6
|
+
grid: "container",
|
7
|
+
children: [{
|
8
|
+
...gridItem()
|
9
|
+
}]
|
10
|
+
};
|
11
|
+
Transforms.insertNodes(editor, grid);
|
12
|
+
Transforms.move(editor);
|
13
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
export const gridItem = () => {
|
3
|
+
return {
|
4
|
+
type: "grid-item",
|
5
|
+
grid: 6,
|
6
|
+
children: [{
|
7
|
+
type: "paragraph",
|
8
|
+
children: [{
|
9
|
+
text: `Grid Item Text - ${new Date().getTime()}`
|
10
|
+
}]
|
11
|
+
}]
|
12
|
+
};
|
13
|
+
};
|
14
|
+
export const insertGridItem = editor => {
|
15
|
+
Transforms.insertNodes(editor, {
|
16
|
+
...gridItem()
|
17
|
+
});
|
18
|
+
Transforms.move(editor);
|
19
|
+
};
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { Editor, Transforms, Path, Range, Element } from 'slate';
|
2
|
+
export const createLinkNode = (href, showInNewTab, text) => ({
|
3
|
+
type: 'link',
|
4
|
+
href,
|
5
|
+
target: showInNewTab ? '_blank' : '_self',
|
6
|
+
children: [{
|
7
|
+
text
|
8
|
+
}]
|
9
|
+
});
|
10
|
+
export const insertLink = (editor, {
|
11
|
+
url,
|
12
|
+
showInNewTab
|
13
|
+
}) => {
|
14
|
+
if (!url) return;
|
15
|
+
const {
|
16
|
+
selection
|
17
|
+
} = editor;
|
18
|
+
const link = createLinkNode(url, showInNewTab, 'Link');
|
19
|
+
if (!!selection) {
|
20
|
+
const [parent, parentPath] = Editor.parent(editor, selection.focus.path);
|
21
|
+
if (parent.type === 'link') {
|
22
|
+
removeLink(editor);
|
23
|
+
}
|
24
|
+
if (editor.isVoid(parent)) {
|
25
|
+
Transforms.insertNodes(editor, {
|
26
|
+
type: 'paragraph',
|
27
|
+
children: [link]
|
28
|
+
}, {
|
29
|
+
at: Path.next(parentPath),
|
30
|
+
select: true
|
31
|
+
});
|
32
|
+
} else if (Range.isCollapsed(selection)) {
|
33
|
+
Transforms.insertNodes(editor, link, {
|
34
|
+
select: true
|
35
|
+
});
|
36
|
+
} else {
|
37
|
+
Transforms.wrapNodes(editor, link, {
|
38
|
+
split: true
|
39
|
+
});
|
40
|
+
}
|
41
|
+
} else {
|
42
|
+
Transforms.insertNodes(editor, {
|
43
|
+
type: 'paragraph',
|
44
|
+
children: [link]
|
45
|
+
});
|
46
|
+
}
|
47
|
+
};
|
48
|
+
export const removeLink = editor => {
|
49
|
+
Transforms.unwrapNodes(editor, {
|
50
|
+
match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'link'
|
51
|
+
});
|
52
|
+
};
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
export const insertMention = (editor, character) => {
|
3
|
+
const mention = {
|
4
|
+
type: "mention",
|
5
|
+
character,
|
6
|
+
children: [{
|
7
|
+
text: ""
|
8
|
+
}]
|
9
|
+
};
|
10
|
+
Transforms.insertNodes(editor, mention);
|
11
|
+
Transforms.move(editor);
|
12
|
+
};
|