@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.
Files changed (84) hide show
  1. package/dist/Editor/CollaborativeEditor.js +116 -0
  2. package/dist/Editor/CommonEditor.js +132 -0
  3. package/dist/Editor/Editor.css +115 -0
  4. package/dist/Editor/Elements/CodeToText/CodeToText.css +57 -0
  5. package/dist/Editor/Elements/CodeToText/CodeToText.js +112 -0
  6. package/dist/Editor/Elements/CodeToText/CodeToTextButton.js +18 -0
  7. package/dist/Editor/Elements/CodeToText/HtmlCode.js +54 -0
  8. package/dist/Editor/Elements/CodeToText/HtmlContextMenu.js +39 -0
  9. package/dist/Editor/Elements/Color Picker/ColorPicker.css +38 -0
  10. package/dist/Editor/Elements/Color Picker/ColorPicker.js +116 -0
  11. package/dist/Editor/Elements/Color Picker/defaultColors.js +1 -0
  12. package/dist/Editor/Elements/Embed/Embed.css +14 -0
  13. package/dist/Editor/Elements/Embed/Embed.js +94 -0
  14. package/dist/Editor/Elements/Embed/Image.js +70 -0
  15. package/dist/Editor/Elements/Embed/Video.js +62 -0
  16. package/dist/Editor/Elements/Equation/Equation.js +24 -0
  17. package/dist/Editor/Elements/Equation/EquationButton.js +66 -0
  18. package/dist/Editor/Elements/Equation/styles.css +4 -0
  19. package/dist/Editor/Elements/Grid/Grid.js +53 -0
  20. package/dist/Editor/Elements/Grid/GridButton.js +19 -0
  21. package/dist/Editor/Elements/Grid/GridItem.js +53 -0
  22. package/dist/Editor/Elements/ID/Id.js +56 -0
  23. package/dist/Editor/Elements/Link/Link.js +34 -0
  24. package/dist/Editor/Elements/Link/LinkButton.js +77 -0
  25. package/dist/Editor/Elements/Link/styles.css +20 -0
  26. package/dist/Editor/Elements/Mentions/Mentions.js +34 -0
  27. package/dist/Editor/Elements/NewLine/NewLineButton.js +22 -0
  28. package/dist/Editor/Elements/Table/Table.js +15 -0
  29. package/dist/Editor/Elements/Table/TableSelector.css +18 -0
  30. package/dist/Editor/Elements/Table/TableSelector.js +93 -0
  31. package/dist/Editor/Elements/TableContextMenu/TableContextMenu.js +91 -0
  32. package/dist/Editor/Elements/TableContextMenu/styles.css +18 -0
  33. package/dist/Editor/RemoteCursorOverlay/Overlay.js +75 -0
  34. package/dist/Editor/Toolbar/Toolbar.js +166 -0
  35. package/dist/Editor/Toolbar/styles.css +28 -0
  36. package/dist/Editor/Toolbar/toolbarGroups.js +131 -0
  37. package/dist/Editor/Toolbar/toolbarIcons/align-center.svg +1 -0
  38. package/dist/Editor/Toolbar/toolbarIcons/align-left.svg +1 -0
  39. package/dist/Editor/Toolbar/toolbarIcons/align-right.svg +1 -0
  40. package/dist/Editor/Toolbar/toolbarIcons/blockquote.svg +1 -0
  41. package/dist/Editor/Toolbar/toolbarIcons/bold.png +0 -0
  42. package/dist/Editor/Toolbar/toolbarIcons/fontColor.svg +4 -0
  43. package/dist/Editor/Toolbar/toolbarIcons/headingOne.svg +3 -0
  44. package/dist/Editor/Toolbar/toolbarIcons/headingTwo.svg +3 -0
  45. package/dist/Editor/Toolbar/toolbarIcons/italic.png +0 -0
  46. package/dist/Editor/Toolbar/toolbarIcons/link.svg +1 -0
  47. package/dist/Editor/Toolbar/toolbarIcons/orderedList.svg +1 -0
  48. package/dist/Editor/Toolbar/toolbarIcons/strikethrough.png +0 -0
  49. package/dist/Editor/Toolbar/toolbarIcons/subscript.svg +1 -0
  50. package/dist/Editor/Toolbar/toolbarIcons/superscript.svg +1 -0
  51. package/dist/Editor/Toolbar/toolbarIcons/textColor.png +0 -0
  52. package/dist/Editor/Toolbar/toolbarIcons/underline.png +0 -0
  53. package/dist/Editor/Toolbar/toolbarIcons/unlink.svg +1 -0
  54. package/dist/Editor/Toolbar/toolbarIcons/unorderedList.svg +1 -0
  55. package/dist/Editor/YjsProvider.js +9 -0
  56. package/dist/Editor/common/Button.js +21 -0
  57. package/dist/Editor/common/Icon.js +114 -0
  58. package/dist/Editor/common/MentionsPopup.js +54 -0
  59. package/dist/Editor/hooks/useMentions.js +44 -0
  60. package/dist/Editor/hooks/withCollaborative.js +15 -0
  61. package/dist/Editor/hooks/withCommon.js +11 -0
  62. package/dist/Editor/plugins/withEmbeds.js +29 -0
  63. package/dist/Editor/plugins/withEquation.js +8 -0
  64. package/dist/Editor/plugins/withLinks.js +8 -0
  65. package/dist/Editor/plugins/withMentions.js +18 -0
  66. package/dist/Editor/plugins/withTable.js +61 -0
  67. package/dist/Editor/utils/SlateUtilityFunctions.js +224 -0
  68. package/dist/Editor/utils/customHooks/useContextMenu.js +37 -0
  69. package/dist/Editor/utils/customHooks/useFormat.js +21 -0
  70. package/dist/Editor/utils/customHooks/usePopup.js +21 -0
  71. package/dist/Editor/utils/customHooks/useResize.js +47 -0
  72. package/dist/Editor/utils/draftToSlate.js +111 -0
  73. package/dist/Editor/utils/embed.js +24 -0
  74. package/dist/Editor/utils/equation.js +23 -0
  75. package/dist/Editor/utils/events.js +76 -0
  76. package/dist/Editor/utils/grid.js +13 -0
  77. package/dist/Editor/utils/gridItem.js +19 -0
  78. package/dist/Editor/utils/link.js +52 -0
  79. package/dist/Editor/utils/mentions.js +12 -0
  80. package/dist/Editor/utils/paragraph.js +6 -0
  81. package/dist/Editor/utils/serializer.js +28 -0
  82. package/dist/Editor/utils/table.js +129 -0
  83. package/dist/index.js +4 -0
  84. 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
+ };
@@ -0,0 +1,6 @@
1
+ export const createParagraph = text => ({
2
+ type: 'paragraph',
3
+ children: [{
4
+ text
5
+ }]
6
+ });