@use-kona/editor 0.1.2-rc.3 → 0.1.2-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@use-kona/editor",
3
- "version": "0.1.2-rc.3",
3
+ "version": "0.1.2-rc.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
@@ -35,6 +35,7 @@
35
35
  "@storybook/test": "^9.0.0-alpha.2",
36
36
  "@testing-library/jest-dom": "^6.6.3",
37
37
  "@testing-library/react": "^16.3.0",
38
+ "@types/escape-html": "^1.0.4",
38
39
  "@types/is-url": "^1.2.32",
39
40
  "@types/react": "^19.1.8",
40
41
  "@types/react-dom": "18",
@@ -57,15 +58,15 @@
57
58
  },
58
59
  "dependencies": {
59
60
  "@nanostores/react": "^1.0.0",
61
+ "clsx": "^2.1.1",
60
62
  "escape-html": "^1.0.3",
61
63
  "is-hotkey": "^0.2.0",
64
+ "is-url": "^1.2.4",
62
65
  "nanostores": "^1.0.1",
63
66
  "prismjs": "^1.30.0",
64
67
  "slate": "^0.117.2",
65
68
  "slate-history": "^0.113.1",
66
69
  "slate-hyperscript": "^0.100.0",
67
- "slate-react": "^0.117.3",
68
- "clsx": "^2.1.1",
69
- "is-url": "^1.2.4"
70
+ "slate-react": "^0.117.3"
70
71
  }
71
72
  }
@@ -5,11 +5,14 @@ import type { IPlugin } from '../types';
5
5
 
6
6
  export const serialize =
7
7
  (plugins: IPlugin[]) =>
