diff --git a/.changeset/wild-garlics-kick.md b/.changeset/wild-garlics-kick.md new file mode 100644 index 0000000000..74673bf460 --- /dev/null +++ b/.changeset/wild-garlics-kick.md @@ -0,0 +1,5 @@ +--- +'@udecode/plate-core': minor +--- + +Add string value support for `createSlateEditor`, `createPlateEditor`, `usePlateEditor` diff --git a/apps/www/content/docs/editor.mdx b/apps/www/content/docs/editor.mdx index c9c341fee1..0564ff0d79 100644 --- a/apps/www/content/docs/editor.mdx +++ b/apps/www/content/docs/editor.mdx @@ -33,6 +33,17 @@ const editor = createPlateEditor({ }); ``` +You can also initialize the editor with an HTML string and the associated plugins: + +```ts +const editor = createPlateEditor({ + plugins: [BoldPlugin, ItalicPlugin], + value: '

This is bold and italic text!

', +}); +``` + +For a comprehensive list of plugins that support HTML string deserialization, refer to the [Plugin Deserialization Rules](/docs/html#plugin-deserialization-rules) section. + ### Adding Plugins You can add plugins to your editor by including them in the `plugins` array: @@ -176,12 +187,12 @@ const editor = createPlateEditor({ ## Typed Editor -`createPlateEditor` will automatically infer the types for your editor from the value and the plugins you pass in. For explicit type creation, you can use `createTPlateEditor`: +`createPlateEditor` will automatically infer the types for your editor from the value and the plugins you pass in. For explicit type creation, use the generics: ### Plugins Type ```ts -const editor = createTPlateEditor({ +const editor = createPlateEditor({ plugins: [TablePlugin, LinkPlugin], }); @@ -238,7 +249,7 @@ const editorInferred = createPlateEditor({ }); // or -const editorExplicit = createTPlateEditor({ +const editorExplicit = createPlateEditor({ plugins: [TablePlugin, LinkPlugin], value, }); diff --git a/apps/www/content/docs/getting-started.mdx b/apps/www/content/docs/getting-started.mdx index 85cb74feee..ba66147739 100644 --- a/apps/www/content/docs/getting-started.mdx +++ b/apps/www/content/docs/getting-started.mdx @@ -109,21 +109,26 @@ export default function BasicEditor() { ### Implementing Change Handler -At this stage, it's crucial to monitor editor modifications in order to store the values appropriately. The **`onChange`** prop will serve this purpose. +At this stage, it's crucial to monitor editor modifications in order to store the values appropriately. The **`onChange`** prop will serve this purpose. You can also persist the editor's state by saving the value to local storage or a database and loading it back when needed. -```tsx showLineNumbers {6-8} +```tsx showLineNumbers {4-5,8,14-16} // ... export default function BasicEditor() { + const localValue = + typeof window !== 'undefined' && localStorage.getItem('editorContent'); + const editor = usePlateEditor({ - value, - onChange: (newValue) => { - // save newValue... - }, + value: localValue ? JSON.parse(localValue) : value, }); return ( - + { + localStorage.setItem('editorContent', JSON.stringify(value)); + }} + > ); @@ -230,6 +235,32 @@ export default function BasicEditor() { +### Initializing Editor's Value with HTML String + +You can also specify the initial content of the editor using an HTML string and the corresponding plugins. + +```tsx showLineNumbers {3,7} +// ... + +const htmlValue = '

This is bold and italic text!

'; + +export default function BasicEditor() { + const editor = usePlateEditor({ + value: htmlValue, + plugins: [ + BoldPlugin, + ItalicPlugin, + ], + }); + + return ( + + + + ); +} +``` + ### That's it! You can now play around with the Playground and start building your own editor. diff --git a/apps/www/content/docs/html.mdx b/apps/www/content/docs/html.mdx index 9fb23ff375..471b0b396a 100644 --- a/apps/www/content/docs/html.mdx +++ b/apps/www/content/docs/html.mdx @@ -13,10 +13,25 @@ Many Plate plugins include HTML deserialization rules. These rules define how HT ## HTML -> Slate -Here's a comprehensive list of plugins that support HTML deserialization, along with their corresponding HTML elements and styles: +### Usage + +The `editor.api.html.deserialize` function allows you to convert HTML content into Slate value: + +```typescript +import { createPlateEditor } from '@udecode/plate-common/react'; + +const editor = createPlateEditor({ + plugins: [ + // all plugins that you want to deserialize + ] +}) +editor.children = editor.api.html.deserialize('

Hello, world!

') +``` ### Plugin Deserialization Rules +Here's a comprehensive list of plugins that support HTML deserialization, along with their corresponding HTML elements and styles: + #### Text Formatting - **BoldPlugin**: ``, ``, or `style="font-weight: 600|700|bold"` @@ -168,6 +183,32 @@ export const IndentListPlugin = createTSlatePlugin({ }); ``` +### API + +#### editor.api.html.deserialize + +Deserialize HTML string into Slate value. + + + + +The HTML element or string to deserialize. + + + + +Flag to enable or disable the removal of whitespace from the serialized HTML. + +- **Default:** `true` (Whitespace will be removed.) + + + + + +The deserialized Slate value. + + + ## Slate -> React -> HTML ### Installation diff --git a/apps/www/src/registry/default/example/basic-editor-handler-demo.tsx b/apps/www/src/registry/default/example/basic-editor-handler-demo.tsx index 1d86039ece..40bf046bbe 100644 --- a/apps/www/src/registry/default/example/basic-editor-handler-demo.tsx +++ b/apps/www/src/registry/default/example/basic-editor-handler-demo.tsx @@ -26,14 +26,20 @@ const value = [ export default function BasicEditorHandlerDemo() { const [debugValue, setDebugValue] = useState(value); - const editor = usePlateEditor({ value }); + + const localValue = + typeof window !== 'undefined' && localStorage.getItem('editorContent'); + + const editor = usePlateEditor({ + value: localValue ? JSON.parse(localValue) : value, + }); return ( { + localStorage.setItem('editorContent', JSON.stringify(value)); setDebugValue(value); - // save newValue... }} > diff --git a/packages/core/src/lib/editor/withSlate.spec.ts b/packages/core/src/lib/editor/withSlate.spec.ts index 78dd013548..abdccf2985 100644 --- a/packages/core/src/lib/editor/withSlate.spec.ts +++ b/packages/core/src/lib/editor/withSlate.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable jest/no-conditional-expect */ +import { BoldPlugin } from '@udecode/plate-basic-marks'; import { type Value, createTEditor, @@ -227,7 +228,6 @@ describe('withPlate', () => { const pluginKeys = editor.pluginList.map((plugin) => plugin.key); const pluginTypes = editor.pluginList.map((plugin) => plugin.node.type); - const slateNextPlugin = editor.getPlugin({ key: SlateNextPlugin.key }); // Check if ReactPlugin replaced DOMPlugin expect(pluginKeys).toContain(ReactPlugin.key); @@ -445,4 +445,23 @@ describe('withPlate', () => { }, ]); }); + + describe('when value is a string', () => { + it('should deserialize HTML string into Slate value', () => { + const htmlString = '

Hello, world!

'; + + const editor = withSlate(createTEditor(), { + id: '1', + plugins: [BoldPlugin], + value: htmlString, + }); + + expect(editor.children).toEqual([ + { + children: [{ text: 'Hello, ' }, { bold: true, text: 'world!' }], + type: 'p', + }, + ]); + }); + }); }); diff --git a/packages/core/src/lib/editor/withSlate.ts b/packages/core/src/lib/editor/withSlate.ts index 73ab3ec7fc..3873a52bbd 100644 --- a/packages/core/src/lib/editor/withSlate.ts +++ b/packages/core/src/lib/editor/withSlate.ts @@ -52,7 +52,7 @@ export type BaseWithSlateOptions< */ shouldNormalizeEditor?: boolean; - value?: V; + value?: V | string; }; export type WithSlateOptions< @@ -190,7 +190,9 @@ export const withSlate = < resolvePlugins(editor, [rootPluginInstance]); - if (value) { + if (typeof value === 'string') { + editor.children = editor.api.html.deserialize({ element: value }) as Value; + } else if (value) { editor.children = value; } if (editor.children?.length === 0) {