@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.
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
+ });