8
- (
9
- node: CustomElement | CustomElement[] | CustomText | CustomText[],
10
- ): string => {
8
+ (node: CustomElement | CustomText): string => {
11
9
  const serializers = plugins
12
10
  .flatMap((plugin) => plugin.blocks?.map((element) => element.serialize))
11
+ .concat(
12
+ plugins.flatMap((plugin) =>
13
+ plugin.leafs?.map((element) => element.serialize),
14
+ ),
15
+ )
13
16
  .filter(Boolean);
14
17
 
15
18
  if (Array.isArray(node)) {
@@ -21,11 +24,11 @@ export const serialize =
21
24
  return current?.(node) || prev;
22
25
  }, escapeHtml(node.text));
23
26
  } else {
24
- const children: string = node.children
27
+ const children: string = node?.children
25
28
  ?.map((n) => serialize(plugins)(n))
26
29
  .join('');
27
30
 
28
- if (node.type === 'paragraph') {
31
+ if (node?.type === 'paragraph') {
29
32
  return `<p>${children}</p>`;
30
33
  }
31
34
 
@@ -1,9 +1,9 @@
1
1
  .root {
2
2
  display: flex;
3
- justify-content: space-between;
4
- column-gap: 8px;
3
+ flex-direction: column;
4
+ background-color: var(--kona-editor-alt-background-color);
5
+ border-radius: 8px;
5
6
  padding: 4px;
6
- border-bottom: 1px solid var(--kona-editor-border-color);
7
7
  }
8
8
 
9
9
  .button {
@@ -24,6 +24,19 @@
24
24
  }
25
25
  }
26
26
 
27
+ .menu {
28
+ display: flex;
29
+ justify-content: space-between;
30
+ column-gap: 4px;
31
+ padding: 4px 0;
32
+ }
33
+
34
+ .content {
35
+ background-color: var(--kona-editor-background-color);
36
+ border-radius: 6px;
37
+ padding: 8px 4px;
38
+ }
39
+
27
40
  .customMenu {
28
41
  max-height: 250px;
29
42
  width: 200px;
@@ -1,21 +1,13 @@
1
- import { forwardRef, useMemo } from 'react';
1
+ import { forwardRef, type ReactNode, useMemo } from 'react';
2
2
  import { Node } from 'slate';
3
3
  import type { CustomElement } from '../../types';
4
+ import styles from './CodeBlock.module.css';
4
5
  import { CheckIcon } from './icons/check';
5
6
  import { CopyIcon } from './icons/copy';
6
- import styles from './LanguageSelector.module.css';
7
7
  import { Button } from './ui/Button';
8
8
  import { Dropdown } from './ui/Dropdown';
9
9
  import { Menu as MenuBase, type MenuConfig } from './ui/Menu';
10
10
 
11
- type Props = {
12
- value: string;
13
- onChange: (value: string) => void;
14
- params: {
15
- element: CustomElement;
16
- };
17
- };
18
-
19
11
  const languages = [
20
12
  { value: 'javascript', label: 'JavaScript' },
21
13
  { value: 'typescript', label: 'TypeScript' },
@@ -40,11 +32,24 @@ const languages = [
40
32
  { value: 'plaintext', label: 'Plain Text' },
41
33
  ];
42
34
 
43
- export const LanguageSelector = (props: Props) => {
44
- const { value: language, onChange, params } = props;
35
+ type Props = {
36
+ value: string;
37
+ onChange: (value: string) => void;
38
+ params: {
39
+ element: CustomElement;
40
+ Content: () => ReactNode;
41
+ };
42
+ };
43
+
44
+ export const CodeBlock = (props: Props) => {
45
+ const {
46
+ value: language,
47
+ onChange,
48
+ params: { element, Content },
49
+ } = props;
45
50
 
46
51
  const handleCopyClick = () => {
47
- const text = Array.from(Node.texts(params.element))
52
+ const text = Array.from(Node.texts(element))
48
53
  .map((nodeEntry) => nodeEntry[0].text)
49
54
  .join('\n');
50
55
 
@@ -72,28 +77,33 @@ export const LanguageSelector = (props: Props) => {
72
77
  );
73
78
  return (
74
79
  <div className={styles.root}>
75
- <Dropdown
76
- config={menuConfig}
77
- Menu={forwardRef<HTMLDivElement, { className: string }>(
78
- (props, ref) => (
79
- <div
80
- {...props}
81
- ref={ref}
82
- className={[styles.customMenu, props.className].join(' ')}
83
- />
84
- ),
85
- )}
86
- >
87
- {({ ref, onClick }) => (
88
- <Button ref={ref} size="sm" onClick={onClick}>
89
- {languages.find((l) => l.value === language)?.label ||
90
- 'Select language'}
91
- </Button>
92
- )}
93
- </Dropdown>
94
- <Button size="sm" type="button" onClick={handleCopyClick}>
95
- <CopyIcon size={16} />
96
- </Button>
80
+ <div className={styles.menu}>
81
+ <Dropdown
82
+ config={menuConfig}
83
+ Menu={forwardRef<HTMLDivElement, { className: string }>(
84
+ (props, ref) => (
85
+ <div
86
+ {...props}
87
+ ref={ref}
88
+ className={[styles.customMenu, props.className].join(' ')}
89
+ />
90
+ ),
91
+ )}
92
+ >
93
+ {({ ref, onClick }) => (
94
+ <Button ref={ref} size="sm" onClick={onClick}>
95
+ {languages.find((l) => l.value === language)?.label ||
96
+ 'Select language'}
97
+ </Button>
98
+ )}
99
+ </Dropdown>
100
+ <Button size="sm" type="button" onClick={handleCopyClick}>
101
+ <CopyIcon size={16} />
102
+ </Button>
103
+ </div>
104
+ <div className={styles.content}>
105
+ <Content />
106
+ </div>
97
107
  </div>
98
108
  );
99
109
  };
@@ -1,9 +1,16 @@
1
- import { useEffect, useRef, useState } from 'react';
1
+ import {
2
+ forwardRef,
3
+ useEffect,
4
+ useImperativeHandle,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
2
8
  import { DndProvider } from 'react-dnd';
3
9
  import { HTML5Backend } from 'react-dnd-html5-backend';
4
10
  import type { Descendant } from 'slate';
5
11
  import type { CustomElement } from '../../types';
6
12
  import { deserialize } from '../core/deserialize';
13
+ import { serialize } from '../core/serialize';
7
14
  import { KonaEditor } from '../editor';
8
15
  import type { EditorRef } from '../types';
9
16
  import styles from './Editor.module.css';
@@ -18,21 +25,29 @@ type Props = {
18
25
  onChange?: (value: Descendant[]) => void;
19
26
  };
20
27
 
21
- export const ExampleEditor = (props: Props) => {
22
- const { initialValueType = 'kona-editor' } = props;
28
+ export const ExampleEditor = forwardRef((props: Props, ref) => {
29
+ const { value: defaultValue = text, initialValueType = 'kona-editor' } =
30
+ props;
23
31
  const [plugins] = useState(getPlugins());
24
32
  const [value, setValue] = useState<Descendant[] | null>(null);
25
33
 
26
- const ref = useRef<EditorRef>(null);
34
+ const editorRef = useRef<EditorRef>(null);
35
+
36
+ useImperativeHandle(
37
+ ref,
38
+ () => ({
39
+ serialize: serialize(plugins),
40
+ }),
41
+ [plugins],
42
+ );
27
43
 
28
44
  // biome-ignore lint/correctness/useExhaustiveDependencies: only on init
29
45
  useEffect(() => {
30
46
  if (initialValueType === 'kona-editor') {
31
- setValue(props.value);
47
+ setValue(defaultValue);
32
48
  } else {
33
- const parsed = deserialize(plugins)(props.value);
49
+ const parsed = deserialize(plugins)(defaultValue);
34
50
  parsed && setValue(parsed as Descendant[]);
35
- console.log(parsed);
36
51
  }
37
52
  }, []);
38
53
 
@@ -41,7 +56,7 @@ export const ExampleEditor = (props: Props) => {
41
56
  <div className={[styles.root].join(' ')}>
42
57
  {value && (
43
58
  <KonaEditor
44
- ref={ref}
59
+ ref={editorRef}
45
60
  initialValue={value || (initialValue as CustomElement[])}
46
61
  plugins={plugins}
47
62
  onChange={props.onChange || console.log}
@@ -50,4 +65,4 @@ export const ExampleEditor = (props: Props) => {
50
65
  </div>
51
66
  </DndProvider>
52
67
  );
53
- };
68
+ });
@@ -19,12 +19,12 @@ import {
19
19
  } from '../plugins';
20
20
  import type { CodeElement } from '../plugins/CodeBlockPlugin/types';
21
21
  import { Backdrop } from './Backdrop';
22
+ import { CodeBlock } from './CodeBlock';
22
23
  import { colors } from './colors';
23
24
  import { DragBlock } from './DragBlock';
24
25
  import { FloatingMenu } from './FloatingMenu';
25
26
  import { getCommands } from './getCommands';
26
27
  import { getShortcuts } from './getShortcuts';
27
- import { LanguageSelector } from './LanguageSelector';
28
28
  import { LinksHint } from './LinksHint';
29
29
  import { Menu } from './Menu';
30
30
  import { $store } from './store';
@@ -126,9 +126,9 @@ export const getPlugins = () => {
126
126
  }),
127
127
  new ListsPlugin({}),
128
128
  new CodeBlockPlugin({
129
- renderLanguageSelector: (value, onChange, params) => {
129
+ renderCodeBlock: (value, onChange, params) => {
130
130
  return (
131
- <LanguageSelector
131
+ <CodeBlock
132
132
  value={value}
133
133
  onChange={onChange}
134
134
  params={{
@@ -40,7 +40,7 @@ export const text = (
40
40
  Kona Editor
41
41
  </htext>{' '}
42
42
  is a text editor based on Slate.js that I use in{' '}
43
- <hlink url="https://kona.to">Kona application</hlink> for notes and event
43
+ <hlink url="https://kona.to">Kona calendar</hlink> for notes and event
44
44
  descriptions. I decided to open-source the editor for a few reasons:
45
45
  </paragraph>
46
46
  <numberedList>
@@ -1,4 +1,5 @@
1
- import { Editor } from 'slate';
1
+ import escapeHtml from 'escape-html';
2
+ import { Editor, Text } from 'slate';
2
3
  import { jsx } from 'slate-hyperscript';
3
4
  import type { CustomElement, CustomText } from '../../../types';
4
5
  import type { IPlugin } from '../../types';
@@ -64,6 +65,26 @@ export class BasicFormattingPlugin
64
65
 
65
66
  return <span {...attributes}>{content}</span>;
66
67
  },
68
+ serialize: (node: CustomElement | CustomLeaf) => {
69
+ if (Text.isText(node)) {
70
+ let text = escapeHtml(node.text);
71
+
72
+ if (node.bold) {
73
+ text = `<strong>${text}</strong>`;
74
+ }
75
+ if (node.italic) {
76
+ text = `<em>${text}</em>`;
77
+ }
78
+ if (node.underline) {
79
+ text = `<u>${text}</u>`;
80
+ }
81
+ if (node.strikethrough) {
82
+ text = `<s>${text}</s>`;
83
+ }
84
+
85
+ return text;
86
+ }
87
+ },
67
88
  deserialize: (element: HTMLElement, children) => {
68
89
  const { nodeName } = element;
69
90
 
@@ -1,19 +1,14 @@
1
- import type { ReactNode } from 'react';
2
1
  import type { RenderElementProps } from 'slate-react';
3
2
  import styles from './styles.module.css';
4
3
  import type { CodeElement } from './types';
5
4
 
6
5
  type Props = RenderElementProps & {
7
6
  element: CodeElement;
8
- renderLanguageSelector: (element: CodeElement) => ReactNode;
9
7
  };
10
8
 
11
9
  export const CodeBlock = (props: Props) => {
12
10
  return (
13
11
  <div {...props.attributes} className={styles.root} spellCheck={false}>
14
- <div contentEditable={false}>
15
- {props.renderLanguageSelector(props.element)}
16
- </div>
17
12
  <div className={styles.content}>
18
13
  <div className={styles.code}>{props.children}</div>
19
14
  </div>
@@ -1,5 +1,5 @@
1
1
  import Prism from 'prismjs';
2
- import type { KeyboardEvent } from 'react';
2
+ import type { KeyboardEvent, ReactNode } from 'react';
3
3
  import {
4
4
  type DecoratedRange,
5
5
  Editor,
@@ -44,10 +44,11 @@ import 'prismjs/components/prism-yaml';
44
44
  import 'prismjs/components/prism-markdown';
45
45
 
46
46
  type Options = {
47
- renderLanguageSelector: (
48
- value: string,
49
- onChange: (value: string) => void,
47
+ renderCodeBlock: (
48
+ language: string,
49
+ onChange: (language: string) => void,
50
50
  params: {
51
+ Content: () => ReactNode;
51
52
  element: CodeElement;
52
53
  },
53
54
  ) => React.ReactNode;
@@ -189,25 +190,25 @@ export class CodeBlockPlugin implements IPlugin {
189
190
  {
190
191
  type: CodeBlockPlugin.CODE_ELEMENT,
191
192
  render: (props: RenderElementProps, editor: Editor) => {
193
+ const { language } = props.element as CodeElement;
192
194
  const onChange = (language: string) => {
193
195
  const path = ReactEditor.findPath(editor, props.element);
194
196
  Transforms.setNodes<CodeElement>(editor, { language }, { at: path });
195
197
  };
196
198
 
199
+ const Content = (): ReactNode => {
200
+ return (
201
+ <CodeBlock {...props} element={props.element as CodeElement} />
202
+ );
203
+ };
204
+
197
205
  return (
198
- <CodeBlock
199
- {...props}
200
- element={props.element as CodeElement}
201
- renderLanguageSelector={(element) =>
202
- this.options.renderLanguageSelector(
203
- (props.element as CodeElement).language,
204
- onChange,
205
- {
206
- element: element as CodeElement,
207
- },
208
- )
209
- }
210
- />
206
+ <>
207
+ {this.options.renderCodeBlock(language, onChange, {
208
+ element: props.element as CodeElement,
209
+ Content,
210
+ })}
211
+ </>
211
212
  );
212
213
  },
213
214
  },
@@ -1,6 +1,4 @@
1
1
  .root {
2
- border: 1px solid var(--kona-editor-border-color, #eee);
3
- border-radius: 4px;
4
2
  overflow: hidden;
5
3
  font-family: monospace;
6
4
  display: flex;
@@ -9,7 +7,6 @@
9
7
 
10
8
  .content {
11
9
  display: flex;
12
- background-color: var(--kona-editor-background-color, #fff);
13
10
  }
14
11
 
15
12
  .line {
@@ -111,7 +111,6 @@ export const Menu = (props: Props) => {
111
111
  case 'Escape': {
112
112
  event.stopPropagation();
113
113
  $store.setKey('isOpen', false);
114
- close();
115
114
  break;
116
115
  }
117
116
  }
@@ -166,7 +165,14 @@ export const Menu = (props: Props) => {
166
165
  return createPortal(
167
166
  renderMenu(
168
167
  <>
169
- {store.isOpen && <div className={styles.backdrop} onClick={close} />}
168
+ {store.isOpen && (
169
+ <div
170
+ className={styles.backdrop}
171
+ onClick={() => {
172
+ $store.setKey('isOpen', false);
173
+ }}
174
+ />
175
+ )}
170
176
  <div
171
177
  ref={handleMenuLayout}
172
178
  style={style}
@@ -1,22 +1,15 @@
1
- :root {
2
- --menu-background-color: #fff;
3
- --menu-background-color-hover: #f9f9f9;
4
- --menu-text-color: #444;
5
- --menu-border-color: #ddd;
6
- }
7
-
8
1
  .menu {
9
2
  position: absolute;
10
- color: var(--menu-text-color, #444);
3
+ color: var(--kona-editor-text-color);
11
4
  z-index: 31;
12
5
  top: -100000px;
13
6
  left: -100000px;
14
7
  opacity: 0;
15
8
  transform: scale(0.9);
16
9
  margin-top: -6px;
17
- background-color: var(--menu-background-color, #fff);
10
+ background-color: var(--kona-editor-background-color, #fff);
18
11
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.025);
19
- border: 1px solid var(--menu-border-color, #ddd);
12
+ border: 1px solid var(--kona-editor-border-color, #ddd);
20
13
  border-radius: 4px;
21
14
  transition: transform 0.25s;
22
15
  display: flex;
@@ -24,6 +17,19 @@
24
17
  max-height: 200px;
25
18
  overflow-y: auto;
26
19
  font-size: 12px;
20
+
21
+ &::-webkit-scrollbar {
22
+ width: 6px;
23
+ }
24
+
25
+ &::-webkit-scrollbar-track {
26
+ background: transparent;
27
+ }
28
+
29
+ &::-webkit-scrollbar-thumb {
30
+ background-color: rgba(0, 0, 0, 0.25);
31
+ border-radius: 10px;
32
+ }
27
33
  }
28
34
 
29
35
  .button {
@@ -36,15 +42,15 @@
36
42
  height: 40px;
37
43
  box-sizing: border-box;
38
44
  cursor: pointer;
39
- color: var(--menu-text-color, #444);
45
+ color: var(--kona-editor-text-color, #444);
40
46
  }
41
47
 
42
48
  .button:hover {
43
- background-color: var(--menu-background-color-hover, #f9f9f9);
49
+ background-color: var(--kona-editor-alt-background-color, #f9f9f9);
44
50
  }
45
51
 
46
52
  .active {
47
- background-color: var(--menu-background-color-hover, #f9f9f9);
53
+ background-color: var(--kona-editor-alt-background-color, #f9f9f9);
48
54
  }
49
55
 
50
56
  .icon {
@@ -53,8 +59,8 @@
53
59
  opacity: 0.5;
54
60
  padding: 2px;
55
61
  font-size: 12px;
56
- background: var(--menu-background-color-hover, #f9f9f9);
57
- color: var(--menu-text-color, #444);
62
+ background: var(--kona-editor-alt-background-color, #f9f9f9);
63
+ color: var(--kona-editor-text-color, #444);
58
64
  border-radius: 4px;
59
65
  display: inline-flex;
60
66
  align-items: center;
@@ -1,4 +1,4 @@
1
- import { Editor, Element, Transforms } from 'slate';
1
+ import { Descendant, Editor, Element, Transforms } from 'slate';
2
2
  import { jsx } from 'slate-hyperscript';
3
3
  import type { RenderElementProps } from 'slate-react';
4
4
  import type { IPlugin } from '../../types';
@@ -25,6 +25,14 @@ export class HeadingsPlugin implements IPlugin {
25
25
  );
26
26
  }
27
27
  },
28
+ serialize: (node: Descendant, children) => {
29
+ if (
30
+ Element.isElement(node) &&
31
+ node.type === HeadingsPlugin.HeadingLevel1
32
+ ) {
33
+ return `<h1>${children}</h1>`;
34
+ }
35
+ },
28
36
  },
29
37
  {
30
38
  type: HeadingsPlugin.HeadingLevel2,
@@ -42,6 +50,14 @@ export class HeadingsPlugin implements IPlugin {
42
50
  );
43
51
  }
44
52
  },
53
+ serialize: (node: Descendant, children) => {
54
+ if (
55
+ Element.isElement(node) &&
56
+ node.type === HeadingsPlugin.HeadingLevel2
57
+ ) {
58
+ return `<h2>${children}</h2>`;
59
+ }
60
+ },
45
61
  },
46
62
  {
47
63
  type: HeadingsPlugin.HeadingLevel3,
@@ -59,6 +75,14 @@ export class HeadingsPlugin implements IPlugin {
59
75
  );
60
76
  }
61
77
  },
78
+ serialize: (node: Descendant, children) => {
79
+ if (
80
+ Element.isElement(node) &&
81
+ node.type === HeadingsPlugin.HeadingLevel3
82
+ ) {
83
+ return `<h3>${children}</h3>`;
84
+ }
85
+ },
62
86
  },
63
87
  ];
64
88
 
@@ -56,6 +56,14 @@ export class LinksPlugin implements IPlugin {
56
56
  />
57
57
  );
58
58
  },
59
+ serialize: (element, children) => {
60
+ if (
61
+ Element.isElement(element) &&
62
+ element.type === LinksPlugin.LINK_TYPE
63
+ ) {
64
+ return `<a href="${(element as LinkElement).url}">${children}</a>`;
65
+ }
66
+ },
59
67
  deserialize: (element: HTMLElement, children) => {
60
68
  if (element.tagName === 'A') {
61
69
  const url = element.getAttribute('href') || '';
@@ -134,6 +134,11 @@ export class ListsPlugin implements IPlugin {
134
134
  </ul>
135
135
  );
136
136
  },
137
+ serialize: (element, children) => {
138
+ if (element.type === ListsPlugin.BULLETED_LIST_ELEMENT) {
139
+ return `<ul>${children}</ul>`;
140
+ }
141
+ },
137
142
  deserialize: (element: HTMLElement, children) => {
138
143
  const { nodeName } = element;
139
144
  if (nodeName === 'UL') {
@@ -154,6 +159,11 @@ export class ListsPlugin implements IPlugin {
154
159
  </ol>
155
160
  );
156
161
  },
162
+ serialize: (element, children) => {
163
+ if (element.type === ListsPlugin.NUMBERED_LIST_ELEMENT) {
164
+ return `<ol>${children}</ol>`;
165
+ }
166
+ },
157
167
  deserialize: (element: HTMLElement, children) => {
158
168
  const { nodeName } = element;
159
169
  if (nodeName === 'OL') {
@@ -174,6 +184,11 @@ export class ListsPlugin implements IPlugin {
174
184
  </li>
175
185
  );
176
186
  },
187
+ serialize: (element, children) => {
188
+ if (element.type === ListsPlugin.BULLETED_LIST_ELEMENT) {
189
+ return `<li>${children}</li>`;
190
+ }
191
+ },
177
192
  deserialize: (element: HTMLElement, children) => {
178
193
  const { nodeName } = element;
179
194
  if (nodeName === 'LI') {
package/src/types.ts CHANGED
@@ -1,11 +1,5 @@
1
1
  import type { KeyboardEvent, ReactElement, ReactNode } from 'react';
2
- import type {
3
- DecoratedRange,
4
- Descendant,
5
- Editor,
6
- Node,
7
- NodeEntry,
8
- } from 'slate';
2
+ import type { DecoratedRange, Descendant, Editor, NodeEntry } from 'slate';
9
3
  import type { RenderElementProps, RenderLeafProps } from 'slate-react';
10
4
  import type { CustomElement, CustomText } from '../types';
11
5
 
@@ -60,6 +54,7 @@ export type Leaf<T extends Editor, TLeaf extends CustomText = CustomText> = {
60
54
  editor: T,
61
55
  ) => ReactElement | null;
62
56
  isVoid?: boolean;
57
+ serialize?: Serialize;
63
58
  deserialize?: Deserialize;
64
59
  };
65
60
 
@@ -72,15 +67,16 @@ export type UiParams = {
72
67
  };
73
68
 
74
69
  export type EditorRef = {
75
- serialize: (
76
- node: CustomElement | CustomElement[] | CustomText | CustomText[],
77
- ) => string;
70
+ serialize: (node: CustomElement | CustomText) => string;
78
71
  deserialize: (
79
72
  element: HTMLElement,
80
73
  ) => (Descendant | string)[] | string | Descendant | null;
81
74
  };
82
75
 
83
- export type Serialize = (node: Node, children?: string) => string | undefined;
76
+ export type Serialize = (
77
+ node: CustomElement | CustomText,
78
+ children?: string,
79
+ ) => string | undefined;
84
80
 
85
81
  export type Deserialize = (
86
82
  element: HTMLElement,