@flozy/editor 5.5.0 → 5.5.2
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/Editor/CommonEditor.js +4 -1
- package/dist/Editor/Elements/DataView/DataView.js +1 -1
- package/dist/Editor/Elements/DataView/Providers/DataViewProvider.js +1 -5
- package/dist/Editor/Toolbar/Mini/MiniToolbar.js +5 -2
- package/dist/Editor/Toolbar/Mini/Styles.js +5 -0
- package/dist/Editor/helper/deserialize/index.js +66 -24
- package/dist/Editor/plugins/withHTML.js +42 -5
- package/package.json +1 -1
@@ -550,7 +550,10 @@ const CommonEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
550
550
|
renderLeaf: renderLeaf,
|
551
551
|
decorate: d => decorators(d, editor),
|
552
552
|
onKeyDown: onKeyDown,
|
553
|
-
onSelect: () => handleCursorScroll(editorWrapper.current)
|
553
|
+
onSelect: () => handleCursorScroll(editorWrapper.current),
|
554
|
+
scrollSelectionIntoView: () => {
|
555
|
+
// disable the scrollSelectionIntoView, to resolve editor auto scroll on free-grid
|
556
|
+
}
|
554
557
|
}), !readOnly ? /*#__PURE__*/_jsx(MentionsPopup, {
|
555
558
|
ref: mentionsRef,
|
556
559
|
mentions: mentions,
|
@@ -38,7 +38,7 @@ const DataView = props => {
|
|
38
38
|
const name = [m?.first_name || "", m?.last_name || ""]?.join(" ").trim();
|
39
39
|
return {
|
40
40
|
value: m?.email,
|
41
|
-
|
41
|
+
label: name || m?.username || m?.email,
|
42
42
|
avatar: m?.avatar || null
|
43
43
|
};
|
44
44
|
});
|
@@ -46,11 +46,7 @@ export const DataViewProvider = ({
|
|
46
46
|
const [rows, setRows] = useState(initialData?.rows || []);
|
47
47
|
const [selectedRows, setSelectedRows] = useState([]);
|
48
48
|
const [search, setSearch] = useState("");
|
49
|
-
const users = peoples
|
50
|
-
return {
|
51
|
-
value: m?.name
|
52
|
-
};
|
53
|
-
});
|
49
|
+
const [users] = useState(peoples);
|
54
50
|
|
55
51
|
// for undo and redo
|
56
52
|
// minimal added for perforamnce issue avoid
|
@@ -139,14 +139,17 @@ const MiniToolbar = props => {
|
|
139
139
|
icon: Icon
|
140
140
|
}) => {
|
141
141
|
const isDisabled = popupType === type || type === "undo" ? !canUndo : type === "redo" ? !canRedo : false;
|
142
|
+
const isFocussed = editor?.selection?.anchor?.path;
|
143
|
+
const disableAddElement = type === "addElement" && !isFocussed;
|
142
144
|
return /*#__PURE__*/_jsx(Tooltip, {
|
143
145
|
arrow: true,
|
144
146
|
title: label,
|
145
147
|
disableHoverListener: toolTip,
|
146
148
|
children: /*#__PURE__*/_jsx(IconButton, {
|
147
|
-
className: `${type === popper ? "active" : ""} ${type === "undo" && !canUndo || type === "redo" && !canRedo ? "disabled" : ""} ${type === "undo" ? canUndo ? "activeUndo" : "disabledUndo" : type === "redo" ? canRedo ? "activeRedo" : "disabledRedo" : ""}
|
149
|
+
className: `${type === popper ? "active" : ""} ${type === "undo" && !canUndo || type === "redo" && !canRedo ? "disabled" : ""} ${type === "undo" ? canUndo ? "activeUndo" : "disabledUndo" : type === "redo" ? canRedo ? "activeRedo" : "disabledRedo" : ""} ${disableAddElement ? "disableAddElement" : ""}
|
150
|
+
`,
|
148
151
|
onClick: handleClick(type),
|
149
|
-
disabled: isDisabled,
|
152
|
+
disabled: isDisabled || disableAddElement,
|
150
153
|
children: type === "page-settings" ? /*#__PURE__*/_jsx(PageSettingsButton, {
|
151
154
|
from: "miniToolBar",
|
152
155
|
icoBtnType: "mini",
|
@@ -1,4 +1,26 @@
|
|
1
1
|
import { jsx } from "slate-hyperscript";
|
2
|
+
const inlineStyles = [{
|
3
|
+
key: "bold",
|
4
|
+
getStyle: styles => styles.fontWeight === "bold" || parseInt(styles.fontWeight, 10) >= 700
|
5
|
+
}, {
|
6
|
+
key: "italic",
|
7
|
+
getStyle: styles => styles.fontStyle === "italic"
|
8
|
+
}, {
|
9
|
+
key: "underline",
|
10
|
+
getStyle: styles => styles.textDecoration.includes("underline")
|
11
|
+
}];
|
12
|
+
function getInlineTextStyles(element) {
|
13
|
+
if (!element || !element.style) return {};
|
14
|
+
const styles = element.style;
|
15
|
+
const elementStyles = inlineStyles.reduce((total, currVal) => {
|
16
|
+
const style = currVal.getStyle(styles);
|
17
|
+
if (style) {
|
18
|
+
total[currVal.key] = style;
|
19
|
+
}
|
20
|
+
return total;
|
21
|
+
}, {});
|
22
|
+
return elementStyles;
|
23
|
+
}
|
2
24
|
const handleTableCell = (el, children) => {
|
3
25
|
const wrapChild = children?.map(c => {
|
4
26
|
if (typeof c === "string") {
|
@@ -20,6 +42,24 @@ const handleTableCell = (el, children) => {
|
|
20
42
|
}
|
21
43
|
};
|
22
44
|
};
|
45
|
+
const INLINE_TAGS = ["A", "ABBR", "B", "BDO", "CITE", "CODE", "DATA", "DEL", "DFN", "IMG", "INS", "KBD", "LABEL", "MARK", "Q", "SAMP", "SMALL", "SPAN", "SUB", "SUP", "TIME", "VAR"];
|
46
|
+
|
47
|
+
// to avoid nested paragraph to resolve performace issue
|
48
|
+
const paragraphType = el => {
|
49
|
+
const {
|
50
|
+
childNodes = []
|
51
|
+
} = el || {};
|
52
|
+
|
53
|
+
// if anyone of the child node is text node or wrapped with inline tags, it is considered to be an paragraph node
|
54
|
+
const isHavingText = childNodes?.length ? Array.from(childNodes)?.some(child => {
|
55
|
+
const isTextNode = child?.nodeType === 3;
|
56
|
+
const isHavingInlineTags = TEXT_TAGS[child?.nodeName] || INLINE_TAGS.includes(child.nodeName);
|
57
|
+
return isTextNode || isHavingInlineTags;
|
58
|
+
}) : null;
|
59
|
+
return isHavingText ? {
|
60
|
+
type: "paragraph"
|
61
|
+
} : {};
|
62
|
+
};
|
23
63
|
const ELEMENT_TAGS = {
|
24
64
|
A: el => ({
|
25
65
|
type: "link",
|
@@ -59,24 +99,14 @@ const ELEMENT_TAGS = {
|
|
59
99
|
OL: () => ({
|
60
100
|
type: "orderedList"
|
61
101
|
}),
|
62
|
-
P:
|
63
|
-
|
64
|
-
}),
|
65
|
-
DIV: () => ({
|
66
|
-
type: "paragraph"
|
67
|
-
}),
|
102
|
+
P: paragraphType,
|
103
|
+
DIV: paragraphType,
|
68
104
|
PRE: () => ({
|
69
105
|
type: "code"
|
70
106
|
}),
|
71
|
-
META:
|
72
|
-
|
73
|
-
|
74
|
-
STYLE: () => ({
|
75
|
-
type: "paragraph"
|
76
|
-
}),
|
77
|
-
"GOOGLE-SHEETS-HTML-ORIGIN": () => ({
|
78
|
-
type: "paragraph"
|
79
|
-
}),
|
107
|
+
META: paragraphType,
|
108
|
+
STYLE: paragraphType,
|
109
|
+
"GOOGLE-SHEETS-HTML-ORIGIN": paragraphType,
|
80
110
|
TABLE: (el, children = []) => {
|
81
111
|
try {
|
82
112
|
const bodyChild = children || [];
|
@@ -98,12 +128,8 @@ const ELEMENT_TAGS = {
|
|
98
128
|
type: "table-row"
|
99
129
|
}),
|
100
130
|
TD: handleTableCell,
|
101
|
-
COLGROUP:
|
102
|
-
|
103
|
-
}),
|
104
|
-
COL: () => ({
|
105
|
-
type: "paragraph"
|
106
|
-
})
|
131
|
+
COLGROUP: paragraphType,
|
132
|
+
COL: paragraphType
|
107
133
|
};
|
108
134
|
|
109
135
|
// COMPAT: `B` is omitted here because Google Docs uses `<b>` in weird ways.
|
@@ -129,11 +155,18 @@ const TEXT_TAGS = {
|
|
129
155
|
U: () => ({
|
130
156
|
underline: true
|
131
157
|
})
|
158
|
+
// B: () => ({ bold: true }),
|
132
159
|
};
|
160
|
+
|
133
161
|
const deserialize = el => {
|
134
162
|
if (el.nodeType === 3) {
|
163
|
+
// if there is any line-breaks
|
135
164
|
const match = /\r|\n/.exec(el.textContent);
|
136
|
-
|
165
|
+
const text = el.textContent.replace(/\r|\n/g, "").trim();
|
166
|
+
return match && !text ? null : {
|
167
|
+
text,
|
168
|
+
...getInlineTextStyles(el.parentNode)
|
169
|
+
};
|
137
170
|
} else if (el.nodeType !== 1) {
|
138
171
|
return null;
|
139
172
|
} else if (el.nodeName === "BR") {
|
@@ -160,11 +193,20 @@ const deserialize = el => {
|
|
160
193
|
overwriteChild,
|
161
194
|
...attrs
|
162
195
|
} = ELEMENT_TAGS[nodeName](el, children);
|
163
|
-
|
196
|
+
if (attrs?.type) {
|
197
|
+
return jsx("element", attrs, overwriteChild || children);
|
198
|
+
}
|
164
199
|
}
|
165
200
|
if (TEXT_TAGS[nodeName]) {
|
166
201
|
const attrs = TEXT_TAGS[nodeName](el);
|
167
|
-
return children.map(child =>
|
202
|
+
return children.map(child => {
|
203
|
+
if (child?.type) {
|
204
|
+
// if any list elements (like ul, ol... tags) is wrapped inside the TEXT_TAGS, we will return child as it is, else return it as text node
|
205
|
+
return child;
|
206
|
+
} else {
|
207
|
+
return jsx("text", attrs, child);
|
208
|
+
}
|
209
|
+
});
|
168
210
|
}
|
169
211
|
return children;
|
170
212
|
};
|
@@ -4,6 +4,43 @@ import { decodeAndParseBase64 } from "../utils/helper";
|
|
4
4
|
const avoidDefaultInsert = ["table", "grid"];
|
5
5
|
const NON_TEXT_TAGS = ["ol", "ul", "img", "table", "video", "a", "button", "GOOGLE-SHEETS-HTML-ORIGIN"];
|
6
6
|
const ALLOWED_TEXT_NODES = ["paragraph", "title", "headingOne", "headingTwo", "headingThree"];
|
7
|
+
const parseCopiedHTML = html => {
|
8
|
+
const parsed = new DOMParser().parseFromString(html, "text/html");
|
9
|
+
|
10
|
+
// if ol, ul are inside li, remove and push ol,ul after that li to maintain format between our slate list and external source list's json
|
11
|
+
parsed.querySelectorAll("li > ul, li > ol").forEach(list => {
|
12
|
+
// Find the parent li
|
13
|
+
const parentLi = list.parentElement;
|
14
|
+
|
15
|
+
// Move the list after the parent li
|
16
|
+
parentLi.after(list);
|
17
|
+
});
|
18
|
+
|
19
|
+
// to handle google docs list
|
20
|
+
parsed.querySelectorAll("li p, li div").forEach(element => {
|
21
|
+
const parent = element.parentNode;
|
22
|
+
// Move all child nodes of <p> or <div> to its parent <li>
|
23
|
+
while (element.firstChild) {
|
24
|
+
parent.insertBefore(element.firstChild, element);
|
25
|
+
}
|
26
|
+
// Remove the <p> or <div> element
|
27
|
+
parent.removeChild(element);
|
28
|
+
});
|
29
|
+
|
30
|
+
// claude.ai, copy list inbetween, some li tags are not wrapped with ul or ol
|
31
|
+
parsed.querySelectorAll("li").forEach(li => {
|
32
|
+
// Check if the parent of <li> is not a <ul> or <ol>
|
33
|
+
if (!li.parentElement || li.parentElement.tagName !== "UL" && li.parentElement.tagName !== "OL") {
|
34
|
+
// Create a <ul> element
|
35
|
+
const ul = document.createElement("ul");
|
36
|
+
// Append the <li> to the <ul>
|
37
|
+
ul.appendChild(li.cloneNode(true)); // Clone the <li>
|
38
|
+
// Replace the original <li> in the DOM with the <ul>
|
39
|
+
li.replaceWith(ul);
|
40
|
+
}
|
41
|
+
});
|
42
|
+
return parsed;
|
43
|
+
};
|
7
44
|
const loopChildren = (children = [], defaultInsert) => {
|
8
45
|
if (!children?.length) {
|
9
46
|
return defaultInsert;
|
@@ -28,7 +65,7 @@ const getCurrentElement = editor => {
|
|
28
65
|
return null;
|
29
66
|
}
|
30
67
|
};
|
31
|
-
const getCurrentElementText = editor => {
|
68
|
+
export const getCurrentElementText = editor => {
|
32
69
|
try {
|
33
70
|
if (editor.selection) {
|
34
71
|
return Editor.string(editor, editor?.selection?.anchor?.path);
|
@@ -186,15 +223,15 @@ const withHtml = editor => {
|
|
186
223
|
return;
|
187
224
|
}
|
188
225
|
const currentText = getCurrentElementText(editor);
|
189
|
-
if (currentText && !isTextNode) {
|
226
|
+
if (currentText?.trim() && !isTextNode) {
|
190
227
|
insertAtNextNode(editor, decoded);
|
191
228
|
return;
|
192
229
|
}
|
193
230
|
insertData(data);
|
194
231
|
}
|
195
232
|
} else if (html) {
|
196
|
-
const parsed =
|
197
|
-
const rootElement = parsed.body
|
233
|
+
const parsed = parseCopiedHTML(html);
|
234
|
+
const rootElement = parsed.body;
|
198
235
|
const isNonText = rootElement ? rootElement?.querySelector(NON_TEXT_TAGS.toString()) : false;
|
199
236
|
const isGoogleSheet = parsed.body.querySelector("google-sheets-html-origin");
|
200
237
|
if (isGoogleSheet) {
|
@@ -230,7 +267,7 @@ const withHtml = editor => {
|
|
230
267
|
return;
|
231
268
|
}
|
232
269
|
const currentText = getCurrentElementText(editor);
|
233
|
-
if (currentText && isNonText) {
|
270
|
+
if (currentText?.trim() && isNonText) {
|
234
271
|
insertAtNextNode(editor, formattedFragment);
|
235
272
|
return;
|
236
273
|
}
|