@use-kona/editor 0.1.1 → 0.1.2-rc.1
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/dist/core/deserialize.js +9 -2
- package/dist/examples/Editor.d.ts +8 -1
- package/dist/examples/Editor.js +22 -5
- package/dist/examples/Editor_module.css +0 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -1
- package/dist/plugins/BasicFormattingPlugin/BasicFormattingPlugin.js +29 -0
- package/dist/plugins/HeadingsPlugin/HeadingsPlugin.d.ts +3 -2
- package/dist/plugins/HeadingsPlugin/HeadingsPlugin.js +22 -3
- package/dist/plugins/LinksPlugin/LinksPlugin.d.ts +1 -0
- package/dist/plugins/LinksPlugin/LinksPlugin.js +11 -1
- package/dist/plugins/ListsPlugin/ListsPlugin.d.ts +2 -0
- package/dist/plugins/ListsPlugin/ListsPlugin.js +22 -3
- package/dist/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/core/deserialize.ts +26 -5
- package/src/examples/Editor.module.css +0 -1
- package/src/examples/Editor.tsx +36 -6
- package/src/index.ts +4 -0
- package/src/plugins/BasicFormattingPlugin/BasicFormattingPlugin.tsx +31 -0
- package/src/plugins/HeadingsPlugin/HeadingsPlugin.tsx +36 -2
- package/src/plugins/LinksPlugin/LinksPlugin.tsx +15 -0
- package/src/plugins/ListsPlugin/ListsPlugin.tsx +31 -0
- package/src/types.ts +2 -1
package/dist/core/deserialize.js
CHANGED
|
@@ -21,13 +21,20 @@ const deserialize = (plugins)=>(element)=>{
|
|
|
21
21
|
for (const plugin of plugins){
|
|
22
22
|
if (plugin.blocks?.some((b)=>b.deserialize)) plugin.blocks.forEach((e)=>{
|
|
23
23
|
if (e.deserialize) {
|
|
24
|
-
const childrenAsDescendants = children;
|
|
24
|
+
const childrenAsDescendants = result || children;
|
|
25
|
+
const newResult = e.deserialize(element, childrenAsDescendants);
|
|
26
|
+
if (newResult) result = newResult;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (plugin.leafs?.some((b)=>b.deserialize)) plugin.leafs.forEach((e)=>{
|
|
30
|
+
if (e.deserialize) {
|
|
31
|
+
const childrenAsDescendants = result || children;
|
|
25
32
|
const newResult = e.deserialize(element, childrenAsDescendants);
|
|
26
33
|
if (newResult) result = newResult;
|
|
27
34
|
}
|
|
28
35
|
});
|
|
29
|
-
if (result) return result;
|
|
30
36
|
}
|
|
37
|
+
if (result) return result;
|
|
31
38
|
return children.filter((child)=>null !== child);
|
|
32
39
|
};
|
|
33
40
|
export { deserialize };
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Descendant } from 'slate';
|
|
2
|
+
type Props = {
|
|
3
|
+
initialValueType?: 'kona-editor' | 'html';
|
|
4
|
+
value?: any;
|
|
5
|
+
onChange?: (value: Descendant[]) => void;
|
|
6
|
+
};
|
|
7
|
+
export declare const ExampleEditor: (props: Props) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
package/dist/examples/Editor.js
CHANGED
|
@@ -1,22 +1,39 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
3
|
import { DndProvider } from "react-dnd";
|
|
3
4
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
|
5
|
+
import { deserialize } from "../core/deserialize.js";
|
|
4
6
|
import { KonaEditor } from "../editor.js";
|
|
5
7
|
import Editor_module from "./Editor.module.js";
|
|
6
8
|
import { getPlugins } from "./getPlugins.js";
|
|
7
9
|
import { text as external_text_js_text } from "./text.js";
|
|
8
10
|
const initialValue = external_text_js_text;
|
|
9
|
-
const ExampleEditor = ()
|
|
11
|
+
const ExampleEditor = (props)=>{
|
|
12
|
+
const { initialValueType = 'kona-editor' } = props;
|
|
13
|
+
const [plugins] = useState(getPlugins());
|
|
14
|
+
const [value, setValue] = useState(null);
|
|
15
|
+
const ref = useRef(null);
|
|
16
|
+
useEffect(()=>{
|
|
17
|
+
if ('kona-editor' === initialValueType) setValue(props.value);
|
|
18
|
+
else {
|
|
19
|
+
const parsed = deserialize(plugins)(props.value);
|
|
20
|
+
parsed && setValue(parsed);
|
|
21
|
+
console.log(parsed);
|
|
22
|
+
}
|
|
23
|
+
}, []);
|
|
24
|
+
return /*#__PURE__*/ jsx(DndProvider, {
|
|
10
25
|
backend: HTML5Backend,
|
|
11
26
|
children: /*#__PURE__*/ jsx("div", {
|
|
12
27
|
className: [
|
|
13
28
|
Editor_module.root
|
|
14
29
|
].join(' '),
|
|
15
|
-
children: /*#__PURE__*/ jsx(KonaEditor, {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
children: value && /*#__PURE__*/ jsx(KonaEditor, {
|
|
31
|
+
ref: ref,
|
|
32
|
+
initialValue: value || initialValue,
|
|
33
|
+
plugins: plugins,
|
|
34
|
+
onChange: props.onChange || console.log
|
|
19
35
|
})
|
|
20
36
|
})
|
|
21
37
|
});
|
|
38
|
+
};
|
|
22
39
|
export { ExampleEditor };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
export type { CustomElement, CustomText } from '../types';
|
|
2
|
+
export { deserialize } from './core/deserialize';
|
|
3
|
+
export { serialize } from './core/serialize';
|
|
1
4
|
export { defaultValue } from './defaultValue';
|
|
2
5
|
export * from './editor';
|
|
3
6
|
export { ExampleEditor } from './examples/Editor';
|
|
4
7
|
export * from './plugins';
|
|
8
|
+
export type { EditorRef } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { deserialize } from "./core/deserialize.js";
|
|
2
|
+
import { serialize } from "./core/serialize.js";
|
|
1
3
|
import { defaultValue } from "./defaultValue.js";
|
|
2
4
|
import { ExampleEditor } from "./examples/Editor.js";
|
|
3
5
|
export * from "./editor.js";
|
|
4
6
|
export * from "./plugins/index.js";
|
|
5
|
-
export { ExampleEditor, defaultValue };
|
|
7
|
+
export { ExampleEditor, defaultValue, deserialize, serialize };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Editor } from "slate";
|
|
3
|
+
import { jsx as external_slate_hyperscript_jsx } from "slate-hyperscript";
|
|
3
4
|
class BasicFormattingPlugin {
|
|
4
5
|
hotkeys = [
|
|
5
6
|
[
|
|
@@ -48,6 +49,34 @@ class BasicFormattingPlugin {
|
|
|
48
49
|
...attributes,
|
|
49
50
|
children: content
|
|
50
51
|
});
|
|
52
|
+
},
|
|
53
|
+
deserialize: (element, children)=>{
|
|
54
|
+
const { nodeName } = element;
|
|
55
|
+
let attrs = null;
|
|
56
|
+
switch(nodeName){
|
|
57
|
+
case 'EM':
|
|
58
|
+
case 'I':
|
|
59
|
+
attrs = {
|
|
60
|
+
italic: true
|
|
61
|
+
};
|
|
62
|
+
break;
|
|
63
|
+
case 'STRONG':
|
|
64
|
+
attrs = {
|
|
65
|
+
bold: true
|
|
66
|
+
};
|
|
67
|
+
break;
|
|
68
|
+
case 'U':
|
|
69
|
+
attrs = {
|
|
70
|
+
underline: true
|
|
71
|
+
};
|
|
72
|
+
break;
|
|
73
|
+
case 'S':
|
|
74
|
+
attrs = {
|
|
75
|
+
strikethrough: true
|
|
76
|
+
};
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
if (attrs) return children?.map((child)=>external_slate_hyperscript_jsx('text', attrs, child));
|
|
51
80
|
}
|
|
52
81
|
}
|
|
53
82
|
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Editor } from 'slate';
|
|
2
|
-
import { RenderElementProps } from 'slate-react';
|
|
3
|
-
import { IPlugin } from '../../types';
|
|
2
|
+
import type { RenderElementProps } from 'slate-react';
|
|
3
|
+
import type { IPlugin } from '../../types';
|
|
4
4
|
export declare class HeadingsPlugin implements IPlugin {
|
|
5
5
|
static HeadingLevel1: string;
|
|
6
6
|
static HeadingLevel2: string;
|
|
@@ -8,6 +8,7 @@ export declare class HeadingsPlugin implements IPlugin {
|
|
|
8
8
|
blocks: {
|
|
9
9
|
type: string;
|
|
10
10
|
render: (props: RenderElementProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
deserialize: (element: HTMLElement, children: any) => import("../..").CustomElement | undefined;
|
|
11
12
|
}[];
|
|
12
13
|
static isHeading1Active(editor: Editor): boolean;
|
|
13
14
|
static isHeading2Active(editor: Editor): boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Editor, Element, Transforms } from "slate";
|
|
3
|
+
import { jsx as external_slate_hyperscript_jsx } from "slate-hyperscript";
|
|
3
4
|
class HeadingsPlugin {
|
|
4
5
|
static HeadingLevel1 = 'h1';
|
|
5
6
|
static HeadingLevel2 = 'h2';
|
|
@@ -10,21 +11,39 @@ class HeadingsPlugin {
|
|
|
10
11
|
render: (props)=>/*#__PURE__*/ jsx("h1", {
|
|
11
12
|
...props.attributes,
|
|
12
13
|
children: props.children
|
|
13
|
-
})
|
|
14
|
+
}),
|
|
15
|
+
deserialize: (element, children)=>{
|
|
16
|
+
const { nodeName } = element;
|
|
17
|
+
if ('H1' === nodeName) return external_slate_hyperscript_jsx('element', {
|
|
18
|
+
type: HeadingsPlugin.HeadingLevel1
|
|
19
|
+
}, children);
|
|
20
|
+
}
|
|
14
21
|
},
|
|
15
22
|
{
|
|
16
23
|
type: HeadingsPlugin.HeadingLevel2,
|
|
17
24
|
render: (props)=>/*#__PURE__*/ jsx("h2", {
|
|
18
25
|
...props.attributes,
|
|
19
26
|
children: props.children
|
|
20
|
-
})
|
|
27
|
+
}),
|
|
28
|
+
deserialize: (element, children)=>{
|
|
29
|
+
const { nodeName } = element;
|
|
30
|
+
if ('H2' === nodeName) return external_slate_hyperscript_jsx('element', {
|
|
31
|
+
type: HeadingsPlugin.HeadingLevel2
|
|
32
|
+
}, children);
|
|
33
|
+
}
|
|
21
34
|
},
|
|
22
35
|
{
|
|
23
36
|
type: HeadingsPlugin.HeadingLevel3,
|
|
24
37
|
render: (props)=>/*#__PURE__*/ jsx("h3", {
|
|
25
38
|
...props.attributes,
|
|
26
39
|
children: props.children
|
|
27
|
-
})
|
|
40
|
+
}),
|
|
41
|
+
deserialize: (element, children)=>{
|
|
42
|
+
const { nodeName } = element;
|
|
43
|
+
if ('H3' === nodeName) return external_slate_hyperscript_jsx('element', {
|
|
44
|
+
type: HeadingsPlugin.HeadingLevel3
|
|
45
|
+
}, children);
|
|
46
|
+
}
|
|
28
47
|
}
|
|
29
48
|
];
|
|
30
49
|
static isHeading1Active(editor) {
|
|
@@ -11,6 +11,7 @@ export declare class LinksPlugin implements IPlugin {
|
|
|
11
11
|
isInline: boolean;
|
|
12
12
|
type: string;
|
|
13
13
|
render: (props: RenderElementProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
deserialize: (element: HTMLElement, children: any) => import("../..").CustomElement | undefined;
|
|
14
15
|
}[];
|
|
15
16
|
static addLink: (editor: Editor, url: string) => void;
|
|
16
17
|
static removeLink: (editor: Editor) => void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import is_url from "is-url";
|
|
3
3
|
import { Editor, Element, Range, Transforms } from "slate";
|
|
4
|
+
import { jsx as external_slate_hyperscript_jsx } from "slate-hyperscript";
|
|
4
5
|
import { LINK_ELEMENT } from "./constants.js";
|
|
5
6
|
import { Link } from "./Link.js";
|
|
6
7
|
class LinksPlugin {
|
|
@@ -47,7 +48,16 @@ class LinksPlugin {
|
|
|
47
48
|
...props,
|
|
48
49
|
element: props.element,
|
|
49
50
|
renderHint: this.options.renderHint
|
|
50
|
-
})
|
|
51
|
+
}),
|
|
52
|
+
deserialize: (element, children)=>{
|
|
53
|
+
if ('A' === element.tagName) {
|
|
54
|
+
const url = element.getAttribute('href') || '';
|
|
55
|
+
return external_slate_hyperscript_jsx('element', {
|
|
56
|
+
type: LinksPlugin.LINK_TYPE,
|
|
57
|
+
url
|
|
58
|
+
}, children);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
51
61
|
}
|
|
52
62
|
];
|
|
53
63
|
static addLink = (editor, url)=>{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { KeyboardEvent } from 'react';
|
|
2
2
|
import { Editor } from 'slate';
|
|
3
3
|
import type { RenderElementProps } from 'slate-react';
|
|
4
|
+
import type { CustomElement } from '../../../types';
|
|
4
5
|
import type { IPlugin } from '../../types';
|
|
5
6
|
type Options = {
|
|
6
7
|
listTypes?: string[];
|
|
@@ -16,6 +17,7 @@ export declare class ListsPlugin implements IPlugin {
|
|
|
16
17
|
blocks: {
|
|
17
18
|
type: string;
|
|
18
19
|
render: (props: RenderElementProps) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
deserialize: (element: HTMLElement, children: any) => CustomElement | undefined;
|
|
19
21
|
}[];
|
|
20
22
|
handlers: {
|
|
21
23
|
onKeyDown: (event: KeyboardEvent, editor: Editor) => true | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Editor, Element, Node, Transforms } from "slate";
|
|
3
|
+
import { jsx as external_slate_hyperscript_jsx } from "slate-hyperscript";
|
|
3
4
|
import { getPrev } from "../../core/queries.js";
|
|
4
5
|
import styles_module from "./styles.module.js";
|
|
5
6
|
class ListsPlugin {
|
|
@@ -76,7 +77,13 @@ class ListsPlugin {
|
|
|
76
77
|
className: styles_module.list,
|
|
77
78
|
...props.attributes,
|
|
78
79
|
children: props.children
|
|
79
|
-
})
|
|
80
|
+
}),
|
|
81
|
+
deserialize: (element, children)=>{
|
|
82
|
+
const { nodeName } = element;
|
|
83
|
+
if ('UL' === nodeName) return external_slate_hyperscript_jsx('element', {
|
|
84
|
+
type: ListsPlugin.BULLETED_LIST_ELEMENT
|
|
85
|
+
}, children);
|
|
86
|
+
}
|
|
80
87
|
},
|
|
81
88
|
{
|
|
82
89
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
@@ -84,7 +91,13 @@ class ListsPlugin {
|
|
|
84
91
|
className: styles_module.list,
|
|
85
92
|
...props.attributes,
|
|
86
93
|
children: props.children
|
|
87
|
-
})
|
|
94
|
+
}),
|
|
95
|
+
deserialize: (element, children)=>{
|
|
96
|
+
const { nodeName } = element;
|
|
97
|
+
if ('OL' === nodeName) return external_slate_hyperscript_jsx('element', {
|
|
98
|
+
type: ListsPlugin.NUMBERED_LIST_ELEMENT
|
|
99
|
+
}, children);
|
|
100
|
+
}
|
|
88
101
|
},
|
|
89
102
|
{
|
|
90
103
|
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
@@ -92,7 +105,13 @@ class ListsPlugin {
|
|
|
92
105
|
className: styles_module.listItem,
|
|
93
106
|
...props.attributes,
|
|
94
107
|
children: props.children
|
|
95
|
-
})
|
|
108
|
+
}),
|
|
109
|
+
deserialize: (element, children)=>{
|
|
110
|
+
const { nodeName } = element;
|
|
111
|
+
if ('LI' === nodeName) return external_slate_hyperscript_jsx('element', {
|
|
112
|
+
type: ListsPlugin.LIST_ITEM_ELEMENT
|
|
113
|
+
}, children);
|
|
114
|
+
}
|
|
96
115
|
}
|
|
97
116
|
];
|
|
98
117
|
handlers = {
|
package/dist/types.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export type Leaf<T extends Editor, TLeaf extends CustomText = CustomText> = {
|
|
|
34
34
|
leaf: CustomText & TLeaf;
|
|
35
35
|
}, editor: T) => ReactElement | null;
|
|
36
36
|
isVoid?: boolean;
|
|
37
|
+
deserialize?: Deserialize;
|
|
37
38
|
};
|
|
38
39
|
type Hotkey = readonly [string, (event: KeyboardEvent, editor: Editor) => void];
|
|
39
40
|
export type UiParams = {
|
|
@@ -46,5 +47,5 @@ export type EditorRef = {
|
|
|
46
47
|
deserialize: (element: HTMLElement) => (Descendant | string)[] | string | Descendant | null;
|
|
47
48
|
};
|
|
48
49
|
export type Serialize = (node: Node, children?: string) => string | undefined;
|
|
49
|
-
export type Deserialize = (element: HTMLElement, children?: (string | Descendant)[]) =>
|
|
50
|
+
export type Deserialize = (element: HTMLElement, children?: (string | Descendant)[]) => CustomElement | CustomText[] | undefined;
|
|
50
51
|
export {};
|
package/package.json
CHANGED
package/src/core/deserialize.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Descendant, Element, type Node } from 'slate';
|
|
2
2
|
import { jsx } from 'slate-hyperscript';
|
|
3
|
+
import { CustomElement, CustomText } from '../../types';
|
|
3
4
|
import type { IPlugin } from '../types';
|
|
4
5
|
|
|
5
6
|
export const deserialize =
|
|
@@ -35,13 +36,16 @@ export const deserialize =
|
|
|
35
36
|
return jsx('element', { type: 'paragraph' }, children);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
let result:
|
|
39
|
+
let result: CustomElement | CustomText[] | null = null;
|
|
39
40
|
for (const plugin of plugins) {
|
|
40
41
|
if (plugin.blocks?.some((b) => b.deserialize)) {
|
|
41
42
|
plugin.blocks.forEach((e) => {
|
|
42
43
|
if (e.deserialize) {
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const childrenAsDescendants = (result || children) as (
|
|
45
|
+
| string
|
|
46
|
+
| Descendant
|
|
47
|
+
)[];
|
|
48
|
+
|
|
45
49
|
const newResult = e.deserialize(element, childrenAsDescendants);
|
|
46
50
|
if (newResult) {
|
|
47
51
|
result = newResult;
|
|
@@ -49,9 +53,26 @@ export const deserialize =
|
|
|
49
53
|
}
|
|
50
54
|
});
|
|
51
55
|
}
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
|
|
57
|
+
if (plugin.leafs?.some((b) => b.deserialize)) {
|
|
58
|
+
plugin.leafs.forEach((e) => {
|
|
59
|
+
if (e.deserialize) {
|
|
60
|
+
const childrenAsDescendants = (result || children) as (
|
|
61
|
+
| string
|
|
62
|
+
| Descendant
|
|
63
|
+
)[];
|
|
64
|
+
const newResult = e.deserialize(element, childrenAsDescendants);
|
|
65
|
+
if (newResult) {
|
|
66
|
+
result = newResult;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
54
70
|
}
|
|
55
71
|
}
|
|
72
|
+
|
|
73
|
+
if (result) {
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
56
77
|
return children.filter((child) => child !== null);
|
|
57
78
|
};
|
package/src/examples/Editor.tsx
CHANGED
|
@@ -1,22 +1,52 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
1
2
|
import { DndProvider } from 'react-dnd';
|
|
2
3
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
4
|
+
import type { Descendant } from 'slate';
|
|
3
5
|
import type { CustomElement } from '../../types';
|
|
6
|
+
import { deserialize } from '../core/deserialize';
|
|
4
7
|
import { KonaEditor } from '../editor';
|
|
8
|
+
import type { EditorRef } from '../types';
|
|
5
9
|
import styles from './Editor.module.css';
|
|
6
10
|
import { getPlugins } from './getPlugins';
|
|
7
11
|
import { text } from './text';
|
|
8
12
|
|
|
9
13
|
const initialValue = text;
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
type Props = {
|
|
16
|
+
initialValueType?: 'kona-editor' | 'html';
|
|
17
|
+
value?: any;
|
|
18
|
+
onChange?: (value: Descendant[]) => void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const ExampleEditor = (props: Props) => {
|
|
22
|
+
const { initialValueType = 'kona-editor' } = props;
|
|
23
|
+
const [plugins] = useState(getPlugins());
|
|
24
|
+
const [value, setValue] = useState<Descendant[] | null>(null);
|
|
25
|
+
|
|
26
|
+
const ref = useRef<EditorRef>(null);
|
|
27
|
+
|
|
28
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: only on init
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (initialValueType === 'kona-editor') {
|
|
31
|
+
setValue(props.value);
|
|
32
|
+
} else {
|
|
33
|
+
const parsed = deserialize(plugins)(props.value);
|
|
34
|
+
parsed && setValue(parsed as Descendant[]);
|
|
35
|
+
console.log(parsed);
|
|
36
|
+
}
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
12
39
|
return (
|
|
13
40
|
<DndProvider backend={HTML5Backend}>
|
|
14
41
|
<div className={[styles.root].join(' ')}>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
42
|
+
{value && (
|
|
43
|
+
<KonaEditor
|
|
44
|
+
ref={ref}
|
|
45
|
+
initialValue={value || (initialValue as CustomElement[])}
|
|
46
|
+
plugins={plugins}
|
|
47
|
+
onChange={props.onChange || console.log}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
20
50
|
</div>
|
|
21
51
|
</DndProvider>
|
|
22
52
|
);
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
export type { CustomElement, CustomText } from '../types';
|
|
2
|
+
export { deserialize } from './core/deserialize';
|
|
3
|
+
export { serialize } from './core/serialize';
|
|
1
4
|
export { defaultValue } from './defaultValue';
|
|
2
5
|
export * from './editor';
|
|
3
6
|
export { ExampleEditor } from './examples/Editor';
|
|
4
7
|
export * from './plugins';
|
|
8
|
+
export type { EditorRef } from './types';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Editor } from 'slate';
|
|
2
|
+
import { jsx } from 'slate-hyperscript';
|
|
2
3
|
import type { CustomElement, CustomText } from '../../../types';
|
|
3
4
|
import type { IPlugin } from '../../types';
|
|
4
5
|
|
|
@@ -63,6 +64,36 @@ export class BasicFormattingPlugin
|
|
|
63
64
|
|
|
64
65
|
return <span {...attributes}>{content}</span>;
|
|
65
66
|
},
|
|
67
|
+
deserialize: (element: HTMLElement, children) => {
|
|
68
|
+
const { nodeName } = element;
|
|
69
|
+
|
|
70
|
+
let attrs: Record<string, boolean> | null = null;
|
|
71
|
+
switch (nodeName) {
|
|
72
|
+
case 'EM':
|
|
73
|
+
case 'I': {
|
|
74
|
+
attrs = { italic: true };
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'STRONG': {
|
|
78
|
+
attrs = { bold: true };
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case 'U': {
|
|
82
|
+
attrs = { underline: true };
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'S': {
|
|
86
|
+
attrs = { strikethrough: true };
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (attrs) {
|
|
92
|
+
return children?.map((child) => jsx('text', attrs, child));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return undefined;
|
|
96
|
+
},
|
|
66
97
|
},
|
|
67
98
|
];
|
|
68
99
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Editor, Element, Transforms } from 'slate';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { jsx } from 'slate-hyperscript';
|
|
3
|
+
import type { RenderElementProps } from 'slate-react';
|
|
4
|
+
import type { IPlugin } from '../../types';
|
|
4
5
|
|
|
5
6
|
export class HeadingsPlugin implements IPlugin {
|
|
6
7
|
static HeadingLevel1 = 'h1';
|
|
@@ -13,18 +14,51 @@ export class HeadingsPlugin implements IPlugin {
|
|
|
13
14
|
render: (props: RenderElementProps) => {
|
|
14
15
|
return <h1 {...props.attributes}>{props.children}</h1>;
|
|
15
16
|
},
|
|
17
|
+
deserialize: (element: HTMLElement, children) => {
|
|
18
|
+
const { nodeName } = element;
|
|
19
|
+
|
|
20
|
+
if (nodeName === 'H1') {
|
|
21
|
+
return jsx(
|
|
22
|
+
'element',
|
|
23
|
+
{ type: HeadingsPlugin.HeadingLevel1 },
|
|
24
|
+
children,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
16
28
|
},
|
|
17
29
|
{
|
|
18
30
|
type: HeadingsPlugin.HeadingLevel2,
|
|
19
31
|
render: (props: RenderElementProps) => {
|
|
20
32
|
return <h2 {...props.attributes}>{props.children}</h2>;
|
|
21
33
|
},
|
|
34
|
+
deserialize: (element: HTMLElement, children) => {
|
|
35
|
+
const { nodeName } = element;
|
|
36
|
+
|
|
37
|
+
if (nodeName === 'H2') {
|
|
38
|
+
return jsx(
|
|
39
|
+
'element',
|
|
40
|
+
{ type: HeadingsPlugin.HeadingLevel2 },
|
|
41
|
+
children,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
22
45
|
},
|
|
23
46
|
{
|
|
24
47
|
type: HeadingsPlugin.HeadingLevel3,
|
|
25
48
|
render: (props: RenderElementProps) => {
|
|
26
49
|
return <h3 {...props.attributes}>{props.children}</h3>;
|
|
27
50
|
},
|
|
51
|
+
deserialize: (element: HTMLElement, children) => {
|
|
52
|
+
const { nodeName } = element;
|
|
53
|
+
|
|
54
|
+
if (nodeName === 'H3') {
|
|
55
|
+
return jsx(
|
|
56
|
+
'element',
|
|
57
|
+
{ type: HeadingsPlugin.HeadingLevel3 },
|
|
58
|
+
children,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
28
62
|
},
|
|
29
63
|
];
|
|
30
64
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import isUrl from 'is-url';
|
|
2
2
|
import { Editor, Element, Range, Transforms } from 'slate';
|
|
3
|
+
import { jsx } from 'slate-hyperscript';
|
|
3
4
|
import type { RenderElementProps } from 'slate-react';
|
|
5
|
+
import { deserialize } from '../../core/deserialize';
|
|
4
6
|
import type { IPlugin } from '../../types';
|
|
5
7
|
import { LINK_ELEMENT } from './constants';
|
|
6
8
|
import { Link } from './Link';
|
|
@@ -54,6 +56,19 @@ export class LinksPlugin implements IPlugin {
|
|
|
54
56
|
/>
|
|
55
57
|
);
|
|
56
58
|
},
|
|
59
|
+
deserialize: (element: HTMLElement, children) => {
|
|
60
|
+
if (element.tagName === 'A') {
|
|
61
|
+
const url = element.getAttribute('href') || '';
|
|
62
|
+
return jsx(
|
|
63
|
+
'element',
|
|
64
|
+
{
|
|
65
|
+
type: LinksPlugin.LINK_TYPE,
|
|
66
|
+
url,
|
|
67
|
+
},
|
|
68
|
+
children,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
57
72
|
},
|
|
58
73
|
];
|
|
59
74
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type Path,
|
|
9
9
|
Transforms,
|
|
10
10
|
} from 'slate';
|
|
11
|
+
import { jsx } from 'slate-hyperscript';
|
|
11
12
|
import type { RenderElementProps } from 'slate-react';
|
|
12
13
|
import type { CustomElement } from '../../../types';
|
|
13
14
|
import { getPrev } from '../../core/queries';
|
|
@@ -133,6 +134,16 @@ export class ListsPlugin implements IPlugin {
|
|
|
133
134
|
</ul>
|
|
134
135
|
);
|
|
135
136
|
},
|
|
137
|
+
deserialize: (element: HTMLElement, children) => {
|
|
138
|
+
const { nodeName } = element;
|
|
139
|
+
if (nodeName === 'UL') {
|
|
140
|
+
return jsx(
|
|
141
|
+
'element',
|
|
142
|
+
{ type: ListsPlugin.BULLETED_LIST_ELEMENT },
|
|
143
|
+
children,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
136
147
|
},
|
|
137
148
|
{
|
|
138
149
|
type: ListsPlugin.NUMBERED_LIST_ELEMENT,
|
|
@@ -143,6 +154,16 @@ export class ListsPlugin implements IPlugin {
|
|
|
143
154
|
</ol>
|
|
144
155
|
);
|
|
145
156
|
},
|
|
157
|
+
deserialize: (element: HTMLElement, children) => {
|
|
158
|
+
const { nodeName } = element;
|
|
159
|
+
if (nodeName === 'OL') {
|
|
160
|
+
return jsx(
|
|
161
|
+
'element',
|
|
162
|
+
{ type: ListsPlugin.NUMBERED_LIST_ELEMENT },
|
|
163
|
+
children,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
146
167
|
},
|
|
147
168
|
{
|
|
148
169
|
type: ListsPlugin.LIST_ITEM_ELEMENT,
|
|
@@ -153,6 +174,16 @@ export class ListsPlugin implements IPlugin {
|
|
|
153
174
|
</li>
|
|
154
175
|
);
|
|
155
176
|
},
|
|
177
|
+
deserialize: (element: HTMLElement, children) => {
|
|
178
|
+
const { nodeName } = element;
|
|
179
|
+
if (nodeName === 'LI') {
|
|
180
|
+
return jsx(
|
|
181
|
+
'element',
|
|
182
|
+
{ type: ListsPlugin.LIST_ITEM_ELEMENT },
|
|
183
|
+
children,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
156
187
|
},
|
|
157
188
|
];
|
|
158
189
|
|
package/src/types.ts
CHANGED
|
@@ -60,6 +60,7 @@ export type Leaf<T extends Editor, TLeaf extends CustomText = CustomText> = {
|
|
|
60
60
|
editor: T,
|
|
61
61
|
) => ReactElement | null;
|
|
62
62
|
isVoid?: boolean;
|
|
63
|
+
deserialize?: Deserialize;
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
type Hotkey = readonly [string, (event: KeyboardEvent, editor: Editor) => void];
|
|
@@ -84,4 +85,4 @@ export type Serialize = (node: Node, children?: string) => string | undefined;
|
|
|
84
85
|
export type Deserialize = (
|
|
85
86
|
element: HTMLElement,
|
|
86
87
|
children?: (string | Descendant)[],
|
|
87
|
-
) =>
|
|
88
|
+
) => CustomElement | CustomText[] | undefined;
|