dn-react-router-toolkit 0.2.4 → 0.2.6
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/file/cdn.d.mts +3 -2
- package/dist/file/cdn.d.ts +3 -2
- package/dist/file/client/drop_file_input.js +36 -10
- package/dist/file/client/drop_file_input.mjs +36 -10
- package/dist/file/client/file_uploader.js +36 -10
- package/dist/file/client/file_uploader.mjs +36 -10
- package/dist/file/client/metadata.d.mts +5 -1
- package/dist/file/client/metadata.d.ts +5 -1
- package/dist/file/client/metadata.js +36 -10
- package/dist/file/client/metadata.mjs +36 -10
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -0
- package/dist/index.mjs +6 -0
- package/dist/sleep.d.mts +3 -0
- package/dist/sleep.d.ts +3 -0
- package/dist/sleep.js +32 -0
- package/dist/sleep.mjs +7 -0
- package/dist/text_editor/attach_media.d.mts +16 -0
- package/dist/text_editor/attach_media.d.ts +16 -0
- package/dist/text_editor/attach_media.js +237 -0
- package/dist/text_editor/attach_media.mjs +210 -0
- package/dist/text_editor/plugins/drag_and_drop.d.mts +13 -0
- package/dist/text_editor/plugins/drag_and_drop.d.ts +13 -0
- package/dist/text_editor/plugins/drag_and_drop.js +59 -0
- package/dist/text_editor/plugins/drag_and_drop.mjs +34 -0
- package/dist/text_editor/plugins/keymap.d.mts +5 -0
- package/dist/text_editor/plugins/keymap.d.ts +5 -0
- package/dist/text_editor/plugins/keymap.js +40 -0
- package/dist/text_editor/plugins/keymap.mjs +15 -0
- package/dist/text_editor/plugins/placehoder.d.mts +5 -0
- package/dist/text_editor/plugins/placehoder.d.ts +5 -0
- package/dist/text_editor/plugins/placehoder.js +112 -0
- package/dist/text_editor/plugins/placehoder.mjs +87 -0
- package/dist/text_editor/plugins/trailing_paragraph.d.mts +5 -0
- package/dist/text_editor/plugins/trailing_paragraph.d.ts +5 -0
- package/dist/text_editor/plugins/trailing_paragraph.js +46 -0
- package/dist/text_editor/plugins/trailing_paragraph.mjs +21 -0
- package/dist/text_editor/plugins/upload_placeholder.d.mts +7 -0
- package/dist/text_editor/plugins/upload_placeholder.d.ts +7 -0
- package/dist/text_editor/plugins/upload_placeholder.js +94 -0
- package/dist/text_editor/plugins/upload_placeholder.mjs +68 -0
- package/dist/text_editor/schema.d.mts +9 -0
- package/dist/text_editor/schema.d.ts +9 -0
- package/dist/text_editor/schema.js +354 -0
- package/dist/text_editor/schema.mjs +319 -0
- package/dist/text_editor/text_editor.d.mts +44 -0
- package/dist/text_editor/text_editor.d.ts +44 -0
- package/dist/text_editor/text_editor.js +830 -0
- package/dist/text_editor/text_editor.mjs +802 -0
- package/package.json +14 -2
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/text_editor/text_editor.tsx
|
|
31
|
+
var text_editor_exports = {};
|
|
32
|
+
__export(text_editor_exports, {
|
|
33
|
+
default: () => createTextEditor
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(text_editor_exports);
|
|
36
|
+
var import_react2 = __toESM(require("react"));
|
|
37
|
+
var import_prosemirror_state4 = require("prosemirror-state");
|
|
38
|
+
var import_prosemirror_view2 = require("prosemirror-view");
|
|
39
|
+
var import_react3 = require("react");
|
|
40
|
+
var import_prosemirror_commands = require("prosemirror-commands");
|
|
41
|
+
var import_prosemirror_keymap = require("prosemirror-keymap");
|
|
42
|
+
|
|
43
|
+
// src/text_editor/plugins/drag_and_drop.tsx
|
|
44
|
+
var import_prosemirror_state = require("prosemirror-state");
|
|
45
|
+
function dragAndDropPlugin({
|
|
46
|
+
attachMedia
|
|
47
|
+
}) {
|
|
48
|
+
return new import_prosemirror_state.Plugin({
|
|
49
|
+
props: {
|
|
50
|
+
handleDOMEvents: {
|
|
51
|
+
drop(view, event) {
|
|
52
|
+
const files = event.dataTransfer?.files;
|
|
53
|
+
if (!files || files.length === 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
const pos = view.state.selection.$from.pos || view.posAtCoords({
|
|
58
|
+
left: event.clientX,
|
|
59
|
+
top: event.clientY
|
|
60
|
+
})?.pos || null;
|
|
61
|
+
if (pos === null) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const medias = Array.from(files).filter(
|
|
65
|
+
(file) => file.type.startsWith("image/") || file.type.startsWith("video/")
|
|
66
|
+
);
|
|
67
|
+
attachMedia(view, medias);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/text_editor/plugins/upload_placeholder.tsx
|
|
76
|
+
var import_prosemirror_state2 = require("prosemirror-state");
|
|
77
|
+
var import_prosemirror_view = require("prosemirror-view");
|
|
78
|
+
var uploadPlaceholderPlugin = new import_prosemirror_state2.Plugin({
|
|
79
|
+
state: {
|
|
80
|
+
init() {
|
|
81
|
+
return import_prosemirror_view.DecorationSet.empty;
|
|
82
|
+
},
|
|
83
|
+
apply(tr, set) {
|
|
84
|
+
set = set.map(tr.mapping, tr.doc);
|
|
85
|
+
const action = tr.getMeta(this);
|
|
86
|
+
if (action && action.add) {
|
|
87
|
+
const { type, width, height } = action.add;
|
|
88
|
+
const widget = document.createElement("div");
|
|
89
|
+
widget.className = "upload-placeholder";
|
|
90
|
+
widget.style.width = `100%`;
|
|
91
|
+
if (type.startsWith("image/") || type.startsWith("video/")) {
|
|
92
|
+
widget.style.aspectRatio = `${width} / ${height}`;
|
|
93
|
+
widget.style.maxWidth = `${width}px`;
|
|
94
|
+
} else {
|
|
95
|
+
widget.style.height = "80px";
|
|
96
|
+
}
|
|
97
|
+
const progress = document.createElement("div");
|
|
98
|
+
progress.className = "upload-progress";
|
|
99
|
+
widget.appendChild(progress);
|
|
100
|
+
const deco = import_prosemirror_view.Decoration.widget(action.add.pos, widget, {
|
|
101
|
+
id: action.add.id
|
|
102
|
+
});
|
|
103
|
+
set = set.add(tr.doc, [deco]);
|
|
104
|
+
} else if (action && action.progress) {
|
|
105
|
+
const found = set.find(
|
|
106
|
+
void 0,
|
|
107
|
+
void 0,
|
|
108
|
+
(spec) => spec.id === action.progress.id
|
|
109
|
+
);
|
|
110
|
+
if (found.length) {
|
|
111
|
+
const widget = found[0].type.toDOM;
|
|
112
|
+
const progress = widget.querySelector(".upload-progress");
|
|
113
|
+
if (progress) {
|
|
114
|
+
progress.innerHTML = `${Math.round(action.progress.progress)}%`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else if (action && action.remove) {
|
|
118
|
+
set = set.remove(
|
|
119
|
+
set.find(void 0, void 0, (spec) => spec.id === action.remove.id)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return set;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
props: {
|
|
126
|
+
decorations(state) {
|
|
127
|
+
return this.getState(state);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
var findPlaceholder = (state, id) => {
|
|
132
|
+
const decos = uploadPlaceholderPlugin.getState(state);
|
|
133
|
+
if (!decos) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const found = decos.find(void 0, void 0, (spec) => spec.id === id);
|
|
137
|
+
return found.length ? found[0].from : null;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// src/file/client/metadata.ts
|
|
141
|
+
function generateMetadata(blob, {
|
|
142
|
+
uploadBlob
|
|
143
|
+
} = {}) {
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
if (blob.type.startsWith("image/")) {
|
|
146
|
+
const img = new Image();
|
|
147
|
+
img.src = URL.createObjectURL(blob);
|
|
148
|
+
img.onload = () => {
|
|
149
|
+
resolve({
|
|
150
|
+
width: img.width,
|
|
151
|
+
height: img.height
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
img.onerror = () => resolve({});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (blob.type.startsWith("video/")) {
|
|
158
|
+
const video = document.createElement("video");
|
|
159
|
+
video.onloadeddata = () => {
|
|
160
|
+
const canvas = document.createElement("canvas");
|
|
161
|
+
canvas.width = video.videoWidth;
|
|
162
|
+
canvas.height = video.videoHeight;
|
|
163
|
+
const context = canvas.getContext("2d");
|
|
164
|
+
if (!context || !uploadBlob) {
|
|
165
|
+
return resolve({
|
|
166
|
+
width: video.videoWidth,
|
|
167
|
+
height: video.videoHeight
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
video.addEventListener("seeked", () => {
|
|
171
|
+
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
|
|
172
|
+
canvas.toBlob((blob2) => {
|
|
173
|
+
if (!blob2) {
|
|
174
|
+
return resolve({
|
|
175
|
+
width: video.videoWidth,
|
|
176
|
+
height: video.videoHeight
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
uploadBlob(blob2, "poster").then(({ url }) => {
|
|
180
|
+
resolve({
|
|
181
|
+
width: video.videoWidth,
|
|
182
|
+
height: video.videoHeight,
|
|
183
|
+
poster: url
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}, "image/jpeg");
|
|
187
|
+
});
|
|
188
|
+
video.currentTime = 0;
|
|
189
|
+
};
|
|
190
|
+
video.onerror = () => resolve({});
|
|
191
|
+
video.src = URL.createObjectURL(blob);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
resolve({});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/file/cdn.ts
|
|
199
|
+
var createCDN = (origin) => {
|
|
200
|
+
return (key, { width } = {}) => {
|
|
201
|
+
return key ? `${origin}/${key}${width ? `?w=${width}` : ""}` : void 0;
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// src/text_editor/attach_media.tsx
|
|
206
|
+
function createAttachMedia({
|
|
207
|
+
schema,
|
|
208
|
+
cdnOrigin,
|
|
209
|
+
fileUploader
|
|
210
|
+
}) {
|
|
211
|
+
const cdn = createCDN(cdnOrigin);
|
|
212
|
+
const attachEachMedia = async (view, file, pos) => {
|
|
213
|
+
const metadata = await generateMetadata(file, {
|
|
214
|
+
uploadBlob: (blob, type) => fileUploader.uploadBlob(blob, type).then(({ key }) => ({
|
|
215
|
+
url: cdn(key)
|
|
216
|
+
}))
|
|
217
|
+
});
|
|
218
|
+
const id = {};
|
|
219
|
+
view.focus();
|
|
220
|
+
const tr = view.state.tr;
|
|
221
|
+
if (!tr.selection.empty) {
|
|
222
|
+
tr.deleteSelection();
|
|
223
|
+
}
|
|
224
|
+
tr.setMeta(uploadPlaceholderPlugin, {
|
|
225
|
+
add: {
|
|
226
|
+
id,
|
|
227
|
+
pos: pos ?? tr.selection.from,
|
|
228
|
+
type: file.type,
|
|
229
|
+
...metadata
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
view.dispatch(tr);
|
|
233
|
+
const $pos = findPlaceholder(view.state, id);
|
|
234
|
+
if (!$pos) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const { name, key } = await fileUploader.uploadFile(file);
|
|
239
|
+
const src = cdn(key);
|
|
240
|
+
const tr2 = view.state.tr.setMeta(uploadPlaceholderPlugin, {
|
|
241
|
+
remove: { id }
|
|
242
|
+
});
|
|
243
|
+
const media = (() => {
|
|
244
|
+
if (file.type.startsWith("image/")) {
|
|
245
|
+
return schema.nodes.image.create({
|
|
246
|
+
src,
|
|
247
|
+
alt: name,
|
|
248
|
+
width: metadata.width,
|
|
249
|
+
height: metadata.height
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
if (file.type.startsWith("video/")) {
|
|
253
|
+
return schema.nodes.video.create({
|
|
254
|
+
src,
|
|
255
|
+
width: metadata.width,
|
|
256
|
+
height: metadata.height,
|
|
257
|
+
poster: metadata.poster
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
})();
|
|
261
|
+
if (!media) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
view.dispatch(tr2.replaceWith($pos, $pos, media));
|
|
265
|
+
return media;
|
|
266
|
+
} catch (e) {
|
|
267
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
return async (view, medias, pos) => {
|
|
271
|
+
const result = [];
|
|
272
|
+
for (let i = 0; i < medias.length; i++) {
|
|
273
|
+
const file = medias[i];
|
|
274
|
+
const item = await attachEachMedia(view, file, pos);
|
|
275
|
+
if (item) {
|
|
276
|
+
result.push(item);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/text_editor/plugins/placehoder.tsx
|
|
284
|
+
var import_prosemirror_state3 = require("prosemirror-state");
|
|
285
|
+
var getFirstChildDescendants = (view) => {
|
|
286
|
+
const nodes = [];
|
|
287
|
+
view.state.doc?.descendants((n) => {
|
|
288
|
+
nodes.push(n);
|
|
289
|
+
});
|
|
290
|
+
return nodes;
|
|
291
|
+
};
|
|
292
|
+
function placeholderPlugin(text) {
|
|
293
|
+
const update = (view) => {
|
|
294
|
+
const decos = uploadPlaceholderPlugin.getState(view.state);
|
|
295
|
+
if (decos && decos.find().length > 0 || view.state.doc.content.content.some((e) => e.type.name !== "paragraph") || view.state.doc.childCount > 1 || getFirstChildDescendants(view).length > 1 || view.state.doc.textContent) {
|
|
296
|
+
view.dom.removeAttribute("data-placeholder");
|
|
297
|
+
} else {
|
|
298
|
+
view.dom.setAttribute("data-placeholder", text);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
return new import_prosemirror_state3.Plugin({
|
|
302
|
+
view(view) {
|
|
303
|
+
update(view);
|
|
304
|
+
return { update };
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/text_editor/text_editor.tsx
|
|
310
|
+
var import_prosemirror_model2 = require("prosemirror-model");
|
|
311
|
+
var import_prosemirror_history2 = require("prosemirror-history");
|
|
312
|
+
|
|
313
|
+
// src/text_editor/plugins/keymap.tsx
|
|
314
|
+
var import_prosemirror_history = require("prosemirror-history");
|
|
315
|
+
function buildKeymap() {
|
|
316
|
+
const keys = {};
|
|
317
|
+
function bind(key, cmd) {
|
|
318
|
+
keys[key] = cmd;
|
|
319
|
+
}
|
|
320
|
+
bind("Mod-z", import_prosemirror_history.undo);
|
|
321
|
+
bind("Shift-Mod-z", import_prosemirror_history.redo);
|
|
322
|
+
bind("Mod-y", import_prosemirror_history.redo);
|
|
323
|
+
return keys;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/text_editor/schema.tsx
|
|
327
|
+
var import_prosemirror_model = require("prosemirror-model");
|
|
328
|
+
var import_prosemirror_schema_list = require("prosemirror-schema-list");
|
|
329
|
+
|
|
330
|
+
// src/file/responsive_image.tsx
|
|
331
|
+
var import_react = __toESM(require("react"));
|
|
332
|
+
var sizes = [
|
|
333
|
+
64,
|
|
334
|
+
128,
|
|
335
|
+
256,
|
|
336
|
+
320,
|
|
337
|
+
480,
|
|
338
|
+
640,
|
|
339
|
+
768,
|
|
340
|
+
1080,
|
|
341
|
+
1200,
|
|
342
|
+
1536,
|
|
343
|
+
1920,
|
|
344
|
+
2560,
|
|
345
|
+
3840
|
|
346
|
+
];
|
|
347
|
+
var generateSrc = (cdnOrigin, src, width, height, ratio, image = {}) => {
|
|
348
|
+
const searchParams = new URLSearchParams();
|
|
349
|
+
if (image.width) {
|
|
350
|
+
searchParams.set("w", image.width.toString());
|
|
351
|
+
}
|
|
352
|
+
if (width) {
|
|
353
|
+
searchParams.set("w", width.toString());
|
|
354
|
+
if (ratio) {
|
|
355
|
+
searchParams.set("h", Math.round(width / ratio).toString());
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (image.height) {
|
|
359
|
+
searchParams.set("h", image.height.toString());
|
|
360
|
+
}
|
|
361
|
+
if (height) {
|
|
362
|
+
searchParams.set("h", height.toString());
|
|
363
|
+
}
|
|
364
|
+
const search = searchParams.toString() ? `?${searchParams.toString()}` : "";
|
|
365
|
+
if (!src.includes(cdnOrigin)) {
|
|
366
|
+
return src;
|
|
367
|
+
}
|
|
368
|
+
return `${encodeURI(decodeURI(src))}${search}`;
|
|
369
|
+
};
|
|
370
|
+
function generateSrcSet(cdnOrigin, image, ratio, props = {}) {
|
|
371
|
+
const src = typeof image === "string" ? image : image.src;
|
|
372
|
+
const isGif = src.endsWith(".gif");
|
|
373
|
+
if (isGif) {
|
|
374
|
+
return void 0;
|
|
375
|
+
}
|
|
376
|
+
if (props.width) {
|
|
377
|
+
return [1, 2, 3].map((scale) => {
|
|
378
|
+
const genWidth = Number(props.width) * scale;
|
|
379
|
+
return `${generateSrc(
|
|
380
|
+
cdnOrigin,
|
|
381
|
+
src,
|
|
382
|
+
genWidth,
|
|
383
|
+
props.height ? Number(props.height) * scale : ratio ? Math.round(genWidth / ratio) : void 0
|
|
384
|
+
)} ${scale}x`;
|
|
385
|
+
}).join(", ");
|
|
386
|
+
}
|
|
387
|
+
return sizes.map(
|
|
388
|
+
(size) => `${generateSrc(cdnOrigin, src, size, void 0, ratio, props)} ${size}w`
|
|
389
|
+
).join(", ");
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/text_editor/schema.tsx
|
|
393
|
+
function createSchema({ cdnOrigin }) {
|
|
394
|
+
const customSchema = new import_prosemirror_model.Schema({
|
|
395
|
+
nodes: {
|
|
396
|
+
doc: { content: "block+" },
|
|
397
|
+
paragraph: {
|
|
398
|
+
attrs: { align: { default: null } },
|
|
399
|
+
content: "inline*",
|
|
400
|
+
group: "block",
|
|
401
|
+
parseDOM: [
|
|
402
|
+
{
|
|
403
|
+
tag: "p",
|
|
404
|
+
getAttrs(dom) {
|
|
405
|
+
return {
|
|
406
|
+
align: dom.style.textAlign || null
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
],
|
|
411
|
+
toDOM(node) {
|
|
412
|
+
return [
|
|
413
|
+
"p",
|
|
414
|
+
{
|
|
415
|
+
style: node.attrs.align ? `text-align: ${node.attrs.align}` : null
|
|
416
|
+
},
|
|
417
|
+
0
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
text: {
|
|
422
|
+
group: "inline"
|
|
423
|
+
},
|
|
424
|
+
hard_break: {
|
|
425
|
+
inline: true,
|
|
426
|
+
group: "inline",
|
|
427
|
+
selectable: false,
|
|
428
|
+
parseDOM: [{ tag: "br" }],
|
|
429
|
+
toDOM() {
|
|
430
|
+
return ["br"];
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
heading: {
|
|
434
|
+
attrs: { level: { default: 1 }, align: { default: null } },
|
|
435
|
+
content: "inline*",
|
|
436
|
+
group: "block",
|
|
437
|
+
defining: true,
|
|
438
|
+
parseDOM: [
|
|
439
|
+
{
|
|
440
|
+
tag: "h1",
|
|
441
|
+
getAttrs(node) {
|
|
442
|
+
return {
|
|
443
|
+
level: 1,
|
|
444
|
+
algin: node.style.textAlign || null
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
tag: "h2",
|
|
450
|
+
getAttrs(node) {
|
|
451
|
+
return {
|
|
452
|
+
level: 2,
|
|
453
|
+
algin: node.style.textAlign || null
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
tag: "h3",
|
|
459
|
+
getAttrs(node) {
|
|
460
|
+
return {
|
|
461
|
+
level: 3,
|
|
462
|
+
algin: node.style.textAlign || null
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
tag: "h4",
|
|
468
|
+
getAttrs(node) {
|
|
469
|
+
return {
|
|
470
|
+
level: 4,
|
|
471
|
+
algin: node.style.textAlign || null
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
tag: "h5",
|
|
477
|
+
getAttrs(node) {
|
|
478
|
+
return {
|
|
479
|
+
level: 5,
|
|
480
|
+
algin: node.style.textAlign || null
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
tag: "h6",
|
|
486
|
+
getAttrs(node) {
|
|
487
|
+
return {
|
|
488
|
+
level: 6,
|
|
489
|
+
algin: node.style.textAlign || null
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
],
|
|
494
|
+
toDOM(node) {
|
|
495
|
+
return [
|
|
496
|
+
"h" + node.attrs.level,
|
|
497
|
+
{
|
|
498
|
+
id: node.textContent.toLowerCase().replace(/\s+/g, "-"),
|
|
499
|
+
style: node.attrs.align ? `text-align: ${node.attrs.align};` : null
|
|
500
|
+
},
|
|
501
|
+
0
|
|
502
|
+
];
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
horizontal_rule: {
|
|
506
|
+
group: "block",
|
|
507
|
+
parseDOM: [{ tag: "hr" }],
|
|
508
|
+
toDOM() {
|
|
509
|
+
return ["hr"];
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
image: {
|
|
513
|
+
attrs: {
|
|
514
|
+
src: { validate: "string" },
|
|
515
|
+
alt: { default: null, validate: "string|null" },
|
|
516
|
+
title: {
|
|
517
|
+
default: null,
|
|
518
|
+
validate: "string|null"
|
|
519
|
+
},
|
|
520
|
+
width: {
|
|
521
|
+
default: null,
|
|
522
|
+
validate: "number|null"
|
|
523
|
+
},
|
|
524
|
+
height: {
|
|
525
|
+
default: null,
|
|
526
|
+
validate: "number|null"
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
inline: true,
|
|
530
|
+
group: "inline",
|
|
531
|
+
draggable: true,
|
|
532
|
+
parseDOM: [
|
|
533
|
+
{
|
|
534
|
+
tag: "img",
|
|
535
|
+
getAttrs(dom) {
|
|
536
|
+
return {
|
|
537
|
+
src: dom.getAttribute("src"),
|
|
538
|
+
title: dom.getAttribute("title"),
|
|
539
|
+
alt: dom.getAttribute("alt"),
|
|
540
|
+
width: dom.getAttribute("width"),
|
|
541
|
+
height: dom.getAttribute("height")
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
],
|
|
546
|
+
toDOM(node) {
|
|
547
|
+
const { src, alt, title, width, height } = node.attrs;
|
|
548
|
+
return [
|
|
549
|
+
"img",
|
|
550
|
+
{
|
|
551
|
+
src,
|
|
552
|
+
alt,
|
|
553
|
+
title,
|
|
554
|
+
width,
|
|
555
|
+
height,
|
|
556
|
+
srcSet: cdnOrigin ? generateSrcSet(cdnOrigin, src) : void 0,
|
|
557
|
+
sizes: cdnOrigin ? "(max-width: 768px) 100vw, 768px" : void 0
|
|
558
|
+
}
|
|
559
|
+
];
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
marks: {
|
|
564
|
+
link: {
|
|
565
|
+
attrs: {
|
|
566
|
+
href: { default: "" },
|
|
567
|
+
title: { default: null }
|
|
568
|
+
},
|
|
569
|
+
inclusive: false,
|
|
570
|
+
parseDOM: [
|
|
571
|
+
{
|
|
572
|
+
tag: "a[href]",
|
|
573
|
+
getAttrs(dom) {
|
|
574
|
+
return {
|
|
575
|
+
href: dom.getAttribute("href"),
|
|
576
|
+
title: dom.getAttribute("title")
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
],
|
|
581
|
+
toDOM(node) {
|
|
582
|
+
const { href, title } = node.attrs;
|
|
583
|
+
const target = "_blank";
|
|
584
|
+
const rel = "noopener noreferrer";
|
|
585
|
+
return ["a", { href, title: title || href, target, rel }, 0];
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
bold: {
|
|
589
|
+
parseDOM: [
|
|
590
|
+
{ tag: "strong" },
|
|
591
|
+
{
|
|
592
|
+
tag: "b",
|
|
593
|
+
getAttrs: (node) => node.style.fontWeight != "normal" && null
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
style: "font-weight=400",
|
|
597
|
+
clearMark: (m) => m.type.name == "strong"
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
style: "font-weight",
|
|
601
|
+
getAttrs: (value) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
|
|
602
|
+
}
|
|
603
|
+
],
|
|
604
|
+
toDOM() {
|
|
605
|
+
return ["strong", 0];
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
italic: {
|
|
609
|
+
parseDOM: [
|
|
610
|
+
{ tag: "em" },
|
|
611
|
+
{ tag: "i" },
|
|
612
|
+
{ style: "font-style=italic" },
|
|
613
|
+
{
|
|
614
|
+
style: "font-style=normal",
|
|
615
|
+
clearMark: (m) => m.type.name == "em"
|
|
616
|
+
}
|
|
617
|
+
],
|
|
618
|
+
toDOM() {
|
|
619
|
+
return ["em", 0];
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
underline: {
|
|
623
|
+
parseDOM: [
|
|
624
|
+
{ tag: "u" },
|
|
625
|
+
{
|
|
626
|
+
style: "text-decoration",
|
|
627
|
+
getAttrs: (value) => value === "underline" && null
|
|
628
|
+
}
|
|
629
|
+
],
|
|
630
|
+
toDOM() {
|
|
631
|
+
return ["u", 0];
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
const prosemirrorSchema = new import_prosemirror_model.Schema({
|
|
637
|
+
nodes: (0, import_prosemirror_schema_list.addListNodes)(customSchema.spec.nodes, "paragraph block*", "block"),
|
|
638
|
+
marks: customSchema.spec.marks
|
|
639
|
+
});
|
|
640
|
+
return prosemirrorSchema;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// src/cn.ts
|
|
644
|
+
function cn(...classes) {
|
|
645
|
+
return classes.filter(Boolean).join(" ").trim();
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// src/text_editor/text_editor.tsx
|
|
649
|
+
function createTextEditor({
|
|
650
|
+
fileUploader,
|
|
651
|
+
cdnOrigin
|
|
652
|
+
} = {}) {
|
|
653
|
+
const schema = createSchema({ cdnOrigin });
|
|
654
|
+
const prosemirrorParser = import_prosemirror_model2.DOMParser.fromSchema(schema);
|
|
655
|
+
const prosemirrorSerializer = import_prosemirror_model2.DOMSerializer.fromSchema(schema);
|
|
656
|
+
const attachMediaComponent = cdnOrigin && fileUploader ? createAttachMedia({
|
|
657
|
+
schema,
|
|
658
|
+
cdnOrigin,
|
|
659
|
+
fileUploader
|
|
660
|
+
}) : null;
|
|
661
|
+
function useTextEditor() {
|
|
662
|
+
const view = (0, import_react3.useRef)(null);
|
|
663
|
+
const observers = (0, import_react3.useMemo)(() => [], []);
|
|
664
|
+
const Component = (0, import_react3.useCallback)(
|
|
665
|
+
function Component2({
|
|
666
|
+
name,
|
|
667
|
+
placeholder,
|
|
668
|
+
className,
|
|
669
|
+
defaultValue,
|
|
670
|
+
onClick,
|
|
671
|
+
onHTMLChanged,
|
|
672
|
+
editor,
|
|
673
|
+
state,
|
|
674
|
+
...props
|
|
675
|
+
}) {
|
|
676
|
+
const ref = (0, import_react3.useRef)(null);
|
|
677
|
+
(0, import_react3.useEffect)(() => {
|
|
678
|
+
const container = ref.current;
|
|
679
|
+
if (!container) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
const wrapper = document.createElement("div");
|
|
683
|
+
wrapper.innerHTML = defaultValue || "";
|
|
684
|
+
const editorView = new import_prosemirror_view2.EditorView(container, {
|
|
685
|
+
...editor,
|
|
686
|
+
attributes: (state2) => {
|
|
687
|
+
const propsAttributes = (() => {
|
|
688
|
+
if (typeof editor?.attributes === "function") {
|
|
689
|
+
return editor.attributes(state2);
|
|
690
|
+
}
|
|
691
|
+
return editor?.attributes;
|
|
692
|
+
})();
|
|
693
|
+
return {
|
|
694
|
+
...propsAttributes,
|
|
695
|
+
class: cn(propsAttributes?.class, "outline-none"),
|
|
696
|
+
spellcheck: propsAttributes?.spellcheck || "false"
|
|
697
|
+
};
|
|
698
|
+
},
|
|
699
|
+
state: import_prosemirror_state4.EditorState.create({
|
|
700
|
+
schema: state?.schema || schema,
|
|
701
|
+
doc: state?.doc || prosemirrorParser.parse(wrapper),
|
|
702
|
+
plugins: [
|
|
703
|
+
...state?.plugins || [],
|
|
704
|
+
(0, import_prosemirror_history2.history)(),
|
|
705
|
+
(0, import_prosemirror_keymap.keymap)(import_prosemirror_commands.baseKeymap),
|
|
706
|
+
(0, import_prosemirror_keymap.keymap)(buildKeymap()),
|
|
707
|
+
uploadPlaceholderPlugin,
|
|
708
|
+
attachMediaComponent ? dragAndDropPlugin({ attachMedia: attachMediaComponent }) : null,
|
|
709
|
+
placeholder && placeholderPlugin(placeholder)
|
|
710
|
+
].filter((e) => !!e)
|
|
711
|
+
}),
|
|
712
|
+
dispatchTransaction(tr) {
|
|
713
|
+
let result;
|
|
714
|
+
if (editor?.dispatchTransaction) {
|
|
715
|
+
result = editor.dispatchTransaction(tr);
|
|
716
|
+
} else {
|
|
717
|
+
editorView.updateState(editorView.state.apply(tr));
|
|
718
|
+
}
|
|
719
|
+
observers.forEach((observer) => {
|
|
720
|
+
observer(editorView);
|
|
721
|
+
});
|
|
722
|
+
if (tr.docChanged) {
|
|
723
|
+
const html = serialize();
|
|
724
|
+
onHTMLChanged?.(html);
|
|
725
|
+
if (inputRef.current) {
|
|
726
|
+
inputRef.current.value = html;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
view.current = editorView;
|
|
733
|
+
return () => {
|
|
734
|
+
view.current = null;
|
|
735
|
+
editorView.destroy();
|
|
736
|
+
container.innerHTML = "";
|
|
737
|
+
};
|
|
738
|
+
}, [editor, state, defaultValue, placeholder, onHTMLChanged]);
|
|
739
|
+
const inputRef = (0, import_react3.useRef)(null);
|
|
740
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(
|
|
741
|
+
"div",
|
|
742
|
+
{
|
|
743
|
+
ref,
|
|
744
|
+
className: cn("cursor-text", className),
|
|
745
|
+
onClick: (e) => {
|
|
746
|
+
e.stopPropagation();
|
|
747
|
+
view?.current?.focus();
|
|
748
|
+
onClick?.(e);
|
|
749
|
+
},
|
|
750
|
+
...props
|
|
751
|
+
}
|
|
752
|
+
), name && /* @__PURE__ */ import_react2.default.createElement("input", { ref: inputRef, type: "hidden", name }));
|
|
753
|
+
},
|
|
754
|
+
[observers]
|
|
755
|
+
);
|
|
756
|
+
const commands = {
|
|
757
|
+
async attachMedia(files) {
|
|
758
|
+
if (view.current && attachMediaComponent) {
|
|
759
|
+
return attachMediaComponent(view.current, files);
|
|
760
|
+
}
|
|
761
|
+
},
|
|
762
|
+
toggleMark(type, attrs, options) {
|
|
763
|
+
const markType = schema.marks[type];
|
|
764
|
+
if (view.current && markType) {
|
|
765
|
+
const command = (0, import_prosemirror_commands.toggleMark)(markType, attrs, options);
|
|
766
|
+
command(view.current.state, view.current.dispatch);
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
setBlockType(type, attrs) {
|
|
770
|
+
const blockType = schema.nodes[type];
|
|
771
|
+
if (view.current && blockType) {
|
|
772
|
+
const command = (0, import_prosemirror_commands.setBlockType)(blockType, attrs);
|
|
773
|
+
command(view.current.state, view.current.dispatch);
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
insertNode(type, attrs, content, marks) {
|
|
777
|
+
const nodeType = schema.nodes[type];
|
|
778
|
+
if (view.current && nodeType) {
|
|
779
|
+
const node = nodeType.create(attrs, content, marks);
|
|
780
|
+
view.current.dispatch(
|
|
781
|
+
view.current.state.tr.replaceSelectionWith(node)
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
setHTML(html) {
|
|
786
|
+
if (!view.current) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const wrap = document.createElement("div");
|
|
790
|
+
wrap.innerHTML = html;
|
|
791
|
+
const doc = prosemirrorParser.parse(wrap);
|
|
792
|
+
const tr = view.current.state.tr.replaceWith(
|
|
793
|
+
0,
|
|
794
|
+
view.current.state.doc.content.size,
|
|
795
|
+
doc.content
|
|
796
|
+
);
|
|
797
|
+
view.current.dispatch(tr);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
const serialize = () => {
|
|
801
|
+
if (!view.current) {
|
|
802
|
+
return "";
|
|
803
|
+
}
|
|
804
|
+
const fragment = prosemirrorSerializer.serializeFragment(
|
|
805
|
+
view.current.state.doc.content
|
|
806
|
+
);
|
|
807
|
+
const container = document.createElement("div");
|
|
808
|
+
container.appendChild(fragment);
|
|
809
|
+
return container.innerHTML;
|
|
810
|
+
};
|
|
811
|
+
const getTextContent = () => {
|
|
812
|
+
if (!view.current) {
|
|
813
|
+
return "";
|
|
814
|
+
}
|
|
815
|
+
return view.current.state.doc.textContent;
|
|
816
|
+
};
|
|
817
|
+
return {
|
|
818
|
+
schema,
|
|
819
|
+
view,
|
|
820
|
+
commands,
|
|
821
|
+
Component,
|
|
822
|
+
serialize,
|
|
823
|
+
getTextContent
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
return {
|
|
827
|
+
schema,
|
|
828
|
+
useTextEditor
|
|
829
|
+
};
|
|
830
|
+
}
|