@flozy/editor 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintignore +4 -0
- package/.eslintrc.json +6 -0
- package/.github/workflows/npm-publish.yml +33 -0
- package/.husky/pre-commit +1 -0
- package/.storybook/main.js +20 -0
- package/.storybook/preview.js +14 -0
- package/.vscode/extensions.json +7 -0
- package/.vscode/launch.json +15 -0
- package/.vscode/settings.json +22 -0
- package/README.md +2 -0
- package/craco.config.js +16 -0
- package/package.json +107 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +43 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +25 -0
- package/public/robots.txt +3 -0
- package/src/components/Editor/CollaborativeEditor.js +119 -0
- package/src/components/Editor/CommonEditor.js +549 -0
- package/src/components/Editor/Editor.css +115 -0
- package/src/components/Editor/Elements/CodeToText/CodeToText.css +57 -0
- package/src/components/Editor/Elements/CodeToText/CodeToText.jsx +115 -0
- package/src/components/Editor/Elements/CodeToText/CodeToTextButton.jsx +16 -0
- package/src/components/Editor/Elements/CodeToText/HtmlCode.jsx +59 -0
- package/src/components/Editor/Elements/CodeToText/HtmlContextMenu.jsx +39 -0
- package/src/components/Editor/Elements/Color Picker/ColorPicker.css +38 -0
- package/src/components/Editor/Elements/Color Picker/ColorPicker.jsx +110 -0
- package/src/components/Editor/Elements/Color Picker/defaultColors.js +34 -0
- package/src/components/Editor/Elements/Embed/Embed.css +14 -0
- package/src/components/Editor/Elements/Embed/Embed.jsx +74 -0
- package/src/components/Editor/Elements/Embed/Image.jsx +82 -0
- package/src/components/Editor/Elements/Embed/Video.jsx +65 -0
- package/src/components/Editor/Elements/Equation/Equation.jsx +19 -0
- package/src/components/Editor/Elements/Equation/EquationButton.jsx +59 -0
- package/src/components/Editor/Elements/Equation/styles.css +4 -0
- package/src/components/Editor/Elements/Grid/Grid.js +48 -0
- package/src/components/Editor/Elements/Grid/GridButton.js +21 -0
- package/src/components/Editor/Elements/Grid/GridItem.js +57 -0
- package/src/components/Editor/Elements/ID/Id.jsx +56 -0
- package/src/components/Editor/Elements/Link/Link.jsx +24 -0
- package/src/components/Editor/Elements/Link/LinkButton.jsx +71 -0
- package/src/components/Editor/Elements/Link/styles.css +20 -0
- package/src/components/Editor/Elements/Mentions/Mentions.jsx +37 -0
- package/src/components/Editor/Elements/NewLine/NewLineButton.js +29 -0
- package/src/components/Editor/Elements/Table/Table.jsx +13 -0
- package/src/components/Editor/Elements/Table/TableSelector.css +18 -0
- package/src/components/Editor/Elements/Table/TableSelector.jsx +76 -0
- package/src/components/Editor/Elements/TableContextMenu/TableContextMenu.jsx +97 -0
- package/src/components/Editor/Elements/TableContextMenu/styles.css +18 -0
- package/src/components/Editor/RemoteCursorOverlay/Overlay.js +78 -0
- package/src/components/Editor/Toolbar/Toolbar.jsx +167 -0
- package/src/components/Editor/Toolbar/styles.css +28 -0
- package/src/components/Editor/Toolbar/toolbarGroups.js +167 -0
- package/src/components/Editor/Toolbar/toolbarIcons/align-center.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/align-left.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/align-right.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/blockquote.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/bold.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/fontColor.svg +4 -0
- package/src/components/Editor/Toolbar/toolbarIcons/headingOne.svg +3 -0
- package/src/components/Editor/Toolbar/toolbarIcons/headingTwo.svg +3 -0
- package/src/components/Editor/Toolbar/toolbarIcons/italic.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/link.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/orderedList.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/strikethrough.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/subscript.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/superscript.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/textColor.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/underline.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/unlink.svg +1 -0
- package/src/components/Editor/Toolbar/toolbarIcons/unorderedList.svg +1 -0
- package/src/components/Editor/YjsProvider.js +11 -0
- package/src/components/Editor/common/Button.jsx +12 -0
- package/src/components/Editor/common/Icon.jsx +82 -0
- package/src/components/Editor/common/MentionsPopup.jsx +56 -0
- package/src/components/Editor/hooks/useMentions.js +44 -0
- package/src/components/Editor/hooks/withCollaborative.js +15 -0
- package/src/components/Editor/hooks/withCommon.js +17 -0
- package/src/components/Editor/plugins/withEmbeds.js +36 -0
- package/src/components/Editor/plugins/withEquation.js +8 -0
- package/src/components/Editor/plugins/withLinks.js +9 -0
- package/src/components/Editor/plugins/withMentions.js +19 -0
- package/src/components/Editor/plugins/withTable.js +74 -0
- package/src/components/Editor/utils/SlateUtilityFunctions.js +273 -0
- package/src/components/Editor/utils/customHooks/useContextMenu.js +42 -0
- package/src/components/Editor/utils/customHooks/useFormat.js +26 -0
- package/src/components/Editor/utils/customHooks/usePopup.jsx +26 -0
- package/src/components/Editor/utils/customHooks/useResize.js +41 -0
- package/src/components/Editor/utils/draftToSlate.js +104 -0
- package/src/components/Editor/utils/embed.js +18 -0
- package/src/components/Editor/utils/equation.js +22 -0
- package/src/components/Editor/utils/events.js +56 -0
- package/src/components/Editor/utils/grid.js +12 -0
- package/src/components/Editor/utils/gridItem.js +19 -0
- package/src/components/Editor/utils/link.js +53 -0
- package/src/components/Editor/utils/mentions.js +11 -0
- package/src/components/Editor/utils/paragraph.js +4 -0
- package/src/components/Editor/utils/serializer.js +32 -0
- package/src/components/Editor/utils/table.js +151 -0
- package/src/components/index.js +5 -0
- package/src/index.js +1 -0
- package/src/stories/CollaborativeEditor.stories.js +30 -0
- package/src/stories/Editor.stories.js +24 -0
- package/src/stories/EditorSampleProps/ChatSample.js +43 -0
- package/src/stories/EditorSampleProps/LayoutOne.js +551 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
const getStyle = (text, inlineStyle, data) => {
|
2
|
+
if (inlineStyle?.style) {
|
3
|
+
switch (inlineStyle?.style) {
|
4
|
+
case "BOLD":
|
5
|
+
return { text, bold: true };
|
6
|
+
case "ITALIC":
|
7
|
+
return { text, italic: true };
|
8
|
+
default:
|
9
|
+
return { text };
|
10
|
+
}
|
11
|
+
} else if (inlineStyle?.key !== undefined) {
|
12
|
+
const entityData = data?.entityMap[inlineStyle?.key];
|
13
|
+
switch (entityData?.type) {
|
14
|
+
case "mention":
|
15
|
+
return {
|
16
|
+
character: text,
|
17
|
+
type: entityData?.type,
|
18
|
+
data: entityData?.data,
|
19
|
+
children: [{ text: "" }],
|
20
|
+
};
|
21
|
+
default:
|
22
|
+
return { text };
|
23
|
+
}
|
24
|
+
} else {
|
25
|
+
return { text };
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
const splitInlineStyleRanges = (text, inlineStyleRanges, data) => {
|
30
|
+
if (inlineStyleRanges.length > 0) {
|
31
|
+
let currentOffset = 0;
|
32
|
+
let allRanges = [];
|
33
|
+
for (let i = 0; i < inlineStyleRanges.length; i++) {
|
34
|
+
const { offset, length } = inlineStyleRanges[i];
|
35
|
+
if (currentOffset < offset) {
|
36
|
+
allRanges.push({
|
37
|
+
offset: currentOffset,
|
38
|
+
length: offset - currentOffset,
|
39
|
+
});
|
40
|
+
allRanges.push({
|
41
|
+
offset,
|
42
|
+
length,
|
43
|
+
});
|
44
|
+
currentOffset = offset + length;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
// last line push
|
48
|
+
if (currentOffset < text.length) {
|
49
|
+
allRanges.push({
|
50
|
+
offset: currentOffset,
|
51
|
+
length: text.length - currentOffset,
|
52
|
+
});
|
53
|
+
}
|
54
|
+
const splits = allRanges.reduce((a, b) => {
|
55
|
+
a.push({
|
56
|
+
...getStyle(
|
57
|
+
text.substr(b.offset, b.length),
|
58
|
+
inlineStyleRanges.find(
|
59
|
+
(f) => f.offset === b.offset && f.length === b.length
|
60
|
+
),
|
61
|
+
data
|
62
|
+
),
|
63
|
+
});
|
64
|
+
return a;
|
65
|
+
}, []);
|
66
|
+
return splits;
|
67
|
+
} else {
|
68
|
+
return [text];
|
69
|
+
}
|
70
|
+
};
|
71
|
+
|
72
|
+
export const draftToSlate = (props) => {
|
73
|
+
const { data } = props;
|
74
|
+
if (data?.blocks && data?.blocks?.length > 0) {
|
75
|
+
const converted = data?.blocks?.reduce((a, b) => {
|
76
|
+
if (b?.text !== undefined) {
|
77
|
+
const blocks = splitInlineStyleRanges(
|
78
|
+
b?.text,
|
79
|
+
[...b?.inlineStyleRanges, ...b?.entityRanges],
|
80
|
+
data
|
81
|
+
).map((m) => {
|
82
|
+
return {
|
83
|
+
...m,
|
84
|
+
};
|
85
|
+
});
|
86
|
+
a.push({
|
87
|
+
type: "paragraph",
|
88
|
+
children: blocks,
|
89
|
+
});
|
90
|
+
}
|
91
|
+
return a;
|
92
|
+
}, []);
|
93
|
+
return converted;
|
94
|
+
} else if (data?.length) {
|
95
|
+
return data;
|
96
|
+
} else {
|
97
|
+
return [
|
98
|
+
{
|
99
|
+
type: "paragraph",
|
100
|
+
children: [{ text: "" }],
|
101
|
+
},
|
102
|
+
];
|
103
|
+
}
|
104
|
+
};
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
|
3
|
+
import { createParagraph } from "./paragraph";
|
4
|
+
export const createEmbedNode = (type, { url, alt }) => ({
|
5
|
+
type,
|
6
|
+
alt,
|
7
|
+
url,
|
8
|
+
children: [{ text: "" }],
|
9
|
+
});
|
10
|
+
|
11
|
+
export const insertEmbed = (editor, embedData, format) => {
|
12
|
+
const { url } = embedData;
|
13
|
+
if (!url) return;
|
14
|
+
const embed = createEmbedNode(format, embedData);
|
15
|
+
|
16
|
+
Transforms.insertNodes(editor, embed, { select: true });
|
17
|
+
Transforms.insertNodes(editor, createParagraph(""));
|
18
|
+
};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { Transforms, Range } from "slate";
|
2
|
+
|
3
|
+
const createEquationNode = (math,inline) =>({
|
4
|
+
type:'equation',
|
5
|
+
inline,
|
6
|
+
math,
|
7
|
+
children:[{text:''}]
|
8
|
+
})
|
9
|
+
|
10
|
+
export const insertEquation = (editor,math,inline) =>{
|
11
|
+
const equation = createEquationNode(math,inline);
|
12
|
+
|
13
|
+
const {selection} = editor;
|
14
|
+
if(!!selection){
|
15
|
+
if(Range.isExpanded(selection)) Transforms.collapse(editor,{edge:'end'});
|
16
|
+
|
17
|
+
Transforms.insertNodes(editor,equation,{select:true})
|
18
|
+
}
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import { Transforms, Editor } from "slate";
|
2
|
+
import { insertMention } from "./mentions";
|
3
|
+
|
4
|
+
const HOTKEYS = {
|
5
|
+
b: "bold",
|
6
|
+
i: "italic",
|
7
|
+
u: "underline",
|
8
|
+
};
|
9
|
+
|
10
|
+
export const mentionsEvent = (props) => {
|
11
|
+
const { event, mentions, setMentions, chars, editor } = props;
|
12
|
+
const { index, target } = mentions;
|
13
|
+
switch (event.key) {
|
14
|
+
case "ArrowDown":
|
15
|
+
event.preventDefault();
|
16
|
+
const prevIndex = index >= chars.length - 1 ? 0 : index + 1;
|
17
|
+
setMentions({ ...mentions, index: prevIndex });
|
18
|
+
break;
|
19
|
+
case "ArrowUp":
|
20
|
+
event.preventDefault();
|
21
|
+
const nextIndex = index <= 0 ? chars.length - 1 : index - 1;
|
22
|
+
setMentions({ ...mentions, index: nextIndex });
|
23
|
+
break;
|
24
|
+
case "Tab":
|
25
|
+
case "Enter":
|
26
|
+
event.preventDefault();
|
27
|
+
Transforms.select(editor, target);
|
28
|
+
insertMention(editor, chars[index]);
|
29
|
+
setMentions({ ...mentions, target: null });
|
30
|
+
break;
|
31
|
+
case "Escape":
|
32
|
+
event.preventDefault();
|
33
|
+
setMentions({ ...mentions, target: null });
|
34
|
+
break;
|
35
|
+
default:
|
36
|
+
break;
|
37
|
+
}
|
38
|
+
};
|
39
|
+
|
40
|
+
const isMarkActive = (editor, format) => {
|
41
|
+
const marks = Editor.marks(editor);
|
42
|
+
return marks ? marks[format] === true : false;
|
43
|
+
};
|
44
|
+
|
45
|
+
export const commands = (props) => {
|
46
|
+
const { event, editor } = props;
|
47
|
+
if (HOTKEYS[event.key]) {
|
48
|
+
event.preventDefault();
|
49
|
+
const isActive = isMarkActive(editor, HOTKEYS[event.key]);
|
50
|
+
if (isActive) {
|
51
|
+
Editor.removeMark(editor, HOTKEYS[event.key]);
|
52
|
+
} else {
|
53
|
+
Editor.addMark(editor, HOTKEYS[event.key], true);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
};
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
import { gridItem } from "./gridItem";
|
3
|
+
|
4
|
+
export const insertGrid = (editor) => {
|
5
|
+
const grid = {
|
6
|
+
type: "grid",
|
7
|
+
grid: "container",
|
8
|
+
children: [{ ...gridItem() }],
|
9
|
+
};
|
10
|
+
Transforms.insertNodes(editor, grid);
|
11
|
+
Transforms.move(editor);
|
12
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Transforms } from "slate";
|
2
|
+
|
3
|
+
export const gridItem = () => {
|
4
|
+
return {
|
5
|
+
type: "grid-item",
|
6
|
+
grid: 6,
|
7
|
+
children: [
|
8
|
+
{
|
9
|
+
type: "paragraph",
|
10
|
+
children: [{ text: `Grid Item Text - ${new Date().getTime()}` }],
|
11
|
+
},
|
12
|
+
],
|
13
|
+
};
|
14
|
+
};
|
15
|
+
|
16
|
+
export const insertGridItem = (editor) => {
|
17
|
+
Transforms.insertNodes(editor, { ...gridItem() });
|
18
|
+
Transforms.move(editor);
|
19
|
+
};
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { Editor, Transforms, Path, Range, Element } from 'slate';
|
2
|
+
|
3
|
+
export const createLinkNode = (href,showInNewTab,text) =>(
|
4
|
+
{
|
5
|
+
type:'link',
|
6
|
+
href,
|
7
|
+
target:showInNewTab ? '_blank': '_self',
|
8
|
+
children:[{ text }]
|
9
|
+
}
|
10
|
+
)
|
11
|
+
|
12
|
+
export const insertLink = (editor,{url,showInNewTab})=>{
|
13
|
+
if(!url) return;
|
14
|
+
|
15
|
+
const { selection } = editor;
|
16
|
+
const link = createLinkNode(url,showInNewTab,'Link');
|
17
|
+
if(!!selection){
|
18
|
+
const [parent, parentPath] = Editor.parent(editor,selection.focus.path);
|
19
|
+
if(parent.type === 'link'){
|
20
|
+
removeLink(editor);
|
21
|
+
}
|
22
|
+
|
23
|
+
|
24
|
+
if(editor.isVoid(parent)){
|
25
|
+
Transforms.insertNodes(editor,
|
26
|
+
{type:'paragraph',children:[link]},
|
27
|
+
{
|
28
|
+
at:Path.next(parentPath),
|
29
|
+
select:true
|
30
|
+
}
|
31
|
+
|
32
|
+
)
|
33
|
+
}
|
34
|
+
else if(Range.isCollapsed(selection)){
|
35
|
+
Transforms.insertNodes(editor,link, {select:true});
|
36
|
+
}
|
37
|
+
else{
|
38
|
+
Transforms.wrapNodes(editor,link,
|
39
|
+
{split:true}
|
40
|
+
)
|
41
|
+
|
42
|
+
}
|
43
|
+
}
|
44
|
+
else{
|
45
|
+
Transforms.insertNodes(editor,{type:'paragraph',children:[link]})
|
46
|
+
}
|
47
|
+
};
|
48
|
+
|
49
|
+
export const removeLink = (editor) =>{
|
50
|
+
Transforms.unwrapNodes(editor,{
|
51
|
+
match:n => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'link'
|
52
|
+
})
|
53
|
+
};
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { Text } from 'slate';
|
2
|
+
import { getBlock, getMarked } from './SlateUtilityFunctions.js'
|
3
|
+
import ReactDOMServer from 'react-dom/server';
|
4
|
+
|
5
|
+
const { renderToStaticMarkup } = ReactDOMServer
|
6
|
+
|
7
|
+
|
8
|
+
export const serialize = node =>{
|
9
|
+
if(Text.isText(node)){
|
10
|
+
let string = getMarked(node,node.text);
|
11
|
+
string = renderToStaticMarkup(string);
|
12
|
+
return string
|
13
|
+
}
|
14
|
+
const children = node.children.map(n => serialize(n)).join('')
|
15
|
+
|
16
|
+
let block = getBlock({children,element:node})
|
17
|
+
block = renderToStaticMarkup(block)
|
18
|
+
|
19
|
+
return block
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
export const serializer = editorValue =>{
|
25
|
+
if(editorValue.length > 0){
|
26
|
+
return editorValue.map(n => serialize(n)).join('')
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
export const deserializer = (body) => {
|
31
|
+
console.log(body);
|
32
|
+
}
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import { Transforms, Editor, Range, Element, Path } from "slate";
|
2
|
+
|
3
|
+
export class TableUtil {
|
4
|
+
constructor(editor) {
|
5
|
+
this.editor = editor;
|
6
|
+
}
|
7
|
+
|
8
|
+
insertTable = (rows, columns) => {
|
9
|
+
const [tableNode] = Editor.nodes(this.editor, {
|
10
|
+
match: (n) =>
|
11
|
+
!Editor.isEditor(n) && Element.isElement(n) && n.type === "table",
|
12
|
+
mode: "highest",
|
13
|
+
});
|
14
|
+
|
15
|
+
if (tableNode) return;
|
16
|
+
if (!rows || !columns) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
//Creating a 2-d array of blank string as default text for the table
|
20
|
+
const cellText = Array.from({ length: rows }, () =>
|
21
|
+
Array.from({ length: columns }, () => "")
|
22
|
+
);
|
23
|
+
const newTable = createTableNode(cellText, rows, columns);
|
24
|
+
|
25
|
+
Transforms.insertNodes(this.editor, newTable, {
|
26
|
+
// mode: "highest",
|
27
|
+
});
|
28
|
+
Transforms.insertNodes(
|
29
|
+
this.editor,
|
30
|
+
{ type: "paragraph", children: [{ text: "" }] }
|
31
|
+
// { mode: "highest" }
|
32
|
+
);
|
33
|
+
};
|
34
|
+
|
35
|
+
removeTable = () => {
|
36
|
+
Transforms.removeNodes(this.editor, {
|
37
|
+
match: (n) =>
|
38
|
+
!Editor.isEditor(n) && Element.isElement(n) && n.type === "table",
|
39
|
+
// mode:'highest'
|
40
|
+
});
|
41
|
+
};
|
42
|
+
|
43
|
+
insertRow = (action) => {
|
44
|
+
const { selection } = this.editor;
|
45
|
+
|
46
|
+
if (!!selection && Range.isCollapsed(selection)) {
|
47
|
+
const [tableNode] = Editor.nodes(this.editor, {
|
48
|
+
match: (n) =>
|
49
|
+
!Editor.isEditor(n) && Element.isElement(n) && n.type === "table-row",
|
50
|
+
});
|
51
|
+
if (tableNode) {
|
52
|
+
const [[table, tablePath]] = Editor.nodes(this.editor, {
|
53
|
+
match: (n) =>
|
54
|
+
!Editor.isEditor(n) && Element.isElement(n) && n.type === "table",
|
55
|
+
});
|
56
|
+
const [, currentRow] = tableNode;
|
57
|
+
|
58
|
+
const path = action === "after" ? Path.next(currentRow) : currentRow;
|
59
|
+
|
60
|
+
Transforms.insertNodes(
|
61
|
+
this.editor,
|
62
|
+
createRow(Array(table.columns).fill("")),
|
63
|
+
{
|
64
|
+
at: path,
|
65
|
+
}
|
66
|
+
);
|
67
|
+
Transforms.setNodes(
|
68
|
+
this.editor,
|
69
|
+
{ rows: table.rows + 1 },
|
70
|
+
{
|
71
|
+
at: tablePath,
|
72
|
+
}
|
73
|
+
);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
};
|
77
|
+
|
78
|
+
insertColumn = (action) => {
|
79
|
+
const { selection } = this.editor;
|
80
|
+
if (!!selection && Range.isCollapsed(selection)) {
|
81
|
+
const [tableNode] = Editor.nodes(this.editor, {
|
82
|
+
match: (n) =>
|
83
|
+
!Editor.isEditor(n) &&
|
84
|
+
Element.isElement(n) &&
|
85
|
+
n.type === "table-cell",
|
86
|
+
});
|
87
|
+
if (tableNode) {
|
88
|
+
const [[table, tablePath]] = Editor.nodes(this.editor, {
|
89
|
+
match: (n) =>
|
90
|
+
!Editor.isEditor(n) && Element.isElement(n) && n.type === "table",
|
91
|
+
});
|
92
|
+
const [, currentCell] = tableNode;
|
93
|
+
const startPath =
|
94
|
+
action === "after" ? Path.next(currentCell) : currentCell;
|
95
|
+
|
96
|
+
// The last two indices of the path represents the row and column. We need to add one cell to each row starting from the first row
|
97
|
+
startPath[startPath.length - 2] = 0;
|
98
|
+
for (let row = 0; row < table.rows; row++) {
|
99
|
+
Transforms.insertNodes(this.editor, createTableCell(""), {
|
100
|
+
at: startPath,
|
101
|
+
});
|
102
|
+
startPath[startPath.length - 2]++;
|
103
|
+
}
|
104
|
+
|
105
|
+
Transforms.setNodes(
|
106
|
+
this.editor,
|
107
|
+
{ columns: table.columns + 1 },
|
108
|
+
{
|
109
|
+
at: tablePath,
|
110
|
+
}
|
111
|
+
);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
};
|
115
|
+
}
|
116
|
+
|
117
|
+
const createRow = (cellText) => {
|
118
|
+
const newRow = Array.from(cellText, (value) => createTableCell(value));
|
119
|
+
return {
|
120
|
+
type: "table-row",
|
121
|
+
children: newRow,
|
122
|
+
};
|
123
|
+
};
|
124
|
+
|
125
|
+
export const createTableCell = (text) => {
|
126
|
+
return {
|
127
|
+
type: "table-cell",
|
128
|
+
children: [
|
129
|
+
{
|
130
|
+
type: "paragraph",
|
131
|
+
children: [{ text }],
|
132
|
+
},
|
133
|
+
],
|
134
|
+
};
|
135
|
+
};
|
136
|
+
|
137
|
+
const createTableNode = (cellText, rows, columns) => {
|
138
|
+
const tableChildren = Array.from(cellText, (value) => createRow(value));
|
139
|
+
let tableNode = {
|
140
|
+
type: "paragraph",
|
141
|
+
children: [
|
142
|
+
{
|
143
|
+
type: "table",
|
144
|
+
children: tableChildren,
|
145
|
+
rows,
|
146
|
+
columns,
|
147
|
+
},
|
148
|
+
],
|
149
|
+
};
|
150
|
+
return tableNode;
|
151
|
+
};
|
package/src/index.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./components";
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { CollaborativeEditor } from "../components";
|
2
|
+
|
3
|
+
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
4
|
+
const DefaultComp = {
|
5
|
+
title: "Example/CollaborativeEditor",
|
6
|
+
component: CollaborativeEditor,
|
7
|
+
parameters: {
|
8
|
+
content: null,
|
9
|
+
},
|
10
|
+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
|
11
|
+
tags: ["autodocs"],
|
12
|
+
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
|
13
|
+
argTypes: {},
|
14
|
+
};
|
15
|
+
|
16
|
+
export default DefaultComp;
|
17
|
+
|
18
|
+
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
19
|
+
export const Default = {
|
20
|
+
args: {
|
21
|
+
id: 1,
|
22
|
+
content: [],
|
23
|
+
user: {
|
24
|
+
id: 1,
|
25
|
+
name: `user_${new Date().getTime()}@emai.com`,
|
26
|
+
token: `user_${new Date().getTime()}@emai.com`,
|
27
|
+
},
|
28
|
+
socketURL: "ws://localhost:1234",
|
29
|
+
},
|
30
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Editor } from "../components";
|
2
|
+
|
3
|
+
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
4
|
+
const DefaultComp = {
|
5
|
+
title: "Example/Editor",
|
6
|
+
component: Editor,
|
7
|
+
parameters: {
|
8
|
+
content: null,
|
9
|
+
},
|
10
|
+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
|
11
|
+
tags: ["autodocs"],
|
12
|
+
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
|
13
|
+
argTypes: {},
|
14
|
+
};
|
15
|
+
|
16
|
+
export default DefaultComp;
|
17
|
+
|
18
|
+
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
19
|
+
export const Default = {
|
20
|
+
args: {
|
21
|
+
id: 1,
|
22
|
+
content: [],
|
23
|
+
},
|
24
|
+
};
|
@@ -0,0 +1,43 @@
|
|
1
|
+
const ChatSample = {
|
2
|
+
blocks: [
|
3
|
+
{
|
4
|
+
key: "c4hg",
|
5
|
+
text: "line one contains bold text\nline two contains normal one\nline three contains both bold and @Tech AgenciFlow ",
|
6
|
+
type: "unstyled",
|
7
|
+
depth: 0,
|
8
|
+
inlineStyleRanges: [
|
9
|
+
{ offset: 18, length: 10, style: "BOLD" },
|
10
|
+
{ offset: 82, length: 5, style: "BOLD" },
|
11
|
+
],
|
12
|
+
entityRanges: [{ offset: 91, length: 16, key: 0 }],
|
13
|
+
data: {},
|
14
|
+
},
|
15
|
+
],
|
16
|
+
entityMap: {
|
17
|
+
0: {
|
18
|
+
type: "mention",
|
19
|
+
mutability: "SEGMENTED",
|
20
|
+
data: {
|
21
|
+
mention: {
|
22
|
+
id: 2,
|
23
|
+
username: "tech AgenciFlow",
|
24
|
+
first_name: "Tech",
|
25
|
+
last_name: "AgenciFlow",
|
26
|
+
email: "tech@agenciflow.com",
|
27
|
+
name: "Tech AgenciFlow",
|
28
|
+
avatar_filename:
|
29
|
+
"https://sweetp-user-uploads.s3.eu-west-2.amazonaws.com/stage%20/%201684133040520_profile",
|
30
|
+
user_job_status: 0,
|
31
|
+
mute_notification: 1,
|
32
|
+
job_user_id: 2,
|
33
|
+
aju_id: 806,
|
34
|
+
job_id: 363,
|
35
|
+
agency_id: 5,
|
36
|
+
user_role: 3,
|
37
|
+
},
|
38
|
+
},
|
39
|
+
},
|
40
|
+
},
|
41
|
+
};
|
42
|
+
|
43
|
+
export default ChatSample;
|