Skip to content

Commit

Permalink
Merge pull request #3495 from udecode/feat/value-string
Browse files Browse the repository at this point in the history
value: string | Value
  • Loading branch information
zbeyens authored Sep 2, 2024
2 parents f1a2469 + a92201c commit 871590f
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/wild-garlics-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@udecode/plate-core': patch
---

Add string value support for `createSlateEditor`, `createPlateEditor`, `usePlateEditor`
17 changes: 14 additions & 3 deletions apps/www/content/docs/editor.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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: '<p>This is <b>bold</b> and <i>italic</i> text!</p>',
});
```

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:
Expand Down Expand Up @@ -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<Value, typeof TablePlugin | typeof LinkPlugin>({
const editor = createPlateEditor<Value, typeof TablePlugin | typeof LinkPlugin>({
plugins: [TablePlugin, LinkPlugin],
});

Expand Down Expand Up @@ -238,7 +249,7 @@ const editorInferred = createPlateEditor({
});

// or
const editorExplicit = createTPlateEditor<MyValue, typeof TablePlugin | typeof LinkPlugin>({
const editorExplicit = createPlateEditor<MyValue, typeof TablePlugin | typeof LinkPlugin>({
plugins: [TablePlugin, LinkPlugin],
value,
});
Expand Down
45 changes: 38 additions & 7 deletions apps/www/content/docs/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Plate editor={editor}>
<Plate
editor={editor}
onChange={({ value }) => {
localStorage.setItem('editorContent', JSON.stringify(value));
}}
>
<PlateContent />
</Plate>
);
Expand Down Expand Up @@ -230,6 +235,32 @@ export default function BasicEditor() {

<ComponentPreview name="basic-plugins-components-demo" padding="md" />

### 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 = '<p>This is <b>bold</b> and <i>italic</i> text!</p>';

export default function BasicEditor() {
const editor = usePlateEditor({
value: htmlValue,
plugins: [
BoldPlugin,
ItalicPlugin,
],
});

return (
<Plate editor={editor}>
<PlateContent />
</Plate>
);
}
```

### That's it!

You can now play around with the <Link href="/?builder=true">Playground</Link> and start building your own editor.
Expand Down
43 changes: 42 additions & 1 deletion apps/www/content/docs/html.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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('<p>Hello, world!</p>')
```

### 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**: `<strong>`, `<b>`, or `style="font-weight: 600|700|bold"`
Expand Down Expand Up @@ -168,6 +183,32 @@ export const IndentListPlugin = createTSlatePlugin<IndentListConfig>({
});
```

### API

#### editor.api.html.deserialize

Deserialize HTML string into Slate value.

<APIParameters>
<APISubListItem parent="options" name="element" type="HTMLElement | string">

The HTML element or string to deserialize.

</APISubListItem>
<APISubListItem parent="options" name="collapseWhiteSpace" type="boolean" optional>

Flag to enable or disable the removal of whitespace from the serialized HTML.

- **Default:** `true` (Whitespace will be removed.)
</APISubListItem>
</APIParameters>
<APIReturns>
<APIItem type="TDescendant[]">

The deserialized Slate value.
</APIItem>
</APIReturns>

## Slate -> React -> HTML

### Installation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ const value = [

export default function BasicEditorHandlerDemo() {
const [debugValue, setDebugValue] = useState<Value>(value);
const editor = usePlateEditor({ value });

const localValue =
typeof window !== 'undefined' && localStorage.getItem('editorContent');

const editor = usePlateEditor({
value: localValue ? JSON.parse(localValue) : value,
});

return (
<Plate
editor={editor}
onChange={({ value }) => {
localStorage.setItem('editorContent', JSON.stringify(value));
setDebugValue(value);
// save newValue...
}}
>
<Editor {...editableProps} />
Expand Down
21 changes: 20 additions & 1 deletion packages/core/src/lib/editor/withSlate.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable jest/no-conditional-expect */
import { BoldPlugin } from '@udecode/plate-basic-marks';
import {
type Value,
createTEditor,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -445,4 +445,23 @@ describe('withPlate', () => {
},
]);
});

describe('when value is a string', () => {
it('should deserialize HTML string into Slate value', () => {
const htmlString = '<p>Hello, <b>world!</b></p>';

const editor = withSlate(createTEditor(), {
id: '1',
plugins: [BoldPlugin],
value: htmlString,
});

expect(editor.children).toEqual([
{
children: [{ text: 'Hello, ' }, { bold: true, text: 'world!' }],
type: 'p',
},
]);
});
});
});
6 changes: 4 additions & 2 deletions packages/core/src/lib/editor/withSlate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export type BaseWithSlateOptions<
*/
shouldNormalizeEditor?: boolean;

value?: V;
value?: V | string;
};

export type WithSlateOptions<
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 871590f

Please sign in to comment.