diff --git a/demo/src/index.js b/demo/src/index.js
index d443aa9..04ac239 100644
--- a/demo/src/index.js
+++ b/demo/src/index.js
@@ -3,14 +3,14 @@ import { render } from "react-dom";
import Editor from "../../src";
import styles from "../../src/styles.module.css";
-import { ConfigProvider, Divider, Drawer, FloatButton, Select, Space, Switch } from "antd";
+import { Button, ConfigProvider, Divider, Drawer, FloatButton, Select, Space, Switch } from "antd";
import Icons from "../../src/icons";
import i18n from "../../src/i18n";
const Demo = () => {
const [open, setOpen] = useState(false);
- const [value, setValue] = useState(null);
+ const [value, setValue] = useState("# this is heading\n\nThis is a paragraph");
const [configuration, setConfiguration] = useState({
richText: true,
language: "en",
@@ -23,7 +23,9 @@ const Demo = () => {
showUndoRedo: true,
showExtraFormat: true,
showInsertLink: true,
+ showSave: true,
},
+ onSave: (contents) => console.log(contents),
format: "raw",
});
const locale = i18n[configuration.language];
@@ -154,6 +156,10 @@ const Demo = () => {
setConfiguration((e) => ({ ...e, toolbar: {... e.toolbar, showInsertLink : checked } }))
}
/>
+
+
diff --git a/src/commands/saveCommand.js b/src/commands/saveCommand.js
new file mode 100644
index 0000000..b86afaa
--- /dev/null
+++ b/src/commands/saveCommand.js
@@ -0,0 +1,26 @@
+import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
+import {
+ COMMAND_PRIORITY_LOW,
+ createCommand,
+} from 'lexical';
+import {useEffect} from 'react';
+
+export const SAVE_COMMAND = createCommand('SAVE_COMMAND');
+
+export function SavePlugin({ onSave = () => {} }) {
+ const [editor] = useLexicalComposerContext();
+
+ useEffect(() => {
+ editor.registerCommand(
+ SAVE_COMMAND,
+ () => {
+ console.log('save command fired');
+ onSave(editor.getEditorState());
+ },
+ COMMAND_PRIORITY_LOW,
+ );
+
+ }, [editor]);
+
+ return null;
+}
diff --git a/src/i18n/index.js b/src/i18n/index.js
index e9c3035..690107e 100644
--- a/src/i18n/index.js
+++ b/src/i18n/index.js
@@ -34,6 +34,7 @@ export default {
insert: "Insert",
horizontalRule: "Horizontal Rule",
image: "Insert Image",
+ save: "Save",
},
},
'ur': {
@@ -71,6 +72,7 @@ export default {
insert: "متفرقات",
horizontalRule: "افقی قاعدہ",
image: "تصویر شامل کریں",
+ save: "محفوظ کریں",
}
}
}
diff --git a/src/icons/index.js b/src/icons/index.js
index 8918627..da0101c 100644
--- a/src/icons/index.js
+++ b/src/icons/index.js
@@ -33,7 +33,8 @@ const Icons = {
Plus: () => (),
HorizontalRule: () => (),
Image: () => (),
- Down: () => (),
- Setting: () => ()
+ Down: () => (),
+ Setting: () => (),
+ Save: () => ()
};
export default Icons
diff --git a/src/index.js b/src/index.js
index 72ad292..24a6132 100644
--- a/src/index.js
+++ b/src/index.js
@@ -24,11 +24,13 @@ import ToolbarPlugin from "./plugins/toolbar";
import AutoLinkPlugin from './plugins/autoLink.Plugin';
import { HorizontalRulePlugin } from './plugins/horizontalRulePlugin';
import LinkPlugin from './plugins/link.Plugin';
+import { ControlledValuePlugin } from './plugins/controlledValuePlugin';
import EditorNodes from "./nodes";
import EditorTheme from './themes/editorTheme'
// ------------------------------------------------------
import i18n from './i18n';
import styles from './styles.module.css'; // Import css modules stylesheet as styles
+import { SavePlugin } from './commands/saveCommand';
// ------------------------------------------------------
const EMPTY_CONTENT =
@@ -58,13 +60,14 @@ function Placeholder({ children }) {
// ------------------------------------------------------
export default ({ value = EMPTY_CONTENT,
- setValue = () => {},
+ onChange = () => {},
configuration = {
richText : false,
toolbar : {
fonts : null,
- fontSizes: null,
+ fontSizes: null
},
+ onSave: () => {},
language : "en",
languageTools: false,
placeholder : null,
@@ -76,24 +79,24 @@ export default ({ value = EMPTY_CONTENT,
const [editorState, setEditorState] = useState(value !== null & value === EMPTY_CONTENT && configuration.format == 'markdown'? ' ' : EMPTY_CONTENT);
const initialConfig = {
namespace: "MyEditor",
- editorState: configuration.format == "markdown" ? () => value == null ? '' : $convertFromMarkdownString(value, TRANSFORMERS) : value,
+ editorState: editorState,
nodes: [...EditorNodes],
theme: EditorTheme,
onError,
};
- function onChange(editorState) {
- if (configuration.format == "markdown") {
- editorState.read(() => {
- const markdown = $convertToMarkdownString(TRANSFORMERS);
- setValue(markdown);
- });
- } else {
- const editorStateJSON = editorState.toJSON();
- setEditorState(JSON.stringify(editorStateJSON));
- setValue(JSON.stringify(editorStateJSON));
- }
- }
+ // function onChange(editorState) {
+ // if (configuration.format == "markdown") {
+ // editorState.read(() => {
+ // const markdown = $convertToMarkdownString(TRANSFORMERS);
+ // setValue(markdown);
+ // });
+ // } else {
+ // const editorStateJSON = editorState.toJSON();
+ // setEditorState(JSON.stringify(editorStateJSON));
+ // setValue(JSON.stringify(editorStateJSON));
+ // }
+ // }
return (
@@ -119,7 +122,12 @@ export default ({ value = EMPTY_CONTENT,
/> }
-
+ { configuration?.toolbar?.showSave && }
+
{configuration.format == "markdown" && }
diff --git a/src/plugins/controlledValuePlugin.js b/src/plugins/controlledValuePlugin.js
new file mode 100644
index 0000000..42c723e
--- /dev/null
+++ b/src/plugins/controlledValuePlugin.js
@@ -0,0 +1,62 @@
+import React, { useEffect } from "react";
+
+import {
+ $getSelection,
+ $getRoot,
+ $createParagraphNode,
+ $createTextNode,
+ $setSelection} from "lexical";
+import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
+
+import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
+
+export const ControlledValuePlugin = ({ value, onChange, isRichtext, format }) => {
+ useAdoptPlaintextValue(value, isRichtext);
+
+ const handleChange = (editorState) => {
+ editorState.read(() => {
+ onChange(editorState);
+ });
+ };
+
+ return ;
+};
+
+export const useAdoptPlaintextValue = (value, isRichtext) => {
+ const [editor] = useLexicalComposerContext();
+
+ useEffect(() => {
+ editor.update(() => {
+ console.log(`Value updated %o`, value);
+ if (isRichtext) {
+ const paragraphNode = $createParagraphNode();
+ const textNode = $createTextNode(value);
+ paragraphNode.append(textNode);
+ $getRoot().clear();
+ $getRoot().append(paragraphNode);
+ } else {
+ const root = $getRoot();
+ root.append(paragraphNode);
+ const initialSelection = $getSelection()?.clone() ?? null;
+ $getRoot().clear();
+ $getRoot().select(); // for some reason this is not even necessary
+ $getSelection()?.insertText(value);
+ $setSelection(initialSelection);
+ }
+ });
+ }, [value, editor]);
+};
+
+// export const useAdoptPlaintextValue = (value: string) => {
+// const [editor] = useLexicalComposerContext();
+
+// useEffect(() => {
+// editor.update(() => {
+// const paragraph = $createParagraphNode();
+// const text = $createTextNode(value);
+// paragraph.append(text);
+// $getRoot().clear();
+// $getRoot().append(paragraph);
+// });
+// }, [value, editor]);
+// };
diff --git a/src/plugins/toolbar.js b/src/plugins/toolbar.js
index feb17d2..40d179d 100644
--- a/src/plugins/toolbar.js
+++ b/src/plugins/toolbar.js
@@ -52,6 +52,7 @@ import Icons from '../icons'
import CheckButton from "../components/checkButton";
import AlignFormatDropDown from "./alignFormatDropDown";
import styles from "../styles.module.css";
+import { SAVE_COMMAND } from '../commands/saveCommand';
// -----------------------------------------------------------
@@ -66,6 +67,8 @@ const ToolbarPlugin = ({ configuration = {
showUndoRedo: true,
showExtraFormat: true,
showInsertLink: true,
+ showSave: false,
+ onSave: () => {}
}, locale }) => {
const [editor] = useLexicalComposerContext();
const [activeEditor, setActiveEditor] = useState(editor);
@@ -273,6 +276,10 @@ const ToolbarPlugin = ({ configuration = {
return (
+ { configuration.showSave &&
+ }
{ configuration.showUndoRedo && <>