Skip to content

Commit

Permalink
Added save button and serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
umerfaruk committed Feb 26, 2024
1 parent bdf3371 commit 3188afe
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 20 deletions.
10 changes: 8 additions & 2 deletions demo/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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];
Expand Down Expand Up @@ -154,6 +156,10 @@ const Demo = () => {
setConfiguration((e) => ({ ...e, toolbar: {... e.toolbar, showInsertLink : checked } }))
}
/>
<Divider />
<Button onClick={() => setValue(Date.now())}>
Change Value
</Button>
</Space>
</Drawer>
</ConfigProvider>
Expand Down
26 changes: 26 additions & 0 deletions src/commands/saveCommand.js
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions src/i18n/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default {
insert: "Insert",
horizontalRule: "Horizontal Rule",
image: "Insert Image",
save: "Save",
},
},
'ur': {
Expand Down Expand Up @@ -71,6 +72,7 @@ export default {
insert: "متفرقات",
horizontalRule: "افقی قاعدہ",
image: "تصویر شامل کریں",
save: "محفوظ کریں",
}
}
}
5 changes: 3 additions & 2 deletions src/icons/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 24 additions & 16 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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,
Expand All @@ -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 (
<div className={ isRtl ? styles.rtl : null }>
Expand All @@ -119,7 +122,12 @@ export default ({ value = EMPTY_CONTENT,
/> }
<HistoryPlugin />
<MyCustomAutoFocusPlugin />
<OnChangePlugin onChange={onChange} />
{ configuration?.toolbar?.showSave && <SavePlugin onSave={configuration.onSave} /> }
<ControlledValuePlugin
value={value}
onChange={onChange}
format={configuration.format }
isRichtext={configuration.richText} />
{configuration.format == "markdown" && <MarkdownShortcutPlugin transformers={TRANSFORMERS} />}
</LexicalComposer>
</div>
Expand Down
62 changes: 62 additions & 0 deletions src/plugins/controlledValuePlugin.js
Original file line number Diff line number Diff line change
@@ -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 <OnChangePlugin onChange={handleChange} />;
};

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]);
// };
7 changes: 7 additions & 0 deletions src/plugins/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

// -----------------------------------------------------------

Expand All @@ -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);
Expand Down Expand Up @@ -273,6 +276,10 @@ const ToolbarPlugin = ({ configuration = {

return (
<div className={styles.toolbar}>
{ configuration.showSave && <Tooltip title={locale.resources.save}>
<Button type="text" onClick={() => editor.dispatchCommand(SAVE_COMMAND) } disabled={!canUndo}
icon={ <Icons.Save /> } />
</Tooltip>}
{ configuration.showUndoRedo && <>
<Tooltip title={locale.resources.undo}>
<Button type="text" onClick={() => activeEditor.dispatchCommand(UNDO_COMMAND, undefined)} disabled={!canUndo}
Expand Down

0 comments on commit 3188afe

Please sign in to comment.