@flozy/editor 1.0.0 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +6 -2
- package/.eslintignore +0 -4
- package/.eslintrc.json +0 -6
- package/.github/workflows/npm-publish.yml +0 -33
- package/.husky/pre-commit +0 -1
- package/.storybook/main.js +0 -20
- package/.storybook/preview.js +0 -14
- package/.vscode/extensions.json +0 -7
- package/.vscode/launch.json +0 -15
- package/.vscode/settings.json +0 -22
- package/craco.config.js +0 -16
- package/public/favicon.ico +0 -0
- package/public/index.html +0 -43
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +0 -25
- package/public/robots.txt +0 -3
- package/src/components/Editor/CollaborativeEditor.js +0 -119
- package/src/components/Editor/CommonEditor.js +0 -549
- package/src/components/Editor/Editor.css +0 -115
- package/src/components/Editor/Elements/CodeToText/CodeToText.css +0 -57
- package/src/components/Editor/Elements/CodeToText/CodeToText.jsx +0 -115
- package/src/components/Editor/Elements/CodeToText/CodeToTextButton.jsx +0 -16
- package/src/components/Editor/Elements/CodeToText/HtmlCode.jsx +0 -59
- package/src/components/Editor/Elements/CodeToText/HtmlContextMenu.jsx +0 -39
- package/src/components/Editor/Elements/Color Picker/ColorPicker.css +0 -38
- package/src/components/Editor/Elements/Color Picker/ColorPicker.jsx +0 -110
- package/src/components/Editor/Elements/Color Picker/defaultColors.js +0 -34
- package/src/components/Editor/Elements/Embed/Embed.css +0 -14
- package/src/components/Editor/Elements/Embed/Embed.jsx +0 -74
- package/src/components/Editor/Elements/Embed/Image.jsx +0 -82
- package/src/components/Editor/Elements/Embed/Video.jsx +0 -65
- package/src/components/Editor/Elements/Equation/Equation.jsx +0 -19
- package/src/components/Editor/Elements/Equation/EquationButton.jsx +0 -59
- package/src/components/Editor/Elements/Equation/styles.css +0 -4
- package/src/components/Editor/Elements/Grid/Grid.js +0 -48
- package/src/components/Editor/Elements/Grid/GridButton.js +0 -21
- package/src/components/Editor/Elements/Grid/GridItem.js +0 -57
- package/src/components/Editor/Elements/ID/Id.jsx +0 -56
- package/src/components/Editor/Elements/Link/Link.jsx +0 -24
- package/src/components/Editor/Elements/Link/LinkButton.jsx +0 -71
- package/src/components/Editor/Elements/Link/styles.css +0 -20
- package/src/components/Editor/Elements/Mentions/Mentions.jsx +0 -37
- package/src/components/Editor/Elements/NewLine/NewLineButton.js +0 -29
- package/src/components/Editor/Elements/Table/Table.jsx +0 -13
- package/src/components/Editor/Elements/Table/TableSelector.css +0 -18
- package/src/components/Editor/Elements/Table/TableSelector.jsx +0 -76
- package/src/components/Editor/Elements/TableContextMenu/TableContextMenu.jsx +0 -97
- package/src/components/Editor/Elements/TableContextMenu/styles.css +0 -18
- package/src/components/Editor/RemoteCursorOverlay/Overlay.js +0 -78
- package/src/components/Editor/Toolbar/Toolbar.jsx +0 -167
- package/src/components/Editor/Toolbar/styles.css +0 -28
- package/src/components/Editor/Toolbar/toolbarGroups.js +0 -167
- package/src/components/Editor/Toolbar/toolbarIcons/align-center.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/align-left.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/align-right.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/blockquote.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/bold.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/fontColor.svg +0 -4
- package/src/components/Editor/Toolbar/toolbarIcons/headingOne.svg +0 -3
- package/src/components/Editor/Toolbar/toolbarIcons/headingTwo.svg +0 -3
- package/src/components/Editor/Toolbar/toolbarIcons/italic.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/link.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/orderedList.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/strikethrough.png +0 -0
- package/src/components/Editor/Toolbar/toolbarIcons/subscript.svg +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/superscript.svg +0 -1
- 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 +0 -1
- package/src/components/Editor/Toolbar/toolbarIcons/unorderedList.svg +0 -1
- package/src/components/Editor/YjsProvider.js +0 -11
- package/src/components/Editor/common/Button.jsx +0 -12
- package/src/components/Editor/common/Icon.jsx +0 -82
- package/src/components/Editor/common/MentionsPopup.jsx +0 -56
- package/src/components/Editor/hooks/useMentions.js +0 -44
- package/src/components/Editor/hooks/withCollaborative.js +0 -15
- package/src/components/Editor/hooks/withCommon.js +0 -17
- package/src/components/Editor/plugins/withEmbeds.js +0 -36
- package/src/components/Editor/plugins/withEquation.js +0 -8
- package/src/components/Editor/plugins/withLinks.js +0 -9
- package/src/components/Editor/plugins/withMentions.js +0 -19
- package/src/components/Editor/plugins/withTable.js +0 -74
- package/src/components/Editor/utils/SlateUtilityFunctions.js +0 -273
- package/src/components/Editor/utils/customHooks/useContextMenu.js +0 -42
- package/src/components/Editor/utils/customHooks/useFormat.js +0 -26
- package/src/components/Editor/utils/customHooks/usePopup.jsx +0 -26
- package/src/components/Editor/utils/customHooks/useResize.js +0 -41
- package/src/components/Editor/utils/draftToSlate.js +0 -104
- package/src/components/Editor/utils/embed.js +0 -18
- package/src/components/Editor/utils/equation.js +0 -22
- package/src/components/Editor/utils/events.js +0 -56
- package/src/components/Editor/utils/grid.js +0 -12
- package/src/components/Editor/utils/gridItem.js +0 -19
- package/src/components/Editor/utils/link.js +0 -53
- package/src/components/Editor/utils/mentions.js +0 -11
- package/src/components/Editor/utils/paragraph.js +0 -4
- package/src/components/Editor/utils/serializer.js +0 -32
- package/src/components/Editor/utils/table.js +0 -151
- package/src/components/index.js +0 -5
- package/src/index.js +0 -1
- package/src/stories/CollaborativeEditor.stories.js +0 -30
- package/src/stories/Editor.stories.js +0 -24
- package/src/stories/EditorSampleProps/ChatSample.js +0 -43
- package/src/stories/EditorSampleProps/LayoutOne.js +0 -551
@@ -1,115 +0,0 @@
|
|
1
|
-
import React, { useEffect, useRef } from "react";
|
2
|
-
import "./CodeToText.css";
|
3
|
-
import Icon from "../../common/Icon";
|
4
|
-
import { Interweave } from "interweave";
|
5
|
-
import { Transforms } from "slate";
|
6
|
-
import { useSlateStatic } from "slate-react";
|
7
|
-
const CodeToText = (props) => {
|
8
|
-
const { html, action, location, handleCodeToText } = props;
|
9
|
-
const codeToTextRef = useRef();
|
10
|
-
const wrapperRef = useRef();
|
11
|
-
|
12
|
-
const editor = useSlateStatic();
|
13
|
-
const checkClick = (e) => {
|
14
|
-
const clickedComponent = e.target;
|
15
|
-
if (
|
16
|
-
wrapperRef?.current?.contains(clickedComponent) &&
|
17
|
-
!codeToTextRef?.current?.contains(clickedComponent)
|
18
|
-
) {
|
19
|
-
let partialState = {
|
20
|
-
showInput: false,
|
21
|
-
};
|
22
|
-
if (html) {
|
23
|
-
partialState.html = action === "update" ? "" : html;
|
24
|
-
}
|
25
|
-
handleCodeToText(partialState);
|
26
|
-
}
|
27
|
-
};
|
28
|
-
useEffect(() => {
|
29
|
-
document.addEventListener("click", checkClick);
|
30
|
-
return () => {
|
31
|
-
document.removeEventListener("click", checkClick);
|
32
|
-
};
|
33
|
-
}, []);
|
34
|
-
|
35
|
-
const codeOnChange = async (e) => {
|
36
|
-
// e.preventDefault();
|
37
|
-
handleCodeToText({ html: e.target.value });
|
38
|
-
};
|
39
|
-
const addHtml = () => {
|
40
|
-
if (html) {
|
41
|
-
if (action === "update") {
|
42
|
-
Transforms.setNodes(
|
43
|
-
editor,
|
44
|
-
{
|
45
|
-
html,
|
46
|
-
},
|
47
|
-
{
|
48
|
-
at: location,
|
49
|
-
}
|
50
|
-
);
|
51
|
-
} else {
|
52
|
-
Transforms.insertNodes(
|
53
|
-
editor,
|
54
|
-
{
|
55
|
-
type: "htmlCode",
|
56
|
-
html: html,
|
57
|
-
children: [{ text: "" }],
|
58
|
-
},
|
59
|
-
{
|
60
|
-
select: true,
|
61
|
-
}
|
62
|
-
);
|
63
|
-
Transforms.insertNodes(editor, {
|
64
|
-
type: "paragraph",
|
65
|
-
children: [{ text: "" }],
|
66
|
-
});
|
67
|
-
}
|
68
|
-
}
|
69
|
-
handleCodeToText({
|
70
|
-
showInput: false,
|
71
|
-
html: "",
|
72
|
-
});
|
73
|
-
};
|
74
|
-
const clearHtml = () => {
|
75
|
-
handleCodeToText({ html: "" });
|
76
|
-
};
|
77
|
-
return (
|
78
|
-
<div className="code-wrapper" ref={wrapperRef}>
|
79
|
-
<div ref={codeToTextRef} className="codeToTextWrapper">
|
80
|
-
<div className="codeToText">
|
81
|
-
<textarea
|
82
|
-
name=""
|
83
|
-
id=""
|
84
|
-
value={html}
|
85
|
-
onChange={codeOnChange}
|
86
|
-
placeholder="Write html here..."
|
87
|
-
></textarea>
|
88
|
-
<div
|
89
|
-
style={{
|
90
|
-
display: "flex",
|
91
|
-
alignItems: "center",
|
92
|
-
justifyContent: "center",
|
93
|
-
color: "white",
|
94
|
-
}}
|
95
|
-
>
|
96
|
-
<Icon icon="arrowRight" />
|
97
|
-
</div>
|
98
|
-
<div className="textOutput">
|
99
|
-
<Interweave content={html} />
|
100
|
-
</div>
|
101
|
-
</div>
|
102
|
-
<div>
|
103
|
-
<button onClick={addHtml} className="done">
|
104
|
-
Done
|
105
|
-
</button>
|
106
|
-
<button className="clear" onClick={clearHtml}>
|
107
|
-
Clear
|
108
|
-
</button>
|
109
|
-
</div>
|
110
|
-
</div>
|
111
|
-
</div>
|
112
|
-
);
|
113
|
-
};
|
114
|
-
|
115
|
-
export default CodeToText;
|
@@ -1,16 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import Button from '../../common/Button'
|
3
|
-
import Icon from '../../common/Icon'
|
4
|
-
const CodeToTextButton = (props) => {
|
5
|
-
const {handleButtonClick} = props
|
6
|
-
|
7
|
-
return (
|
8
|
-
<>
|
9
|
-
<Button format='insert Html' onClick={() => handleButtonClick({showInput:true,action:'insert'})}>
|
10
|
-
<Icon icon='insertHtml'/>
|
11
|
-
</Button>
|
12
|
-
</>
|
13
|
-
)
|
14
|
-
}
|
15
|
-
|
16
|
-
export default CodeToTextButton
|
@@ -1,59 +0,0 @@
|
|
1
|
-
import { Interweave } from "interweave";
|
2
|
-
import React, { useEffect } from "react";
|
3
|
-
import { Transforms, Path } from "slate";
|
4
|
-
import { useSelected, useFocused, useSlateStatic } from "slate-react";
|
5
|
-
import useFormat from "../../utils/customHooks/useFormat";
|
6
|
-
|
7
|
-
const HtmlCode = (props) => {
|
8
|
-
const { attributes, element, children } = props;
|
9
|
-
const selected = useSelected();
|
10
|
-
const focused = useFocused();
|
11
|
-
const editor = useSlateStatic();
|
12
|
-
|
13
|
-
const isHtmlEmbed = useFormat(editor, "htmlCode");
|
14
|
-
|
15
|
-
const handleKeyUp = (e) => {
|
16
|
-
if (!isHtmlEmbed) return;
|
17
|
-
if (e.keyCode === 13) {
|
18
|
-
const parentPath = Path.parent(editor.selection.focus.path);
|
19
|
-
const nextPath = Path.next(parentPath);
|
20
|
-
Transforms.insertNodes(
|
21
|
-
editor,
|
22
|
-
{
|
23
|
-
type: "paragraph",
|
24
|
-
children: [{ text: "" }],
|
25
|
-
},
|
26
|
-
{
|
27
|
-
at: nextPath,
|
28
|
-
select: true, // Focus on this node once inserted
|
29
|
-
}
|
30
|
-
);
|
31
|
-
} else if (e.keyCode === 8) {
|
32
|
-
Transforms.removeNodes(editor);
|
33
|
-
}
|
34
|
-
// console.log(e);
|
35
|
-
};
|
36
|
-
useEffect(() => {
|
37
|
-
document.addEventListener("keyup", handleKeyUp);
|
38
|
-
return () => {
|
39
|
-
document.removeEventListener("keyup", handleKeyUp);
|
40
|
-
};
|
41
|
-
}, [isHtmlEmbed]);
|
42
|
-
return (
|
43
|
-
<div
|
44
|
-
{...attributes}
|
45
|
-
{...element.attr}
|
46
|
-
style={{
|
47
|
-
boxShadow: selected && focused && "0 0 3px 3px lightgray",
|
48
|
-
marginRight: "20px",
|
49
|
-
}}
|
50
|
-
>
|
51
|
-
<div contentEditable={false}>
|
52
|
-
<Interweave content={element.html} />
|
53
|
-
</div>
|
54
|
-
{children}
|
55
|
-
</div>
|
56
|
-
);
|
57
|
-
};
|
58
|
-
|
59
|
-
export default HtmlCode;
|
@@ -1,39 +0,0 @@
|
|
1
|
-
import React, { useState } from "react";
|
2
|
-
import useContextMenu from "../../utils/customHooks/useContextMenu.js";
|
3
|
-
import Icon from "../../common/Icon.jsx";
|
4
|
-
import { Transforms, Node, Path } from "slate";
|
5
|
-
|
6
|
-
const HtmlContextMenu = (props) => {
|
7
|
-
const { editor, handleCodeToText } = props;
|
8
|
-
const [selection, setSelection] = useState();
|
9
|
-
const [showMenu, { top, left }] = useContextMenu(
|
10
|
-
editor,
|
11
|
-
"htmlCode",
|
12
|
-
setSelection
|
13
|
-
);
|
14
|
-
|
15
|
-
const handleEditHtml = () => {
|
16
|
-
Transforms.select(editor, selection);
|
17
|
-
const parentPath = Path.parent(selection.focus.path);
|
18
|
-
const htmlNode = Node.get(editor, parentPath);
|
19
|
-
handleCodeToText({
|
20
|
-
showInput: true,
|
21
|
-
html: htmlNode.html,
|
22
|
-
action: "update",
|
23
|
-
location: selection,
|
24
|
-
});
|
25
|
-
};
|
26
|
-
|
27
|
-
return (
|
28
|
-
showMenu && (
|
29
|
-
<div className="contextMenu" style={{ top, left }}>
|
30
|
-
<div className="menuOption" onClick={handleEditHtml}>
|
31
|
-
<Icon icon="pen" />
|
32
|
-
<span>Edit HTML</span>
|
33
|
-
</div>
|
34
|
-
</div>
|
35
|
-
)
|
36
|
-
);
|
37
|
-
};
|
38
|
-
|
39
|
-
export default HtmlContextMenu;
|
@@ -1,38 +0,0 @@
|
|
1
|
-
|
2
|
-
.color-options{
|
3
|
-
display: grid;
|
4
|
-
grid-template-columns: auto auto auto auto auto auto auto;
|
5
|
-
align-items: center;
|
6
|
-
gap: 5px;
|
7
|
-
}
|
8
|
-
.clicked{
|
9
|
-
border: 1px solid lightgray;
|
10
|
-
border-bottom: none;
|
11
|
-
}
|
12
|
-
.option,.hexPreview{
|
13
|
-
width: 16px;
|
14
|
-
height: 16px;
|
15
|
-
background-color: #000000;
|
16
|
-
|
17
|
-
}
|
18
|
-
.color-picker form{
|
19
|
-
display: flex;
|
20
|
-
align-items: center;
|
21
|
-
column-gap: 5px;
|
22
|
-
width: 100%;
|
23
|
-
}
|
24
|
-
.color-picker input{
|
25
|
-
width: 65%;
|
26
|
-
height:1.3em;
|
27
|
-
border:1px solid lightgray;
|
28
|
-
border-radius: 5px;
|
29
|
-
padding-left:5px
|
30
|
-
}
|
31
|
-
.color-picker button{
|
32
|
-
margin:0;
|
33
|
-
padding:0;
|
34
|
-
cursor: pointer;
|
35
|
-
}
|
36
|
-
.color-picker input:focus{
|
37
|
-
outline: none;
|
38
|
-
}
|
@@ -1,110 +0,0 @@
|
|
1
|
-
import React, { useRef, useState } from "react";
|
2
|
-
import { MdFormatColorText, MdFormatColorFill, MdCheck } from "react-icons/md";
|
3
|
-
import "./ColorPicker.css";
|
4
|
-
import { colors } from "./defaultColors.js";
|
5
|
-
import { addMarkData, activeMark } from "../../utils/SlateUtilityFunctions.js";
|
6
|
-
import { Transforms } from "slate";
|
7
|
-
import usePopup from "../../utils/customHooks/usePopup";
|
8
|
-
import { ReactEditor } from "slate-react";
|
9
|
-
|
10
|
-
const logo = {
|
11
|
-
color: <MdFormatColorText size={20} />,
|
12
|
-
bgColor: <MdFormatColorFill size={20} />,
|
13
|
-
};
|
14
|
-
const ColorPicker = ({ format, editor }) => {
|
15
|
-
const [selection, setSelection] = useState();
|
16
|
-
const [hexValue, setHexValue] = useState("");
|
17
|
-
const [validHex, setValidHex] = useState();
|
18
|
-
const colorPickerRef = useRef(null);
|
19
|
-
const [showOptions, setShowOptions] = usePopup(colorPickerRef);
|
20
|
-
|
21
|
-
const isValideHexSix = new RegExp("^#[0-9A-Za-z]{6}");
|
22
|
-
const isValideHexThree = new RegExp("^#[0-9A-Za-z]{3}");
|
23
|
-
|
24
|
-
const changeColor = (e) => {
|
25
|
-
const clickedColor = e.target.getAttribute("data-value");
|
26
|
-
selection && Transforms.select(editor, selection);
|
27
|
-
selection && ReactEditor.focus(editor);
|
28
|
-
|
29
|
-
addMarkData(editor, { format, value: clickedColor });
|
30
|
-
setShowOptions(false);
|
31
|
-
};
|
32
|
-
const toggleOption = () => {
|
33
|
-
setSelection(editor.selection);
|
34
|
-
selection && ReactEditor.focus(editor);
|
35
|
-
|
36
|
-
setShowOptions((prev) => !prev);
|
37
|
-
};
|
38
|
-
const handleFormSubmit = (e) => {
|
39
|
-
e.preventDefault();
|
40
|
-
if (!validHex) return;
|
41
|
-
selection && Transforms.select(editor, selection);
|
42
|
-
|
43
|
-
addMarkData(editor, { format, value: hexValue });
|
44
|
-
setShowOptions(false);
|
45
|
-
setValidHex("");
|
46
|
-
setHexValue("");
|
47
|
-
selection && ReactEditor.focus(editor);
|
48
|
-
};
|
49
|
-
const handleHexChange = (e) => {
|
50
|
-
e.preventDefault();
|
51
|
-
const newHex = e.target.value;
|
52
|
-
setValidHex(isValideHexSix.test(newHex) || isValideHexThree.test(newHex));
|
53
|
-
setHexValue(newHex);
|
54
|
-
};
|
55
|
-
return (
|
56
|
-
<div className="color-picker popup-wrapper" ref={colorPickerRef}>
|
57
|
-
<button
|
58
|
-
style={{
|
59
|
-
color: showOptions ? "black" : activeMark(editor, format),
|
60
|
-
opacity: "1",
|
61
|
-
}}
|
62
|
-
className={showOptions ? "clicked" : ""}
|
63
|
-
onClick={toggleOption}
|
64
|
-
>
|
65
|
-
{logo[format]}
|
66
|
-
</button>
|
67
|
-
{showOptions && (
|
68
|
-
<div className="popup">
|
69
|
-
<div className="color-options">
|
70
|
-
{colors.map((color, index) => {
|
71
|
-
return (
|
72
|
-
<div
|
73
|
-
key={index}
|
74
|
-
data-value={color}
|
75
|
-
onClick={changeColor}
|
76
|
-
className="option"
|
77
|
-
style={{ background: color }}
|
78
|
-
></div>
|
79
|
-
);
|
80
|
-
})}
|
81
|
-
</div>
|
82
|
-
<p style={{ textAlign: "center", opacity: "0.7", width: "100%" }}>
|
83
|
-
OR
|
84
|
-
</p>
|
85
|
-
<form onSubmit={handleFormSubmit}>
|
86
|
-
<div
|
87
|
-
className="hexPreview"
|
88
|
-
style={{ background: validHex ? hexValue : "#000000" }}
|
89
|
-
></div>
|
90
|
-
<input
|
91
|
-
type="text"
|
92
|
-
placeholder="#000000"
|
93
|
-
value={hexValue}
|
94
|
-
onChange={handleHexChange}
|
95
|
-
style={{
|
96
|
-
border:
|
97
|
-
validHex === false ? "1px solid red" : "1px solid lightgray",
|
98
|
-
}}
|
99
|
-
/>
|
100
|
-
<button style={{ color: validHex ? "green" : "" }} type={"submit"}>
|
101
|
-
<MdCheck size={20} />
|
102
|
-
</button>
|
103
|
-
</form>
|
104
|
-
</div>
|
105
|
-
)}
|
106
|
-
</div>
|
107
|
-
);
|
108
|
-
};
|
109
|
-
|
110
|
-
export default ColorPicker;
|
@@ -1,34 +0,0 @@
|
|
1
|
-
export const colors = ["#000000","#e60000",
|
2
|
-
"#ff9900",
|
3
|
-
"#ffff00",
|
4
|
-
"#008a00",
|
5
|
-
"#0066cc",
|
6
|
-
"#9933ff",
|
7
|
-
"#ffffff",
|
8
|
-
"#facccc",
|
9
|
-
"#ffebcc",
|
10
|
-
"#ffffcc",
|
11
|
-
"#cce8cc",
|
12
|
-
"#cce0f5",
|
13
|
-
"#ebd6ff",
|
14
|
-
"#bbbbbb",
|
15
|
-
"#f06666",
|
16
|
-
"#ffc266",
|
17
|
-
"#ffff66",
|
18
|
-
"#66b966",
|
19
|
-
"#66a3e0",
|
20
|
-
"#c285ff",
|
21
|
-
"#888888",
|
22
|
-
"#a10000",
|
23
|
-
"#b26b00",
|
24
|
-
"#b2b200",
|
25
|
-
"#006100",
|
26
|
-
"#0047b2",
|
27
|
-
"#6b24b2",
|
28
|
-
"#444444",
|
29
|
-
"#5c0000",
|
30
|
-
"#663d00",
|
31
|
-
"#666600",
|
32
|
-
"#003700",
|
33
|
-
"#002966",
|
34
|
-
"#3d1466"]
|
@@ -1,74 +0,0 @@
|
|
1
|
-
import React, {useRef, useState} from 'react';
|
2
|
-
import Button from '../../common/Button'
|
3
|
-
import Icon from '../../common/Icon'
|
4
|
-
import {isBlockActive} from '../../utils/SlateUtilityFunctions'
|
5
|
-
import usePopup from '../../utils/customHooks/usePopup'
|
6
|
-
import {insertEmbed } from '../../utils/embed.js'
|
7
|
-
import { Transforms } from 'slate';
|
8
|
-
import {ReactEditor} from 'slate-react'
|
9
|
-
|
10
|
-
import './Embed.css'
|
11
|
-
const Embed = ({editor,format}) =>{
|
12
|
-
const urlInputRef = useRef();
|
13
|
-
const [showInput,setShowInput] = usePopup(urlInputRef);
|
14
|
-
const [formData,setFormData] = useState({
|
15
|
-
url:'',
|
16
|
-
alt:''
|
17
|
-
})
|
18
|
-
const [selection,setSelection] = useState();
|
19
|
-
const handleButtonClick = (e)=>{
|
20
|
-
e.preventDefault();
|
21
|
-
setSelection(editor.selection);
|
22
|
-
selection && ReactEditor.focus(editor);
|
23
|
-
|
24
|
-
setShowInput(prev =>!prev);
|
25
|
-
}
|
26
|
-
const handleFormSubmit = (e)=>{
|
27
|
-
e.preventDefault();
|
28
|
-
|
29
|
-
selection && Transforms.select(editor,selection);
|
30
|
-
selection && ReactEditor.focus(editor);
|
31
|
-
|
32
|
-
insertEmbed(editor,{...formData},format);
|
33
|
-
setShowInput(false);
|
34
|
-
setFormData({
|
35
|
-
url:'',
|
36
|
-
alt:''
|
37
|
-
})
|
38
|
-
}
|
39
|
-
const handleImageUpload = ()=>{
|
40
|
-
setShowInput(false)
|
41
|
-
}
|
42
|
-
return (
|
43
|
-
<div ref={urlInputRef} className='popup-wrapper'>
|
44
|
-
<Button active={isBlockActive(editor,format)} style={{border: showInput?'1px solid lightgray':'',borderBottom: 'none'}} format={format} onClick={handleButtonClick}>
|
45
|
-
<Icon icon={format}/>
|
46
|
-
</Button>
|
47
|
-
{
|
48
|
-
showInput&&
|
49
|
-
<div className='popup'>
|
50
|
-
{
|
51
|
-
format === 'image' &&
|
52
|
-
<div>
|
53
|
-
<div style={{display:'flex',gap:'10px'}} onClick={handleImageUpload}>
|
54
|
-
<Icon icon='upload'/>
|
55
|
-
<span>Upload</span>
|
56
|
-
</div>
|
57
|
-
<p style={{textAlign:'center',opacity:'0.7',width:'100%'}}>OR</p>
|
58
|
-
|
59
|
-
</div>
|
60
|
-
}
|
61
|
-
<form onSubmit={handleFormSubmit}>
|
62
|
-
<input type="text" placeholder='Enter url' value={formData.url} onChange={e=>setFormData(prev =>({...prev,url:e.target.value}))}/>
|
63
|
-
<input type="text" placeholder='Enter alt' value={formData.alt} onChange={e=>setFormData(prev =>({...prev,alt:e.target.value}))}/>
|
64
|
-
|
65
|
-
|
66
|
-
<Button type='submit'>Save</Button>
|
67
|
-
</form>
|
68
|
-
</div>
|
69
|
-
}
|
70
|
-
</div>
|
71
|
-
)
|
72
|
-
}
|
73
|
-
|
74
|
-
export default Embed;
|
@@ -1,82 +0,0 @@
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
2
|
-
import {
|
3
|
-
useSlateStatic,
|
4
|
-
useSelected,
|
5
|
-
useFocused,
|
6
|
-
ReactEditor,
|
7
|
-
} from "slate-react";
|
8
|
-
import { Node, Transforms } from "slate";
|
9
|
-
import Icon from "../../common/Icon";
|
10
|
-
import useResize from "../../utils/customHooks/useResize.js";
|
11
|
-
|
12
|
-
const Image = ({ attributes, element, children }) => {
|
13
|
-
const { url, alt } = element;
|
14
|
-
const editor = useSlateStatic();
|
15
|
-
const selected = useSelected();
|
16
|
-
const focused = useFocused();
|
17
|
-
const [parentDOM, setParentDOM] = useState(null);
|
18
|
-
const [size, onMouseDown, resizing, onLoad] = useResize({
|
19
|
-
parentDOM,
|
20
|
-
size: element?.size,
|
21
|
-
});
|
22
|
-
const arr = Array.from(Node.elements(editor));
|
23
|
-
const ele = arr.find(([elem]) => element === elem);
|
24
|
-
|
25
|
-
useEffect(() => {
|
26
|
-
if (editor && ele[1] !== undefined) {
|
27
|
-
const dom = ReactEditor.toDOMNode(editor, Node.get(editor, ele[1]));
|
28
|
-
setParentDOM(dom);
|
29
|
-
onLoad(dom);
|
30
|
-
}
|
31
|
-
}, []);
|
32
|
-
|
33
|
-
useEffect(() => {
|
34
|
-
if (!resizing) {
|
35
|
-
Transforms.setNodes(editor, {
|
36
|
-
size: size,
|
37
|
-
});
|
38
|
-
}
|
39
|
-
}, [resizing]);
|
40
|
-
|
41
|
-
return (
|
42
|
-
<div
|
43
|
-
{...attributes}
|
44
|
-
className="embed"
|
45
|
-
style={{
|
46
|
-
display: "flex",
|
47
|
-
width: "100%",
|
48
|
-
maxWidth: "100%",
|
49
|
-
boxShadow: selected && focused && "0 0 3px 3px lightgray",
|
50
|
-
}}
|
51
|
-
{...element.attr}
|
52
|
-
>
|
53
|
-
<div
|
54
|
-
contentEditable={false}
|
55
|
-
style={{
|
56
|
-
position: "relative",
|
57
|
-
width: size.widthInPercent
|
58
|
-
? `${size.widthInPercent}%`
|
59
|
-
: `${size.width}px`,
|
60
|
-
height: `${size.height}px`,
|
61
|
-
}}
|
62
|
-
>
|
63
|
-
<img alt={alt} src={url} />
|
64
|
-
{selected && (
|
65
|
-
<button
|
66
|
-
onPointerDown={onMouseDown}
|
67
|
-
style={{
|
68
|
-
width: "15px",
|
69
|
-
height: "15px",
|
70
|
-
opacity: 1,
|
71
|
-
background: "transparent",
|
72
|
-
}}
|
73
|
-
>
|
74
|
-
<Icon icon="resize" />
|
75
|
-
</button>
|
76
|
-
)}
|
77
|
-
</div>
|
78
|
-
{children}
|
79
|
-
</div>
|
80
|
-
);
|
81
|
-
};
|
82
|
-
export default Image;
|
@@ -1,65 +0,0 @@
|
|
1
|
-
import React from "react";
|
2
|
-
import { useSelected, useFocused } from "slate-react";
|
3
|
-
import Icon from "../../common/Icon";
|
4
|
-
import useResize from "../../utils/customHooks/useResize.js";
|
5
|
-
// import "./Video.css";
|
6
|
-
|
7
|
-
const Video = ({ attributes, element, children }) => {
|
8
|
-
const { url, alt } = element;
|
9
|
-
const [size, onMouseDown, resizing] = useResize();
|
10
|
-
const selected = useSelected();
|
11
|
-
const focused = useFocused();
|
12
|
-
return (
|
13
|
-
<div
|
14
|
-
{...attributes}
|
15
|
-
className="embed"
|
16
|
-
style={{
|
17
|
-
display: "flex",
|
18
|
-
boxShadow: selected && focused && "0 0 3px 3px lightgray",
|
19
|
-
}}
|
20
|
-
{...element.attr}
|
21
|
-
>
|
22
|
-
<div
|
23
|
-
contentEditable={false}
|
24
|
-
style={{ width: `${size.width}px`, height: `${size.height}px` }}
|
25
|
-
>
|
26
|
-
{
|
27
|
-
// The iframe reloads on each re-render and hence it stutters and the document doesn't detect mouse-up event leading to unwanted behaviour
|
28
|
-
// So during resize replace the iframe with a simple div
|
29
|
-
resizing ? (
|
30
|
-
<div
|
31
|
-
style={{
|
32
|
-
width: "100%",
|
33
|
-
height: "100%",
|
34
|
-
border: "2px dashed black",
|
35
|
-
display: "flex",
|
36
|
-
justifyContent: "center",
|
37
|
-
alignItems: "center",
|
38
|
-
}}
|
39
|
-
>
|
40
|
-
<Icon icon="videoPlayer" />
|
41
|
-
</div>
|
42
|
-
) : (
|
43
|
-
<iframe src={url} frameBorder="0" title={alt} />
|
44
|
-
)
|
45
|
-
}
|
46
|
-
|
47
|
-
{selected && (
|
48
|
-
<button
|
49
|
-
onMouseDown={onMouseDown}
|
50
|
-
style={{
|
51
|
-
width: "15px",
|
52
|
-
height: "15px",
|
53
|
-
opacity: 1,
|
54
|
-
background: "transparent",
|
55
|
-
}}
|
56
|
-
>
|
57
|
-
<Icon icon="resize" />
|
58
|
-
</button>
|
59
|
-
)}
|
60
|
-
</div>
|
61
|
-
{children}
|
62
|
-
</div>
|
63
|
-
);
|
64
|
-
};
|
65
|
-
export default Video;
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import React from "react";
|
2
|
-
import { InlineMath, BlockMath } from "react-katex";
|
3
|
-
|
4
|
-
import "./styles.css";
|
5
|
-
const Equation = ({ attributes, element, children }) => {
|
6
|
-
const { inline, math } = element;
|
7
|
-
return (
|
8
|
-
<div className={inline ? "equation-inline" : ""}>
|
9
|
-
<span {...attributes} {...element.attr}>
|
10
|
-
<span contentEditable={false}>
|
11
|
-
{inline ? <InlineMath math={math} /> : <BlockMath math={math} />}
|
12
|
-
</span>
|
13
|
-
{children}
|
14
|
-
</span>
|
15
|
-
</div>
|
16
|
-
);
|
17
|
-
};
|
18
|
-
|
19
|
-
export default Equation;
|