@flozy/editor 1.0.5 → 1.0.7
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/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
|
+
};
|