diff --git a/example/src/App.tsx b/example/src/App.tsx
index 69d2366..48e0dfb 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -110,5 +110,21 @@ const blockInitalValue2 = [
},
},
},
+ {
+ block: {
+ _id: '5',
+ type: 'image',
+ properties: {
+ document: [
+ {
+ text: '',
+ properties: [
+ 'https://repository-images.githubusercontent.com/125159715/61f2ee00-865a-11e9-8ce5-f7028c561633',
+ ],
+ },
+ ],
+ },
+ },
+ },
];
export default App;
diff --git a/src/Editor.tsx b/src/Editor.tsx
index 39bdfdc..ac954a8 100644
--- a/src/Editor.tsx
+++ b/src/Editor.tsx
@@ -12,6 +12,8 @@ import { withLinks } from './Helpers/LinkHelper';
import Element from './plugins/Element';
import Leaf from './plugins/Leaf';
import withBlockID from './plugins/withBlockID';
+import withImages from './plugins/withImages';
+import withBreak from './plugins/withBreak';
import serialize from './serialize/index';
import deserialize from './deserialize/index';
import { ADD, UPDATE, DELETE } from './constant/operations';
@@ -40,7 +42,7 @@ const Editor: (props: Props) => any = ({
isHoveringToolBar = false,
}) => {
const [editorData, setData] = useState(EMPTY_NODE);
- const withPlugins = [withReact, withHistory, withLinks, withBlockID] as const;
+ const withPlugins = [withReact, withHistory, withLinks, withBlockID, withImages, withBreak] as const;
const editor: any = useMemo(() => pipe(createEditor(), ...withPlugins), []);
const renderElement = useCallback((props) => , []);
const renderLeaf = useCallback((props) => , []);
diff --git a/src/Helpers/ImageHelper.tsx b/src/Helpers/ImageHelper.tsx
new file mode 100644
index 0000000..4089d5f
--- /dev/null
+++ b/src/Helpers/ImageHelper.tsx
@@ -0,0 +1,33 @@
+import React, { FC, SVGProps } from 'react';
+import { Transforms } from 'slate';
+import { ReactEditor, useSlate } from 'slate-react';
+
+import { Button, Icon } from './Helper';
+
+export const insertImage = (editor: ReactEditor, url: string) => {
+ const text = { text: '' };
+ const image = { type: 'image', url, children: [text] };
+ Transforms.insertNodes(editor, image);
+};
+
+interface InsertImageButtonProps {
+ icon: FC>;
+ iconColor?: string;
+}
+export const InsertImageButton: (props: InsertImageButtonProps) => JSX.Element = ({ icon, iconColor = '#ffffff' }) => {
+ const editor = useSlate();
+ return (
+
+ );
+};
diff --git a/src/ToolBar/ToolBar.tsx b/src/ToolBar/ToolBar.tsx
index bcf5e3c..a3632ec 100644
--- a/src/ToolBar/ToolBar.tsx
+++ b/src/ToolBar/ToolBar.tsx
@@ -7,6 +7,7 @@ import { BlockButton } from '../Helpers/BlockHelper';
import { MarkButton } from '../Helpers/MarkHelper';
import { LinkButton, insertLink } from '../Helpers/LinkHelper';
import { Menu, Portal, LinkInput } from '../Helpers/Helper';
+import { InsertImageButton } from '../Helpers/ImageHelper';
// icons
import { ReactComponent as Bold } from '../assets/bold.svg';
@@ -18,6 +19,7 @@ import { ReactComponent as Underline } from '../assets/underline.svg';
import { ReactComponent as H1 } from '../assets/h1.svg';
import { ReactComponent as H2 } from '../assets/h2.svg';
import { ReactComponent as CLEAR_FORMAT } from '../assets/clear_format.svg';
+import { ReactComponent as Image } from '../assets/image.svg';
const ICON_COLOR = '#b5b9c6';
export const FixedMenu: any = React.forwardRef(({ ...props }, ref: React.Ref) => (
@@ -113,6 +115,7 @@ export const ToolBar: React.FC = () => {
+
diff --git a/src/assets/image.svg b/src/assets/image.svg
new file mode 100644
index 0000000..b711525
--- /dev/null
+++ b/src/assets/image.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/deserialize/index.ts b/src/deserialize/index.ts
index 8e151aa..06b27ad 100644
--- a/src/deserialize/index.ts
+++ b/src/deserialize/index.ts
@@ -56,6 +56,10 @@ const deserialization = (blockContentList: any) => {
const { block } = blockContent;
const children = getChildNodes(block);
const type = getNodeType(block.type);
+ if (type === 'image' && block.properties) {
+ return { id: block._id, type, children, url: block.properties.document[0].properties };
+ }
+
return { id: block._id, type, children };
});
return deserializedContent;
diff --git a/src/plugins/Element.tsx b/src/plugins/Element.tsx
index e2e913f..459a0d0 100644
--- a/src/plugins/Element.tsx
+++ b/src/plugins/Element.tsx
@@ -10,6 +10,7 @@ import {
Rectangle,
Heading1,
Heading2,
+ Image,
} from './ElementStyle';
import getShortLink from '../utils/getShortLink';
@@ -41,6 +42,15 @@ const Element: React.FC = ({ attributes, children, element }
);
+ case `image`:
+ return (
+
+ );
default:
return {children}
;
}
diff --git a/src/plugins/ElementStyle.ts b/src/plugins/ElementStyle.ts
index ee372c5..de88d12 100644
--- a/src/plugins/ElementStyle.ts
+++ b/src/plugins/ElementStyle.ts
@@ -79,3 +79,9 @@ export const Heading1 = styled.h1`
export const Heading2 = styled.h2`
color: ${({ theme }) => (theme.colors !== undefined ? theme.colors.text : '#050b21')};
`;
+export const Image = styled.img`
+ display: block;
+ max-width: 100%;
+ max-height: 20em;
+ padding: 4px 0px 0px 20px;
+`;
diff --git a/src/plugins/withBreak.tsx b/src/plugins/withBreak.tsx
new file mode 100644
index 0000000..f133692
--- /dev/null
+++ b/src/plugins/withBreak.tsx
@@ -0,0 +1,18 @@
+import { Transforms } from 'slate';
+
+const withBreak = (editor: any) => {
+ const localEditor = editor;
+ localEditor.insertBreak = () => {
+ const newLine = {
+ type: 'paragraph',
+ children: [
+ {
+ text: '',
+ },
+ ],
+ };
+ Transforms.insertNodes(editor, newLine);
+ };
+ return localEditor;
+};
+export default withBreak;
diff --git a/src/plugins/withImages.tsx b/src/plugins/withImages.tsx
new file mode 100644
index 0000000..a8716d0
--- /dev/null
+++ b/src/plugins/withImages.tsx
@@ -0,0 +1,11 @@
+import { ReactEditor } from 'slate-react';
+
+const withImages = (editor: ReactEditor) => {
+ const { isVoid } = editor;
+ const localEditor = editor;
+ localEditor.isVoid = (element) => {
+ return element.type === 'image' ? true : isVoid(element);
+ };
+ return localEditor;
+};
+export default withImages;
diff --git a/src/serialize/index.tsx b/src/serialize/index.tsx
index 2211ca8..54fc60f 100644
--- a/src/serialize/index.tsx
+++ b/src/serialize/index.tsx
@@ -38,7 +38,12 @@ const checkIdAndReturnBlock = (type: string, document: any, node: any) => {
const serializeParagraph = (paragraphNode: any, textType: string) => {
const document = paragraphNode.children.map((childNodes: any) => {
const text = getParagraphText(childNodes);
- const properties = getParagraphProperties(childNodes);
+ let properties = [];
+ if (textType === 'image') {
+ properties.push(paragraphNode.url);
+ } else {
+ properties = getParagraphProperties(childNodes);
+ }
return { text, properties };
});
const paragraphBlock = checkIdAndReturnBlock(textType, document, paragraphNode);
@@ -64,6 +69,8 @@ const serialize = (slateNodesList: any) => {
case 'heading-one':
case 'heading-two':
return serializeHeading(node, node.type);
+ case 'image':
+ return serializeParagraph(node, 'image');
default:
return serializeParagraph(node, 'text');
}