@pie-lib/editable-html-tip-tap 3.0.3-next.20261007175429 → 3.0.3-next.20261007181944
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/components/EditableHtml.js +136 -132
- package/dist/extensions/image.d.ts +5 -0
- package/dist/extensions/image.js +39 -23
- package/dist/external-paste.d.ts +17 -5
- package/dist/external-paste.js +83 -54
- package/package.json +1 -1
|
@@ -5,42 +5,42 @@ import { ExtendedTableCell as r, ExtendedTableHeader as i } from "../extensions/
|
|
|
5
5
|
import { DivNode as a } from "../extensions/div-node.js";
|
|
6
6
|
import { EnsureEmptyRootIsDiv as ee } from "../extensions/ensure-empty-root-div.js";
|
|
7
7
|
import { EnsureListItemContentIsDiv as te } from "../extensions/ensure-list-item-content-is-div.js";
|
|
8
|
-
import { DragInTheBlankNode as
|
|
9
|
-
import { MathNode as
|
|
10
|
-
import { ImageUploadNode as
|
|
11
|
-
import { Media as
|
|
8
|
+
import { DragInTheBlankNode as o, ExplicitConstructedResponseNode as s, InlineDropdownNode as c, MathTemplatedNode as l, ResponseAreaExtension as u } from "../extensions/responseArea.js";
|
|
9
|
+
import { MathNode as ne } from "../extensions/math.js";
|
|
10
|
+
import { ImageUploadNode as re, uploadPastedImage as ie } from "../extensions/image.js";
|
|
11
|
+
import { Media as ae } from "../extensions/media.js";
|
|
12
12
|
import { CSSMark as oe } from "../extensions/css.js";
|
|
13
|
-
import { ExtendedListItem as
|
|
14
|
-
import { HeadingParagraph as
|
|
13
|
+
import { ExtendedListItem as se } from "../extensions/extended-list-item.js";
|
|
14
|
+
import { HeadingParagraph as ce } from "../extensions/heading-paragraph.js";
|
|
15
15
|
import { valueToSize as d } from "../utils/size.js";
|
|
16
|
-
import
|
|
17
|
-
import { PLUGINS_MAP as
|
|
18
|
-
import { useCallback as
|
|
19
|
-
import { debounce as
|
|
20
|
-
import { EditorContent as
|
|
21
|
-
import { styled as
|
|
22
|
-
import
|
|
23
|
-
import { TextStyleKit as
|
|
24
|
-
import { CharacterCount as
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import { TableRow as
|
|
31
|
-
import { jsx as
|
|
16
|
+
import le from "./TiptapContainer.js";
|
|
17
|
+
import { PLUGINS_MAP as ue, buildExtensions as f } from "../extensions/index.js";
|
|
18
|
+
import { useCallback as p, useEffect as m, useMemo as h, useRef as g, useState as _ } from "react";
|
|
19
|
+
import { debounce as de } from "@pie-element/shared-lodash";
|
|
20
|
+
import { EditorContent as v, useEditor as y, useEditorState as b } from "@tiptap/react";
|
|
21
|
+
import { styled as x } from "@mui/material/styles";
|
|
22
|
+
import S from "@tiptap/starter-kit";
|
|
23
|
+
import { TextStyleKit as C } from "@tiptap/extension-text-style";
|
|
24
|
+
import { CharacterCount as w } from "@tiptap/extension-character-count";
|
|
25
|
+
import T from "@tiptap/extension-superscript";
|
|
26
|
+
import E from "@tiptap/extension-subscript";
|
|
27
|
+
import D from "@tiptap/extension-text-align";
|
|
28
|
+
import O from "@tiptap/extension-image";
|
|
29
|
+
import k from "@tiptap/extension-placeholder";
|
|
30
|
+
import { TableRow as A } from "@tiptap/extension-table-row";
|
|
31
|
+
import { jsx as j } from "react/jsx-runtime";
|
|
32
32
|
//#region src/components/EditableHtml.tsx
|
|
33
|
-
var
|
|
33
|
+
var M = {
|
|
34
34
|
position: "bottom",
|
|
35
35
|
alignment: "left",
|
|
36
36
|
alwaysVisible: !1,
|
|
37
37
|
showDone: !0,
|
|
38
38
|
doneOn: "blur"
|
|
39
|
-
},
|
|
39
|
+
}, N = {
|
|
40
40
|
options: {},
|
|
41
41
|
respAreaToolbar: () => {},
|
|
42
42
|
onHandleAreaChange: () => {}
|
|
43
|
-
},
|
|
43
|
+
}, P = [
|
|
44
44
|
"bold",
|
|
45
45
|
"italic",
|
|
46
46
|
"underline",
|
|
@@ -62,7 +62,7 @@ var A = {
|
|
|
62
62
|
"h3",
|
|
63
63
|
"undo",
|
|
64
64
|
"redo"
|
|
65
|
-
],
|
|
65
|
+
], F = {
|
|
66
66
|
bold: "bold",
|
|
67
67
|
italic: "italic",
|
|
68
68
|
underline: "underline",
|
|
@@ -71,8 +71,9 @@ var A = {
|
|
|
71
71
|
subscript: "subscript",
|
|
72
72
|
"bulleted-list": "bulletList",
|
|
73
73
|
"numbered-list": "orderedList",
|
|
74
|
-
table: "table"
|
|
75
|
-
|
|
74
|
+
table: "table",
|
|
75
|
+
image: "image"
|
|
76
|
+
}, I = {
|
|
76
77
|
"--white": "#fff",
|
|
77
78
|
"--black": "#2e2b29",
|
|
78
79
|
"--black-contrast": "#110f0e",
|
|
@@ -91,7 +92,7 @@ var A = {
|
|
|
91
92
|
"--red": "#ff5c33",
|
|
92
93
|
"--red-light": "#ffebe5",
|
|
93
94
|
"--shadow": "0px 12px 33px 0px rgba(0, 0, 0, .06),\n 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04)"
|
|
94
|
-
},
|
|
95
|
+
}, L = (e, t, n) => ({
|
|
95
96
|
role: "textbox",
|
|
96
97
|
"data-pie-editor": "true",
|
|
97
98
|
class: "mathjax_ignore",
|
|
@@ -100,55 +101,55 @@ var A = {
|
|
|
100
101
|
autocapitalize: e ? "on" : "off",
|
|
101
102
|
...t && { "aria-label": t },
|
|
102
103
|
...n && { "aria-labelledby": n }
|
|
103
|
-
}),
|
|
104
|
-
let { showParagraphs:
|
|
105
|
-
|
|
104
|
+
}), R = ["aria-label", "aria-labelledby"], z = (v) => {
|
|
105
|
+
let { showParagraphs: x, separateParagraphs: z } = v.pluginProps || {}, [fe, V] = _([]), [H, pe] = _(!1), { toolbarOpts: me } = v, U = p((e) => {
|
|
106
|
+
V((t) => {
|
|
106
107
|
let n = t.filter((t) => t.pos !== e);
|
|
107
|
-
return n.length === 0 &&
|
|
108
|
+
return n.length === 0 && pe(!1), n;
|
|
108
109
|
});
|
|
109
|
-
}, [
|
|
110
|
-
...
|
|
110
|
+
}, [V]), W = {
|
|
111
|
+
...M,
|
|
111
112
|
...me
|
|
112
|
-
},
|
|
113
|
+
}, G = p((e) => {
|
|
113
114
|
let t = e.getHTML();
|
|
114
|
-
|
|
115
|
+
v.markup !== t && v.onChange?.(t), W.doneOn === "blur" && v.onDone?.(t);
|
|
115
116
|
}, [
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
]),
|
|
121
|
-
...
|
|
122
|
-
...
|
|
123
|
-
onInlineDropdownToolbarClose:
|
|
124
|
-
}), [
|
|
125
|
-
let { customPlugins: e, ...t } =
|
|
117
|
+
v.markup,
|
|
118
|
+
v.onChange,
|
|
119
|
+
v.onDone,
|
|
120
|
+
W.doneOn
|
|
121
|
+
]), K = h(() => ({
|
|
122
|
+
...N,
|
|
123
|
+
...v.responseAreaProps,
|
|
124
|
+
onInlineDropdownToolbarClose: G
|
|
125
|
+
}), [v.responseAreaProps, G]), q = h(() => {
|
|
126
|
+
let { customPlugins: e, ...t } = v.pluginProps || {};
|
|
126
127
|
e ||= [];
|
|
127
|
-
let n = (
|
|
128
|
-
let n =
|
|
128
|
+
let n = (v.activePlugins || P)?.filter((e) => {
|
|
129
|
+
let n = ue[e] || e, r = t[n] || {};
|
|
129
130
|
return !r || !r.disabled;
|
|
130
131
|
});
|
|
131
|
-
return
|
|
132
|
+
return f(n, e, {
|
|
132
133
|
math: {},
|
|
133
|
-
textAlign:
|
|
134
|
+
textAlign: v.textAlign,
|
|
134
135
|
html: {},
|
|
135
|
-
extraCSSRules:
|
|
136
|
-
image: { ...
|
|
136
|
+
extraCSSRules: v.extraCSSRules || {},
|
|
137
|
+
image: { ...v.imageSupport },
|
|
137
138
|
toolbar: {},
|
|
138
139
|
table: {},
|
|
139
|
-
responseArea: { type:
|
|
140
|
-
languageCharacters:
|
|
140
|
+
responseArea: { type: K.type },
|
|
141
|
+
languageCharacters: v.languageCharactersProps,
|
|
141
142
|
keyPadCharacterRef: {},
|
|
142
143
|
setKeypadInteraction: {},
|
|
143
144
|
media: {}
|
|
144
145
|
});
|
|
145
|
-
}, [
|
|
146
|
-
|
|
147
|
-
plainText:
|
|
148
|
-
formatting:
|
|
146
|
+
}, [v, K.type]), J = g(null);
|
|
147
|
+
J.current = {
|
|
148
|
+
plainText: v.pluginProps?.pasteFormatting?.disabled === !0,
|
|
149
|
+
formatting: q.map((e) => F[e]).filter(Boolean)
|
|
149
150
|
};
|
|
150
|
-
let
|
|
151
|
-
|
|
151
|
+
let he = [
|
|
152
|
+
D.configure({
|
|
152
153
|
types: [
|
|
153
154
|
"heading",
|
|
154
155
|
"paragraph",
|
|
@@ -170,10 +171,13 @@ var A = {
|
|
|
170
171
|
"justify"
|
|
171
172
|
]
|
|
172
173
|
}),
|
|
173
|
-
|
|
174
|
-
e.configure({
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
C,
|
|
175
|
+
e.configure({
|
|
176
|
+
settings: () => J.current,
|
|
177
|
+
uploadImage: v.imageSupport && ie
|
|
178
|
+
}),
|
|
179
|
+
w.configure({ limit: v.charactersLimit || 1e6 }),
|
|
180
|
+
S.configure({
|
|
177
181
|
trailingNode: {
|
|
178
182
|
node: "paragraph",
|
|
179
183
|
notAfter: ["paragraph", "div"]
|
|
@@ -183,95 +187,95 @@ var A = {
|
|
|
183
187
|
linkOnPaste: !1
|
|
184
188
|
}
|
|
185
189
|
}),
|
|
186
|
-
u,
|
|
187
|
-
a,
|
|
188
190
|
se,
|
|
191
|
+
a,
|
|
192
|
+
ce,
|
|
189
193
|
ee,
|
|
190
194
|
te,
|
|
191
|
-
|
|
192
|
-
placeholder:
|
|
195
|
+
k.configure({
|
|
196
|
+
placeholder: v.placeholder,
|
|
193
197
|
showOnlyWhenEditable: !0,
|
|
194
198
|
showOnlyCurrent: !1,
|
|
195
199
|
includeChildren: !0
|
|
196
200
|
}),
|
|
197
201
|
n,
|
|
198
|
-
|
|
202
|
+
A,
|
|
199
203
|
i,
|
|
200
204
|
r,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
toolbarOpts:
|
|
208
|
-
math:
|
|
205
|
+
u.configure(K),
|
|
206
|
+
s.configure(K),
|
|
207
|
+
o.configure(K),
|
|
208
|
+
c.configure(K),
|
|
209
|
+
l.configure(K),
|
|
210
|
+
ne.configure({
|
|
211
|
+
toolbarOpts: W,
|
|
212
|
+
math: v.pluginProps?.math || {}
|
|
209
213
|
}),
|
|
210
|
-
w,
|
|
211
|
-
C,
|
|
212
214
|
E,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
+
T,
|
|
216
|
+
O,
|
|
217
|
+
re.configure({
|
|
218
|
+
toolbarOpts: W,
|
|
215
219
|
imageHandling: {
|
|
216
|
-
disableImageAlignmentButtons:
|
|
217
|
-
onDone: (e) =>
|
|
218
|
-
onDelete:
|
|
220
|
+
disableImageAlignmentButtons: v.disableImageAlignmentButtons,
|
|
221
|
+
onDone: (e) => v.onDone?.(e.getHTML()),
|
|
222
|
+
onDelete: v.imageSupport && v.imageSupport.delete && ((e) => {
|
|
219
223
|
let { src: t } = e.attrs;
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
v.imageSupport.delete(t, (t) => {
|
|
225
|
+
U(e.pos);
|
|
222
226
|
});
|
|
223
227
|
}),
|
|
224
|
-
insertImageRequested:
|
|
228
|
+
insertImageRequested: v.imageSupport && ((e, t, n) => {
|
|
225
229
|
let [r, i] = t, a = (t) => {
|
|
226
230
|
let n;
|
|
227
|
-
|
|
231
|
+
H && t && (n = v.onChange), U(i), n?.(e.getHTML());
|
|
228
232
|
};
|
|
229
|
-
e._insertingImage = !0,
|
|
230
|
-
let t = n(a), r =
|
|
233
|
+
e._insertingImage = !0, V((e) => [...e, r]), (() => {
|
|
234
|
+
let t = n(a), r = de(() => {
|
|
231
235
|
let t = () => window.removeEventListener("focus", r);
|
|
232
236
|
if (!e._insertingImage) {
|
|
233
237
|
t();
|
|
234
238
|
return;
|
|
235
239
|
}
|
|
236
|
-
|
|
240
|
+
U(i), e._insertingImage = !1, t();
|
|
237
241
|
}, 500);
|
|
238
|
-
window.addEventListener("focus", r),
|
|
242
|
+
window.addEventListener("focus", r), v.imageSupport.add(t);
|
|
239
243
|
})();
|
|
240
244
|
}),
|
|
241
|
-
maxImageWidth:
|
|
242
|
-
maxImageHeight:
|
|
245
|
+
maxImageWidth: v.maxImageWidth,
|
|
246
|
+
maxImageHeight: v.maxImageHeight
|
|
243
247
|
},
|
|
244
248
|
limit: 3
|
|
245
249
|
}),
|
|
246
|
-
|
|
247
|
-
oe.configure({ extraCSSRules:
|
|
248
|
-
], Y =
|
|
249
|
-
extensions:
|
|
250
|
+
ae.configure({ uploadSoundSupport: v.uploadSoundSupport }),
|
|
251
|
+
oe.configure({ extraCSSRules: v.extraCSSRules })
|
|
252
|
+
], Y = v.spellCheck !== !1, { ariaLabel: X, ariaLabelledBy: Z } = v, Q = y({
|
|
253
|
+
extensions: he,
|
|
250
254
|
immediatelyRender: !1,
|
|
251
255
|
editorProps: {
|
|
252
|
-
attributes:
|
|
256
|
+
attributes: L(Y, X, Z),
|
|
253
257
|
handleKeyDown(e, t) {
|
|
254
|
-
return
|
|
258
|
+
return v.onKeyDown ? v.onKeyDown(t) : !1;
|
|
255
259
|
}
|
|
256
260
|
},
|
|
257
|
-
editable: !
|
|
258
|
-
content: t(
|
|
261
|
+
editable: !v.disabled,
|
|
262
|
+
content: t(v.markup),
|
|
259
263
|
onUpdate: ({ editor: e, transaction: t }) => {
|
|
260
|
-
t.isDone &&
|
|
264
|
+
t.isDone && v.onChange?.(e.getHTML());
|
|
261
265
|
},
|
|
262
266
|
onBlur: ({ editor: e }) => {
|
|
263
|
-
e._insertingImage || e._toolbarOpened || e.isActive("inline_dropdown") || e.isActive("explicit_constructed_response") || !e.schema ||
|
|
267
|
+
e._insertingImage || e._toolbarOpened || e.isActive("inline_dropdown") || e.isActive("explicit_constructed_response") || !e.schema || G(e);
|
|
264
268
|
}
|
|
265
|
-
}, [
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}, [
|
|
269
|
-
Q?.setEditable(!
|
|
270
|
-
}, [
|
|
269
|
+
}, [v.charactersLimit]);
|
|
270
|
+
m(() => {
|
|
271
|
+
v.editorRef && v.editorRef(Q);
|
|
272
|
+
}, [v.editorRef, Q]), m(() => {
|
|
273
|
+
Q?.setEditable(!v.disabled);
|
|
274
|
+
}, [v.disabled, Q]), m(() => {
|
|
271
275
|
if (!Q) return;
|
|
272
|
-
let e = Q.options?.editorProps, t = e?.attributes || {}, n =
|
|
273
|
-
if (["spellcheck", ...
|
|
274
|
-
let r = Object.fromEntries(Object.entries(t).filter(([e]) => !
|
|
276
|
+
let e = Q.options?.editorProps, t = e?.attributes || {}, n = L(Y, X, Z);
|
|
277
|
+
if (["spellcheck", ...R].every((e) => t[e] === n[e])) return;
|
|
278
|
+
let r = Object.fromEntries(Object.entries(t).filter(([e]) => !R.includes(e)));
|
|
275
279
|
Q.setOptions({ editorProps: {
|
|
276
280
|
...e,
|
|
277
281
|
attributes: {
|
|
@@ -284,20 +288,20 @@ var A = {
|
|
|
284
288
|
X,
|
|
285
289
|
Z,
|
|
286
290
|
Q
|
|
287
|
-
]),
|
|
291
|
+
]), m(() => {
|
|
288
292
|
if (!Q) return;
|
|
289
|
-
let e = t(
|
|
293
|
+
let e = t(v.markup);
|
|
290
294
|
e !== Q.getHTML() && Q.commands.setContent(e, { emitUpdate: !1 });
|
|
291
|
-
}, [
|
|
292
|
-
Object.entries(
|
|
295
|
+
}, [v.markup, Q]), m(() => {
|
|
296
|
+
Object.entries(I).forEach(([e, t]) => {
|
|
293
297
|
document.documentElement.style.setProperty(e, t);
|
|
294
298
|
});
|
|
295
299
|
}, []);
|
|
296
|
-
let
|
|
300
|
+
let ge = b({
|
|
297
301
|
editor: Q,
|
|
298
302
|
selector: (e) => ({ isFocused: e.editor?.isFocused })
|
|
299
|
-
}), $ =
|
|
300
|
-
let { minWidth: e, width: t, maxWidth: n, minHeight: r, height: i, maxHeight: a } =
|
|
303
|
+
}), $ = h(() => {
|
|
304
|
+
let { minWidth: e, width: t, maxWidth: n, minHeight: r, height: i, maxHeight: a } = v;
|
|
301
305
|
return {
|
|
302
306
|
width: d(t),
|
|
303
307
|
minWidth: d(e),
|
|
@@ -306,25 +310,25 @@ var A = {
|
|
|
306
310
|
minHeight: d(r),
|
|
307
311
|
maxHeight: d(a)
|
|
308
312
|
};
|
|
309
|
-
}, [
|
|
310
|
-
return /* @__PURE__ */
|
|
311
|
-
...
|
|
312
|
-
activePlugins:
|
|
313
|
-
toolbarOpts:
|
|
314
|
-
editorState:
|
|
313
|
+
}, [v]);
|
|
314
|
+
return /* @__PURE__ */ j(le, {
|
|
315
|
+
...v,
|
|
316
|
+
activePlugins: q,
|
|
317
|
+
toolbarOpts: W,
|
|
318
|
+
editorState: ge,
|
|
315
319
|
editor: Q,
|
|
316
|
-
children: Q && /* @__PURE__ */
|
|
320
|
+
children: Q && /* @__PURE__ */ j(B, {
|
|
317
321
|
style: {
|
|
318
322
|
minHeight: $.minHeight,
|
|
319
323
|
height: $.height,
|
|
320
324
|
maxHeight: $.maxHeight
|
|
321
325
|
},
|
|
322
|
-
showParagraph:
|
|
323
|
-
separateParagraph:
|
|
326
|
+
showParagraph: x && !x.disabled,
|
|
327
|
+
separateParagraph: z && !z.disabled,
|
|
324
328
|
editor: Q
|
|
325
329
|
})
|
|
326
330
|
});
|
|
327
|
-
},
|
|
331
|
+
}, B = x(v, { shouldForwardProp: (e) => !["showParagraph", "separateParagraph"].includes(e) })(({ showParagraph: e, separateParagraph: t }) => ({
|
|
328
332
|
display: "flex",
|
|
329
333
|
outline: "none !important",
|
|
330
334
|
"& .ProseMirror": {
|
|
@@ -354,4 +358,4 @@ var A = {
|
|
|
354
358
|
}
|
|
355
359
|
}));
|
|
356
360
|
//#endregion
|
|
357
|
-
export {
|
|
361
|
+
export { z as EditableHtml, z as default };
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import { Node } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* Uploads the image pasted with `nodeKey` and a data URL src, as a pasted image file uploads.
|
|
4
|
+
* Resolves once the upload succeeds or fails.
|
|
5
|
+
*/
|
|
6
|
+
export declare function uploadPastedImage(editor: any, nodeKey: any): Promise<unknown>;
|
|
2
7
|
export declare const ImageUploadNode: Node<any, any>;
|
package/dist/extensions/image.js
CHANGED
|
@@ -7,7 +7,30 @@ import { Node as a, mergeAttributes as o } from "@tiptap/core";
|
|
|
7
7
|
import { Plugin as s } from "@tiptap/pm/state";
|
|
8
8
|
import { jsx as c } from "react/jsx-runtime";
|
|
9
9
|
//#region src/extensions/image.tsx
|
|
10
|
-
var l =
|
|
10
|
+
var l = (e) => {
|
|
11
|
+
let [t, n] = e.split(","), r = /^data:([^;,]+)/.exec(t)?.[1] ?? "image/png", i = Uint8Array.from(atob(n), (e) => e.charCodeAt(0));
|
|
12
|
+
return new File([i], `image.${r.split("/")[1]}`, { type: r });
|
|
13
|
+
};
|
|
14
|
+
function u(t, r, i, a, o = () => {}) {
|
|
15
|
+
let s = e(t, i);
|
|
16
|
+
if (!s) {
|
|
17
|
+
o();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
r(t, s, (e) => {
|
|
21
|
+
let r;
|
|
22
|
+
return r = new n(t, s, (t) => {
|
|
23
|
+
t || r?.updateNode({ loaded: !0 }), e(t), o();
|
|
24
|
+
}, !0), r.fileChosen(a), r;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function d(t, n) {
|
|
28
|
+
let r = t.extensionManager.extensions.find((e) => e.name === "imageUploadNode")?.options.imageHandling?.insertImageRequested, i = e(t, n)?.[0].attrs.src;
|
|
29
|
+
return new Promise((e) => {
|
|
30
|
+
r && i ? u(t, r, n, l(i), e) : e();
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
var f = a.create({
|
|
11
34
|
name: "imageUploadNode",
|
|
12
35
|
group: "block",
|
|
13
36
|
atom: !0,
|
|
@@ -45,33 +68,26 @@ var l = a.create({
|
|
|
45
68
|
}) };
|
|
46
69
|
},
|
|
47
70
|
addProseMirrorPlugins() {
|
|
48
|
-
let
|
|
49
|
-
return [new s({ props: { handlePaste(
|
|
50
|
-
let
|
|
51
|
-
if (!
|
|
52
|
-
let
|
|
53
|
-
if (!
|
|
54
|
-
let
|
|
55
|
-
return
|
|
56
|
-
let t =
|
|
57
|
-
|
|
71
|
+
let e = this.editor, n = this.options;
|
|
72
|
+
return [new s({ props: { handlePaste(r, i) {
|
|
73
|
+
let a = Array.from(i.clipboardData?.items || []).find((e) => e.kind === "file" && e.type.startsWith("image/"));
|
|
74
|
+
if (!a) return !1;
|
|
75
|
+
let o = a.getAsFile();
|
|
76
|
+
if (!o) return !1;
|
|
77
|
+
let s = n?.imageHandling?.insertImageRequested, c = t(), l = new FileReader();
|
|
78
|
+
return l.onload = () => {
|
|
79
|
+
let t = l.result;
|
|
80
|
+
typeof t == "string" && (e.commands.insertContent({
|
|
58
81
|
type: "imageUploadNode",
|
|
59
82
|
attrs: {
|
|
60
83
|
src: t,
|
|
61
|
-
loaded: !
|
|
62
|
-
nodeKey:
|
|
84
|
+
loaded: !s,
|
|
85
|
+
nodeKey: c
|
|
63
86
|
}
|
|
64
|
-
}),
|
|
65
|
-
|
|
66
|
-
i && l(r, i, (e) => {
|
|
67
|
-
let t;
|
|
68
|
-
return t = new n(r, i, (n) => {
|
|
69
|
-
n || t?.updateNode({ loaded: !0 }), e(n);
|
|
70
|
-
}, !0), t.fileChosen(c), t;
|
|
71
|
-
});
|
|
72
|
-
}, d.readAsDataURL(c), !0;
|
|
87
|
+
}), s && u(e, s, c, o));
|
|
88
|
+
}, l.readAsDataURL(o), !0;
|
|
73
89
|
} } })];
|
|
74
90
|
}
|
|
75
91
|
});
|
|
76
92
|
//#endregion
|
|
77
|
-
export {
|
|
93
|
+
export { f as ImageUploadNode, d as uploadPastedImage };
|
package/dist/external-paste.d.ts
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core';
|
|
1
|
+
import { type Editor, Extension } from '@tiptap/core';
|
|
2
2
|
/** The formatting that content pasted from outside a PIE editor can keep, by mark or node name. */
|
|
3
|
-
export declare const PASTED_FORMATTING: readonly ["bold", "italic", "underline", "strike", "superscript", "subscript", "bulletList", "orderedList", "table"];
|
|
3
|
+
export declare const PASTED_FORMATTING: readonly ["bold", "italic", "underline", "strike", "superscript", "subscript", "bulletList", "orderedList", "table", "image"];
|
|
4
4
|
export type PastedFormatting = (typeof PASTED_FORMATTING)[number];
|
|
5
5
|
export type ExternalPasteSettings = {
|
|
6
6
|
/** Paste as plain text, as the Slate editor did. Math copied from rendered PIE content stays math. */
|
|
7
7
|
plainText: boolean;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* The formatting a paste keeps. The rest becomes text: a list its items, a table its rows.
|
|
10
|
+
* `image` keeps the pictures Word puts in its HTML as data URLs, in an editor with image upload
|
|
11
|
+
* nodes. Other images go.
|
|
12
|
+
*/
|
|
9
13
|
formatting: readonly PastedFormatting[];
|
|
10
14
|
};
|
|
11
15
|
export type ExternalPasteOptions = {
|
|
12
16
|
/** Read at each paste and drop, so a mounted editor follows a change of toolbar or setting. */
|
|
13
17
|
settings: () => ExternalPasteSettings;
|
|
18
|
+
/**
|
|
19
|
+
* Uploads the picture pasted as the image upload node with `nodeKey`, which shows its data URL
|
|
20
|
+
* until the upload replaces it, and resolves once the upload finishes. Pictures upload one at a
|
|
21
|
+
* time, as a host on pie-player-components serves one upload at a time. Without it, the data
|
|
22
|
+
* URL is the picture's src.
|
|
23
|
+
*/
|
|
24
|
+
uploadImage?: (editor: Editor, nodeKey: string) => Promise<void>;
|
|
14
25
|
};
|
|
15
26
|
/**
|
|
16
27
|
* Pastes and drops content from outside a PIE editor, such as from Word or Google Docs, with its
|
|
@@ -18,8 +29,9 @@ export type ExternalPasteOptions = {
|
|
|
18
29
|
* superscript, subscript, lists and tables in `formatting`. Its fonts, sizes, colours, alignment,
|
|
19
30
|
* headings, links and class names go, which TextStyleKit, TextAlign and CSSMark would otherwise keep
|
|
20
31
|
* (PIE-1145). Word for Windows and Mac copies lists as styled paragraphs, which are rebuilt as
|
|
21
|
-
* lists first.
|
|
22
|
-
*
|
|
32
|
+
* lists first. Word's pictures paste as image upload nodes when `formatting` has `image`, and
|
|
33
|
+
* upload through `uploadImage`. With `plainText` set it pastes plain text. Copies from a PIE editor
|
|
34
|
+
* and pasted image files are left to ProseMirror and the image upload handler.
|
|
23
35
|
*
|
|
24
36
|
* Mirrored in `packages/lib-svelte/editable-html-tiptap-svelte/src/external-paste.ts`.
|
|
25
37
|
*/
|
package/dist/external-paste.js
CHANGED
|
@@ -11,14 +11,22 @@ var a = [
|
|
|
11
11
|
"subscript",
|
|
12
12
|
"bulletList",
|
|
13
13
|
"orderedList",
|
|
14
|
-
"table"
|
|
15
|
-
|
|
14
|
+
"table",
|
|
15
|
+
"image"
|
|
16
|
+
], o = (e) => Array.from(e.items ?? []).some((e) => e.kind === "file" && e.type.startsWith("image/")), s = (e, t) => new DOMParser().parseFromString(e, "text/html").querySelector(t) !== null, c = (e) => e.includes("data-pm-slice") && s(e, "[data-pm-slice]"), l = (e) => /data-latex|data-type="?mathml/.test(e) && s(e, "[data-latex], [data-type=\"mathml\"]"), u = null, d = /^data:image\/(?:png|jpeg|gif|webp);base64,/i, f = () => `img-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
17
|
+
function p(e) {
|
|
18
|
+
if (!e.includes("data:image/")) return e;
|
|
19
|
+
let t = new DOMParser().parseFromString(e, "text/html");
|
|
20
|
+
for (let e of Array.from(t.body.querySelectorAll("img"))) d.test(e.getAttribute("src") ?? "") && e.setAttribute("data-type", "image-upload-node");
|
|
21
|
+
return t.body.innerHTML;
|
|
22
|
+
}
|
|
23
|
+
var m = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"), h = (e) => e.replace(/\r*\n|\r/g, "\n").replace(/\n+$/, ""), g = (e) => {
|
|
16
24
|
let t = [];
|
|
17
25
|
return e.forEach((e) => {
|
|
18
26
|
t.push(e);
|
|
19
27
|
}), t;
|
|
20
28
|
};
|
|
21
|
-
function
|
|
29
|
+
function _(e, t) {
|
|
22
30
|
let n = e.topNodeType.create(null, t), r = (e) => {
|
|
23
31
|
let t = 0;
|
|
24
32
|
for (let r = n[e]; r && !r.isLeaf && !r.type.spec.isolating; r = r[e]) t += 1;
|
|
@@ -26,7 +34,7 @@ function m(e, t) {
|
|
|
26
34
|
};
|
|
27
35
|
return t.length ? n.slice(r("firstChild"), n.content.size - r("lastChild"), !0) : n.slice(0, 0);
|
|
28
36
|
}
|
|
29
|
-
var
|
|
37
|
+
var v = [
|
|
30
38
|
[1e3, "m"],
|
|
31
39
|
[900, "cm"],
|
|
32
40
|
[500, "d"],
|
|
@@ -40,19 +48,19 @@ var h = [
|
|
|
40
48
|
[5, "v"],
|
|
41
49
|
[4, "iv"],
|
|
42
50
|
[1, "i"]
|
|
43
|
-
],
|
|
51
|
+
], y = (e) => v.reduce(({ numeral: e, rest: t }, [n, r]) => ({
|
|
44
52
|
numeral: e + r.repeat(Math.floor(t / n)),
|
|
45
53
|
rest: t % n
|
|
46
54
|
}), {
|
|
47
55
|
numeral: "",
|
|
48
56
|
rest: e
|
|
49
|
-
}).numeral,
|
|
50
|
-
function
|
|
57
|
+
}).numeral, b = (e) => (e > 26 ? b(Math.floor((e - 1) / 26)) : "") + String.fromCharCode(97 + (e - 1) % 26);
|
|
58
|
+
function x(e, t) {
|
|
51
59
|
if (t < 1 || !e || !/^[aAiI]$/.test(e)) return String(t);
|
|
52
|
-
let n = /^[aA]$/.test(e) ?
|
|
60
|
+
let n = /^[aA]$/.test(e) ? b(t) : y(t);
|
|
53
61
|
return e === e.toUpperCase() ? n.toUpperCase() : n;
|
|
54
62
|
}
|
|
55
|
-
function
|
|
63
|
+
function S(e) {
|
|
56
64
|
let t = e?.getData("text/html");
|
|
57
65
|
if (!e || !t || c(t)) return null;
|
|
58
66
|
let n = e.getData("text/plain"), r = Array.from(e.types).includes("text/rtf") && n.trim() !== "";
|
|
@@ -61,55 +69,67 @@ function y(e) {
|
|
|
61
69
|
html: t
|
|
62
70
|
};
|
|
63
71
|
}
|
|
64
|
-
var
|
|
65
|
-
let { schema:
|
|
72
|
+
var C = (e, t = null) => (n, r) => {
|
|
73
|
+
let { schema: i } = r, { paragraph: a, hardBreak: o, math: s, imageUploadNode: c } = i.nodes, l = (e) => a.create(null, e), u = (t) => t.filter((t) => e.has(t.type.name)).map((e) => e.type.create()), p = (e) => g(e).flatMap((e) => {
|
|
66
74
|
if (e.isText) {
|
|
67
|
-
let t =
|
|
68
|
-
return (e.text ?? "").split("\n").flatMap((e, n) => [...n &&
|
|
75
|
+
let t = u(e.marks);
|
|
76
|
+
return (e.text ?? "").split("\n").flatMap((e, n) => [...n && o ? [o.create(null, null, t)] : [], ...e ? [i.text(e, t)] : []]);
|
|
69
77
|
}
|
|
70
|
-
return e.type ===
|
|
71
|
-
}),
|
|
78
|
+
return e.type === o || s && e.type === s ? [e.mark(u(e.marks))] : e.isLeaf ? [] : p(e);
|
|
79
|
+
}), m = (e) => {
|
|
80
|
+
let { src: n, width: r, height: i, alt: a } = e.attrs;
|
|
81
|
+
if (!t || !d.test(n ?? "")) return [];
|
|
82
|
+
let o = f();
|
|
83
|
+
return t.keys.push(o), [e.type.create({
|
|
84
|
+
src: n,
|
|
85
|
+
width: r,
|
|
86
|
+
height: i,
|
|
87
|
+
alt: a,
|
|
88
|
+
nodeKey: o,
|
|
89
|
+
loaded: !t.upload
|
|
90
|
+
})];
|
|
91
|
+
}, h = (e) => {
|
|
72
92
|
let t = [];
|
|
73
|
-
return e.descendants((e) => e.isTextblock ? (t.length && t.push(
|
|
74
|
-
},
|
|
93
|
+
return e.descendants((e) => e.isTextblock ? (t.length && t.push(i.text(" ")), t.push(...p(e)), !1) : !0), t;
|
|
94
|
+
}, v = (t) => {
|
|
75
95
|
let n = t.type.name === "orderedList";
|
|
76
96
|
if (e.has(t.type.name)) {
|
|
77
|
-
let e =
|
|
97
|
+
let e = g(t).flatMap((e) => e.type.createAndFill(null, C(e)) ?? []), r = n ? {
|
|
78
98
|
start: t.attrs.start,
|
|
79
99
|
type: t.attrs.type
|
|
80
100
|
} : null;
|
|
81
101
|
return e.length ? [t.type.create(r, e)] : [];
|
|
82
102
|
}
|
|
83
|
-
let
|
|
84
|
-
return
|
|
85
|
-
let o =
|
|
86
|
-
return
|
|
87
|
-
|
|
88
|
-
...
|
|
89
|
-
...
|
|
103
|
+
let r = n ? t.attrs.start ?? 1 : 0;
|
|
104
|
+
return g(t).flatMap((e) => {
|
|
105
|
+
let o = i.text(n ? `${x(t.attrs.type, r++)}. ` : "• "), [s, ...c] = C(e);
|
|
106
|
+
return s?.type === a ? [l([o, ...g(s)]), ...c] : [
|
|
107
|
+
l([o]),
|
|
108
|
+
...s ? [s] : [],
|
|
109
|
+
...c
|
|
90
110
|
];
|
|
91
111
|
});
|
|
92
|
-
},
|
|
112
|
+
}, y = (t) => {
|
|
93
113
|
let n = t.attrs.caption ?? null;
|
|
94
114
|
if (e.has("table")) {
|
|
95
|
-
let e =
|
|
96
|
-
let t =
|
|
115
|
+
let e = g(t).flatMap((e) => {
|
|
116
|
+
let t = g(e).flatMap((e) => {
|
|
97
117
|
let { colspan: t, rowspan: n, scope: r } = e.attrs;
|
|
98
118
|
return e.type.createAndFill({
|
|
99
119
|
colspan: t,
|
|
100
120
|
rowspan: n,
|
|
101
121
|
scope: r
|
|
102
|
-
},
|
|
122
|
+
}, C(e)) ?? [];
|
|
103
123
|
});
|
|
104
124
|
return t.length ? [e.type.create(null, t)] : [];
|
|
105
125
|
});
|
|
106
126
|
return e.length ? [t.type.create({ caption: n }, e)] : [];
|
|
107
127
|
}
|
|
108
|
-
return [...n ? [
|
|
109
|
-
},
|
|
110
|
-
return
|
|
128
|
+
return [...n ? [l([i.text(n)])] : [], ...g(t).map((e) => l(g(e).flatMap((e, t) => t ? [i.text(" "), ...h(e)] : h(e))))];
|
|
129
|
+
}, b = (e) => /^\s+$/.test(e.textContent) && g(e).every((e) => e.isText), S = (e) => !!t && !!e && e.type === c, C = (e) => g(e).flatMap((e, t, n) => e.isTextblock && !e.content.size && (S(n[t - 1]) || S(n[t + 1])) ? [] : e.isTextblock && b(e) ? [l([i.text(e.textContent)])] : e.isTextblock ? [l(p(e))] : e.type.spec.tableRole === "table" ? y(e) : e.type.name === "bulletList" || e.type.name === "orderedList" ? v(e) : S(e) ? m(e) : e.isLeaf ? [] : C(e));
|
|
130
|
+
return _(i, n.content.firstChild?.isInline ? [l(p(n.content))] : C(n.content));
|
|
111
131
|
};
|
|
112
|
-
function
|
|
132
|
+
function w(e, t) {
|
|
113
133
|
let { schema: n } = t, r = t.selection.$from.marks(), i = (e) => {
|
|
114
134
|
let t = [];
|
|
115
135
|
return e.descendants((e) => (e.isTextblock && t.length && t.push(n.text(" ", r)), e.isText && e.text && t.push(n.text(e.text, r)), e.type === n.nodes.math && t.push(e.mark([])), !e.isInline)), t;
|
|
@@ -122,9 +142,9 @@ function x(e, t) {
|
|
|
122
142
|
}), a.push(t.flatMap((e, t) => t ? [n.text(" ", r), ...e] : e)), !1;
|
|
123
143
|
}
|
|
124
144
|
return e.isTextblock ? (a.push(i(e)), !1) : !0;
|
|
125
|
-
}),
|
|
145
|
+
}), _(n, a.map((e) => n.nodes.paragraph.create(null, e)));
|
|
126
146
|
}
|
|
127
|
-
function
|
|
147
|
+
function T(e, t, n) {
|
|
128
148
|
u = n;
|
|
129
149
|
try {
|
|
130
150
|
e.pasteHTML(t);
|
|
@@ -132,34 +152,43 @@ function S(e, t, n) {
|
|
|
132
152
|
u = null;
|
|
133
153
|
}
|
|
134
154
|
}
|
|
135
|
-
function
|
|
136
|
-
let { selection:
|
|
137
|
-
if ("$anchorCell" in
|
|
138
|
-
let e =
|
|
155
|
+
function E(t, { text: n, html: r }, i, a) {
|
|
156
|
+
let { selection: o, schema: c } = t.state, u = new Set(i.plainText ? [] : i.formatting);
|
|
157
|
+
if ("$anchorCell" in o && !(u.has("table") && s(r, "table"))) {
|
|
158
|
+
let e = h(n).split("\n").map((e) => `<tr>${e.split(" ").map((e) => `<td>${m(e)}</td>`).join("")}</tr>`);
|
|
139
159
|
t.pasteHTML(`<table><tbody>${e.join("")}</tbody></table>`);
|
|
140
160
|
return;
|
|
141
161
|
}
|
|
142
162
|
if (!i.plainText) {
|
|
143
|
-
|
|
163
|
+
let n = u.has("image") && c.nodes.imageUploadNode ? {
|
|
164
|
+
keys: [],
|
|
165
|
+
upload: !!a
|
|
166
|
+
} : null;
|
|
167
|
+
T(t, e(n ? p(r) : r), C(u, n));
|
|
168
|
+
let i = Promise.resolve();
|
|
169
|
+
for (let e of n?.keys ?? []) i = i.then(() => a?.(e));
|
|
144
170
|
return;
|
|
145
171
|
}
|
|
146
|
-
if (
|
|
147
|
-
|
|
172
|
+
if (c.nodes.math && l(r)) {
|
|
173
|
+
T(t, r, w);
|
|
148
174
|
return;
|
|
149
175
|
}
|
|
150
|
-
t.pasteText(
|
|
176
|
+
t.pasteText(o.$from.parent.type.spec.code ? h(n) : h(n).replace(/^$/gm, "\xA0"));
|
|
151
177
|
}
|
|
152
|
-
var
|
|
178
|
+
var D = t.create({
|
|
153
179
|
name: "externalPaste",
|
|
154
180
|
priority: 1e3,
|
|
155
181
|
addOptions() {
|
|
156
|
-
return {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
182
|
+
return {
|
|
183
|
+
settings: () => ({
|
|
184
|
+
plainText: !1,
|
|
185
|
+
formatting: a
|
|
186
|
+
}),
|
|
187
|
+
uploadImage: void 0
|
|
188
|
+
};
|
|
160
189
|
},
|
|
161
190
|
addProseMirrorPlugins() {
|
|
162
|
-
let { settings: e } = this.options;
|
|
191
|
+
let { settings: e, uploadImage: t } = this.options, { editor: a } = this, o = t ? (e) => t(a, e) : null;
|
|
163
192
|
return [new n({
|
|
164
193
|
key: new r("externalPaste"),
|
|
165
194
|
props: {
|
|
@@ -167,19 +196,19 @@ var w = t.create({
|
|
|
167
196
|
return u ? u(e, t.state) : e;
|
|
168
197
|
},
|
|
169
198
|
handlePaste(t, n) {
|
|
170
|
-
let r =
|
|
171
|
-
return r === null ? !1 : (
|
|
199
|
+
let r = S(n.clipboardData);
|
|
200
|
+
return r === null ? !1 : (E(t, r, e(), o), !0);
|
|
172
201
|
},
|
|
173
202
|
handleDrop(t, n) {
|
|
174
|
-
let r = t.dragging ? null :
|
|
203
|
+
let r = t.dragging ? null : S(n.dataTransfer), a = r === null ? null : t.posAtCoords({
|
|
175
204
|
left: n.clientX,
|
|
176
205
|
top: n.clientY
|
|
177
206
|
});
|
|
178
|
-
return r === null || !a ? !1 : (t.dispatch(t.state.tr.setSelection(i.near(t.state.doc.resolve(a.pos)))),
|
|
207
|
+
return r === null || !a ? !1 : (t.dispatch(t.state.tr.setSelection(i.near(t.state.doc.resolve(a.pos)))), E(t, r, e(), o), t.focus(), !0);
|
|
179
208
|
}
|
|
180
209
|
}
|
|
181
210
|
})];
|
|
182
211
|
}
|
|
183
212
|
});
|
|
184
213
|
//#endregion
|
|
185
|
-
export {
|
|
214
|
+
export { D as ExternalPaste, a as PASTED_FORMATTING };
|