Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

value: string | Value #3495

Merged
merged 2 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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