@seafile/sea-email-editor 0.0.9 → 0.0.10-beta
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/README.md +51 -0
- package/dist/editor/main/index.js +13 -7
- package/dist/extension/plugins/text-style/render-elem.js +15 -0
- package/dist/slate-convert/html-to-slate/index.js +18 -9
- package/dist/slate-convert/html-to-slate/rules/blockquote.js +4 -1
- package/dist/slate-convert/html-to-slate/rules/code-block.js +7 -3
- package/dist/slate-convert/html-to-slate/rules/image.js +5 -1
- package/dist/slate-convert/html-to-slate/rules/link.js +2 -1
- package/dist/slate-convert/html-to-slate/rules/list.js +1 -1
- package/dist/slate-convert/html-to-slate/rules/p.js +8 -1
- package/dist/slate-convert/html-to-slate/rules/paragraph.js +1 -1
- package/dist/slate-convert/html-to-slate/rules/text.js +45 -39
- package/dist/slate-convert/md-to-slate/transform.js +20 -10
- package/dist/slate-convert/slate-to-html/index.js +16 -2
- package/dist/utils/common.js +3 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1 +1,52 @@
|
|
|
1
1
|
# Sea email editor
|
|
2
|
+
|
|
3
|
+
Sea email editor is a React-based rich text editor for composing email content. It is built on top of Slate and includes HTML and Markdown conversion, along with support for common email editing blocks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- HTML to editor content conversion
|
|
8
|
+
- Markdown to editor content conversion
|
|
9
|
+
- Rich text formatting: bold, italic, underline, inline code
|
|
10
|
+
- Block elements: headings, blockquote, lists, code blocks, divider, tables
|
|
11
|
+
- Link and image rendering
|
|
12
|
+
- Localization support
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @seafile/sea-email-editor
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```jsx
|
|
23
|
+
import React from "react";
|
|
24
|
+
import SeaEmailEditor from "@seafile/sea-email-editor";
|
|
25
|
+
|
|
26
|
+
export default function App() {
|
|
27
|
+
return (
|
|
28
|
+
<SeaEmailEditor
|
|
29
|
+
value={"<div>Hello, world!</div>"}
|
|
30
|
+
isHtmlValue={true}
|
|
31
|
+
onChange={(html) => {
|
|
32
|
+
console.log(html);
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Props
|
|
40
|
+
|
|
41
|
+
- `value`: initial editor content, HTML or Markdown depending on `isHtmlValue`
|
|
42
|
+
- `isHtmlValue`: set to `true` when `value` is HTML
|
|
43
|
+
- `options.lang`: locale, currently `en` and `zh-cn`
|
|
44
|
+
- `onChange`: called with serialized HTML when the document changes
|
|
45
|
+
- `assetURLPrefix`: prefix for editor assets
|
|
46
|
+
- `editorApi`: editor integration hooks
|
|
47
|
+
- `onLinkClick`: custom link click handler
|
|
48
|
+
|
|
49
|
+
## Notes
|
|
50
|
+
|
|
51
|
+
- The editor now re-initializes when the incoming `value` or `isHtmlValue` changes.
|
|
52
|
+
- The example app under `example/` demonstrates how to preview the generated HTML output.
|
|
@@ -75,13 +75,19 @@ const Main = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
|
|
|
75
75
|
const [firstNode] = editor.children;
|
|
76
76
|
if (!firstNode) return;
|
|
77
77
|
if (focusRange && focusRange !== null && focusRange !== void 0 && focusRange.anchor) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
try {
|
|
79
|
+
const startOfFirstNode = _slate.Editor.start(editor, focusRange.anchor.path);
|
|
80
|
+
const range = {
|
|
81
|
+
anchor: startOfFirstNode,
|
|
82
|
+
focus: startOfFirstNode
|
|
83
|
+
};
|
|
84
|
+
(0, _core.focusEditor)(editor, range);
|
|
85
|
+
setTimeout(() => (0, _core.focusEditor)(editor, focusRange), 0);
|
|
86
|
+
} catch {
|
|
87
|
+
focusRangeRef.current = null;
|
|
88
|
+
focusNode(editor);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
85
91
|
focusRangeRef.current = null;
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
@@ -49,6 +49,21 @@ const renderText = (props, editor) => {
|
|
|
49
49
|
children: markedChildren
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
|
+
if (leaf.superscript) {
|
|
53
|
+
markedChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)("sup", {
|
|
54
|
+
children: markedChildren
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (leaf.subscript) {
|
|
58
|
+
markedChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)("sub", {
|
|
59
|
+
children: markedChildren
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (leaf.highlight) {
|
|
63
|
+
markedChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)("mark", {
|
|
64
|
+
children: markedChildren
|
|
65
|
+
});
|
|
66
|
+
}
|
|
52
67
|
if (leaf.decoration) {
|
|
53
68
|
markedChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
54
69
|
children: markedChildren
|
|
@@ -10,6 +10,17 @@ var _typeOf = _interopRequireDefault(require("type-of"));
|
|
|
10
10
|
var _constants = require("./constants");
|
|
11
11
|
var _rules = _interopRequireDefault(require("./rules"));
|
|
12
12
|
var _helper = require("./helper");
|
|
13
|
+
var _typeDetection = require("../../utils/type-detection");
|
|
14
|
+
const generateDefaultValue = () => {
|
|
15
|
+
return [{
|
|
16
|
+
id: _slugid.default.nice(),
|
|
17
|
+
type: _constants.PARAGRAPH,
|
|
18
|
+
children: [{
|
|
19
|
+
text: '',
|
|
20
|
+
id: _slugid.default.nice()
|
|
21
|
+
}]
|
|
22
|
+
}];
|
|
23
|
+
};
|
|
13
24
|
const cruftNewline = element => {
|
|
14
25
|
return !(element.nodeName === '#text' && element.nodeValue === '\n');
|
|
15
26
|
};
|
|
@@ -98,14 +109,7 @@ const deserializeElements = function () {
|
|
|
98
109
|
|
|
99
110
|
const formatElementNodes = nodes => {
|
|
100
111
|
if (nodes.length === 0) {
|
|
101
|
-
return
|
|
102
|
-
id: _slugid.default.nice(),
|
|
103
|
-
type: _constants.PARAGRAPH,
|
|
104
|
-
children: [{
|
|
105
|
-
text: '',
|
|
106
|
-
id: _slugid.default.nice()
|
|
107
|
-
}]
|
|
108
|
-
}];
|
|
112
|
+
return generateDefaultValue();
|
|
109
113
|
}
|
|
110
114
|
nodes = nodes.reduce((memo, node) => {
|
|
111
115
|
if (_constants.TOP_LEVEL_TYPES.includes(node.type)) {
|
|
@@ -145,8 +149,13 @@ const formatElementNodes = nodes => {
|
|
|
145
149
|
return nodes;
|
|
146
150
|
};
|
|
147
151
|
const deserializeHtml = html => {
|
|
148
|
-
|
|
152
|
+
if ((0, _typeDetection.isNumber)(html)) {
|
|
153
|
+
html = String(html);
|
|
154
|
+
}
|
|
155
|
+
if (typeof html !== 'string') return generateDefaultValue();
|
|
156
|
+
const parsed = new DOMParser().parseFromString(html.replace('\n', '').replace(' ', ''), 'text/html');
|
|
149
157
|
const fragment = parsed.body;
|
|
158
|
+
fragment.querySelectorAll('style, title').forEach(el => el.remove());
|
|
150
159
|
const children = Array.from(fragment.childNodes);
|
|
151
160
|
let nodes = [];
|
|
152
161
|
nodes = deserializeElements(children, true);
|
|
@@ -17,7 +17,10 @@ const blockquoteRule = (element, parseChild) => {
|
|
|
17
17
|
const node = {
|
|
18
18
|
id: _slugid.default.nice(),
|
|
19
19
|
type: _constants.BLOCKQUOTE,
|
|
20
|
-
children: parseChild(childNodes)
|
|
20
|
+
children: parseChild(childNodes) || [{
|
|
21
|
+
id: _slugid.default.nice(),
|
|
22
|
+
text: ''
|
|
23
|
+
}]
|
|
21
24
|
};
|
|
22
25
|
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
23
26
|
}
|
|
@@ -17,7 +17,10 @@ const codeBlockRule = (element, parseChild) => {
|
|
|
17
17
|
const children = Array.from(childNodes).filter(item => item.nodeName === 'CODE');
|
|
18
18
|
let codeChild = children[0];
|
|
19
19
|
if (codeChild) {
|
|
20
|
-
let lang = codeChild.getAttribute('lang');
|
|
20
|
+
let lang = codeChild.getAttribute('lang') || codeChild.getAttribute('class') || '';
|
|
21
|
+
if (lang.startsWith('language-')) {
|
|
22
|
+
lang = lang.replace('language-', '');
|
|
23
|
+
}
|
|
21
24
|
lang = (0, _helper.genCodeLangs)().find(item => item.value === lang) || 'plaintext';
|
|
22
25
|
const node = {
|
|
23
26
|
id: _slugid.default.nice(),
|
|
@@ -27,9 +30,10 @@ const codeBlockRule = (element, parseChild) => {
|
|
|
27
30
|
};
|
|
28
31
|
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
29
32
|
} else {
|
|
33
|
+
var _childNodes$;
|
|
30
34
|
const lang = 'plaintext';
|
|
31
|
-
const content = childNodes[0]
|
|
32
|
-
const textArr = content.split('\n')
|
|
35
|
+
const content = ((_childNodes$ = childNodes[0]) === null || _childNodes$ === void 0 ? void 0 : _childNodes$.textContent) || '';
|
|
36
|
+
const textArr = content.split('\n');
|
|
33
37
|
const children = textArr.map(text => {
|
|
34
38
|
return {
|
|
35
39
|
id: _slugid.default.nice(),
|
|
@@ -17,7 +17,11 @@ const imageRule = (element, parseChild) => {
|
|
|
17
17
|
id: _slugid.default.nice(),
|
|
18
18
|
type: _constants.IMAGE,
|
|
19
19
|
data: {
|
|
20
|
-
src: element.getAttribute('src')
|
|
20
|
+
src: element.getAttribute('src'),
|
|
21
|
+
alt: element.getAttribute('alt') || undefined,
|
|
22
|
+
title: element.getAttribute('title') || undefined,
|
|
23
|
+
width: element.getAttribute('width') || undefined,
|
|
24
|
+
height: element.getAttribute('height') || undefined
|
|
21
25
|
},
|
|
22
26
|
children: [{
|
|
23
27
|
text: '',
|
|
@@ -14,12 +14,13 @@ const linkRule = (element, parseChild) => {
|
|
|
14
14
|
} = element;
|
|
15
15
|
const content = element.textContent || element.getAttribute('title') || element.getAttribute('href');
|
|
16
16
|
if (nodeName === 'A') {
|
|
17
|
+
const children = parseChild(element.childNodes);
|
|
17
18
|
const node = {
|
|
18
19
|
id: _slugid.default.nice(),
|
|
19
20
|
type: _constants.LINK,
|
|
20
21
|
url: element.getAttribute('href') || content,
|
|
21
22
|
title: element.getAttribute('title'),
|
|
22
|
-
children: [{
|
|
23
|
+
children: Array.isArray(children) && children.length > 0 ? children : [{
|
|
23
24
|
id: _slugid.default.nice(),
|
|
24
25
|
text: content || ''
|
|
25
26
|
}]
|
|
@@ -53,7 +53,7 @@ const listRule = (element, parseChild) => {
|
|
|
53
53
|
};
|
|
54
54
|
normalizedChildren.forEach(child => {
|
|
55
55
|
if (!child) return;
|
|
56
|
-
const isInlineNode = !child.type || _constants.INLINE_LEVEL_TYPES.includes(child.type);
|
|
56
|
+
const isInlineNode = !child.type || _constants.INLINE_LEVEL_TYPES.includes(child.type) || child.type === 'text';
|
|
57
57
|
if (isInlineNode) {
|
|
58
58
|
inlineChildren.push(child);
|
|
59
59
|
return;
|
|
@@ -25,10 +25,17 @@ const pRule = (element, parseChild) => {
|
|
|
25
25
|
};
|
|
26
26
|
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
27
27
|
}
|
|
28
|
+
let children = parseChild(childNodes);
|
|
29
|
+
if (children.length === 0) {
|
|
30
|
+
children = [{
|
|
31
|
+
id: _slugid.default.nice(),
|
|
32
|
+
text: ''
|
|
33
|
+
}];
|
|
34
|
+
}
|
|
28
35
|
const node = {
|
|
29
36
|
id: _slugid.default.nice(),
|
|
30
37
|
type: _constants.P,
|
|
31
|
-
children
|
|
38
|
+
children
|
|
32
39
|
};
|
|
33
40
|
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
34
41
|
}
|
|
@@ -13,7 +13,7 @@ const paragraphRule = (element, parseChild) => {
|
|
|
13
13
|
nodeName,
|
|
14
14
|
childNodes
|
|
15
15
|
} = element;
|
|
16
|
-
if (nodeName === 'DIV' && element.parentElement.nodeName !== 'LI') {
|
|
16
|
+
if ((nodeName === 'DIV' || nodeName === 'ARTICLE') && element.parentElement.nodeName !== 'LI') {
|
|
17
17
|
if (childNodes.length === 0) {
|
|
18
18
|
const node = {
|
|
19
19
|
id: _slugid.default.nice(),
|
|
@@ -12,59 +12,65 @@ const textRule = (element, parseChild) => {
|
|
|
12
12
|
nodeName,
|
|
13
13
|
nodeType
|
|
14
14
|
} = element;
|
|
15
|
-
|
|
15
|
+
const createTextNode = function () {
|
|
16
|
+
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
16
17
|
const node = {
|
|
17
18
|
id: _slugid.default.nice(),
|
|
18
|
-
text: element.textContent
|
|
19
|
+
text: element.textContent,
|
|
20
|
+
...props
|
|
19
21
|
};
|
|
20
22
|
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
23
|
+
};
|
|
24
|
+
if (nodeName === 'SPAN') {
|
|
25
|
+
return createTextNode();
|
|
21
26
|
}
|
|
22
27
|
if (nodeName === 'STRONG' || nodeName === 'B') {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
text: element.textContent
|
|
27
|
-
};
|
|
28
|
-
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
28
|
+
return createTextNode({
|
|
29
|
+
bold: true
|
|
30
|
+
});
|
|
29
31
|
}
|
|
30
32
|
if (nodeName === 'CODE' && element.parentElement.nodeName !== 'PRE') {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
text: element.textContent
|
|
35
|
-
};
|
|
36
|
-
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
33
|
+
return createTextNode({
|
|
34
|
+
code: true
|
|
35
|
+
});
|
|
37
36
|
}
|
|
38
|
-
if (nodeName === 'DEL') {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
text: element.textContent
|
|
43
|
-
};
|
|
44
|
-
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
37
|
+
if (nodeName === 'DEL' || nodeName === 'S' || nodeName === 'STRIKE') {
|
|
38
|
+
return createTextNode({
|
|
39
|
+
delete: true
|
|
40
|
+
});
|
|
45
41
|
}
|
|
46
|
-
if (nodeName === 'I') {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
text: element.textContent
|
|
51
|
-
};
|
|
52
|
-
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
42
|
+
if (nodeName === 'I' || nodeName === 'EM') {
|
|
43
|
+
return createTextNode({
|
|
44
|
+
italic: true
|
|
45
|
+
});
|
|
53
46
|
}
|
|
54
47
|
if (nodeName === 'INS') {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return (
|
|
48
|
+
return createTextNode({
|
|
49
|
+
add: true
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (nodeName === 'U') {
|
|
53
|
+
return createTextNode({
|
|
54
|
+
underline: true
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (nodeName === 'SUP') {
|
|
58
|
+
return createTextNode({
|
|
59
|
+
superscript: true
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (nodeName === 'SUB') {
|
|
63
|
+
return createTextNode({
|
|
64
|
+
subscript: true
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (nodeName === 'MARK') {
|
|
68
|
+
return createTextNode({
|
|
69
|
+
highlight: true
|
|
70
|
+
});
|
|
61
71
|
}
|
|
62
72
|
if (nodeType === 3) {
|
|
63
|
-
|
|
64
|
-
id: _slugid.default.nice(),
|
|
65
|
-
text: element.textContent
|
|
66
|
-
};
|
|
67
|
-
return (0, _helper.mergeElementOther2SlateNode)(element, node);
|
|
73
|
+
return createTextNode();
|
|
68
74
|
}
|
|
69
75
|
return;
|
|
70
76
|
};
|
|
@@ -11,7 +11,8 @@ var _elementTypes = require("../../extension/constants/element-types");
|
|
|
11
11
|
var _htmlToSlate = _interopRequireDefault(require("../html-to-slate"));
|
|
12
12
|
const INLINE_KEY_MAP = {
|
|
13
13
|
strong: 'bold',
|
|
14
|
-
emphasis: 'italic'
|
|
14
|
+
emphasis: 'italic',
|
|
15
|
+
delete: 'delete'
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
// <strong><em>aa<em>bb<em></strong>
|
|
@@ -88,6 +89,15 @@ const applyMarkForInlineItem = function (result, item) {
|
|
|
88
89
|
textNode = {};
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
92
|
+
if (type === 'break') {
|
|
93
|
+
result.push({
|
|
94
|
+
id: _slugid.default.nice(),
|
|
95
|
+
text: '\n',
|
|
96
|
+
...textNode
|
|
97
|
+
});
|
|
98
|
+
textNode = {};
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
91
101
|
if (type === 'inlineCode') {
|
|
92
102
|
textNode['code'] = true;
|
|
93
103
|
textNode['text'] = value || '';
|
|
@@ -430,16 +440,16 @@ const transformMath = node => {
|
|
|
430
440
|
};
|
|
431
441
|
exports.transformMath = transformMath;
|
|
432
442
|
const elementHandlers = {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
443
|
+
paragraph: transformParagraph,
|
|
444
|
+
heading: transformHeader,
|
|
445
|
+
blockquote: transformBlockquote,
|
|
446
|
+
table: transformTable,
|
|
447
|
+
list: transformList,
|
|
438
448
|
// ordered_list | unordered_list | check_list_item
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
449
|
+
code: transformCodeBlock,
|
|
450
|
+
thematicBreak: transformHr,
|
|
451
|
+
math: transformMath,
|
|
452
|
+
html: transformBlockHtml
|
|
443
453
|
};
|
|
444
454
|
const formatMdToSlate = children => {
|
|
445
455
|
const validChildren = children.filter(child => elementHandlers[child.type]);
|
|
@@ -12,8 +12,7 @@ const isContentValid = value => {
|
|
|
12
12
|
};
|
|
13
13
|
const isEmptyParagraph = node => {
|
|
14
14
|
const voidNodeTypes = ['image', 'formula'];
|
|
15
|
-
if (
|
|
16
|
-
if (node.type !== _constants.ElementTypes.P) return false;
|
|
15
|
+
if (![_constants.ElementTypes.PARAGRAPH, _constants.ElementTypes.P].includes(node.type)) return false;
|
|
17
16
|
const hasBlock = node.children.some(item => voidNodeTypes.includes(item.type));
|
|
18
17
|
const hasHtml = node.children.some(item => item.type === 'html');
|
|
19
18
|
if (hasBlock) return false;
|
|
@@ -128,6 +127,21 @@ const element2Html = (value, element, path) => {
|
|
|
128
127
|
if (underline) {
|
|
129
128
|
textDom = `<span style="text-decoration: underline;">${textDom}</span>`;
|
|
130
129
|
}
|
|
130
|
+
if (element.delete) {
|
|
131
|
+
textDom = `<del>${textDom}</del>`;
|
|
132
|
+
}
|
|
133
|
+
if (element.add) {
|
|
134
|
+
textDom = `<ins>${textDom}</ins>`;
|
|
135
|
+
}
|
|
136
|
+
if (element.superscript) {
|
|
137
|
+
textDom = `<sup>${textDom}</sup>`;
|
|
138
|
+
}
|
|
139
|
+
if (element.subscript) {
|
|
140
|
+
textDom = `<sub>${textDom}</sub>`;
|
|
141
|
+
}
|
|
142
|
+
if (element.highlight) {
|
|
143
|
+
textDom = `<mark>${textDom}</mark>`;
|
|
144
|
+
}
|
|
131
145
|
if (code) {
|
|
132
146
|
const {
|
|
133
147
|
style
|
package/dist/utils/common.js
CHANGED
|
@@ -33,8 +33,10 @@ const isUrl = url => {
|
|
|
33
33
|
// Check document is empty or only contains void nodes
|
|
34
34
|
exports.isUrl = isUrl;
|
|
35
35
|
const isDocumentEmpty = editor => {
|
|
36
|
-
const document = editor.children;
|
|
36
|
+
const document = editor === null || editor === void 0 ? void 0 : editor.children;
|
|
37
|
+
if (!Array.isArray(document) || document.length === 0) return true;
|
|
37
38
|
const [firstChildNode] = document;
|
|
39
|
+
if (!firstChildNode || !Array.isArray(firstChildNode.children)) return true;
|
|
38
40
|
// Check if document has only one block node
|
|
39
41
|
const isWrapperEmpty = document.length === 1 && _slate.Node.string(firstChildNode).length === 0;
|
|
40
42
|
if (!isWrapperEmpty) return false;
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seafile/sea-email-editor",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "0.0.10-beta",
|
|
4
|
+
"description": "A Slate-based rich email editor with HTML, markdown, tables, images, links, and block plugins.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
|
|
7
|
+
"@seafile/react-image-lightbox": "^5.0.4",
|
|
8
8
|
"classnames": "2.3.2",
|
|
9
9
|
"copy-to-clipboard": "3.3.1",
|
|
10
10
|
"deep-copy": "1.4.2",
|