@underverse-ui/underverse 2.0.28 → 2.0.30
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/api-reference.json +1 -1
- package/dist/{EmojiPicker-NV3GQYWI.js → EmojiPicker-ISJ6RXYG.js} +4 -4
- package/dist/{chunk-Y4X6CAZY.js → chunk-2P7TSXEE.js} +82 -25
- package/dist/chunk-2P7TSXEE.js.map +1 -0
- package/dist/{chunk-KTOXCD6J.js → chunk-37MHVJMV.js} +1078 -90
- package/dist/chunk-37MHVJMV.js.map +1 -0
- package/dist/{chunk-QYFXYDBK.js → chunk-57BKIC6J.js} +1306 -888
- package/dist/chunk-57BKIC6J.js.map +1 -0
- package/dist/{chunk-LRIRY4DG.js → chunk-5W63IHIN.js} +11 -3
- package/dist/chunk-5W63IHIN.js.map +1 -0
- package/dist/{chunk-F7MX3XXK.js → chunk-S4UHFRL3.js} +3 -3
- package/dist/{chunk-A4GUPKHM.js → chunk-ZP7F4ZD7.js} +63 -43
- package/dist/chunk-ZP7F4ZD7.js.map +1 -0
- package/dist/index.cjs +3275 -1628
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +23 -10
- package/dist/index.js.map +1 -1
- package/dist/{menu-bar-CFIWMBAA.js → menu-bar-DPCNNUX5.js} +227 -54
- package/dist/menu-bar-DPCNNUX5.js.map +1 -0
- package/dist/ueditor.cjs +9803 -8169
- package/dist/ueditor.cjs.map +1 -1
- package/dist/ueditor.d.cts +10 -0
- package/dist/ueditor.d.ts +10 -0
- package/dist/ueditor.js +4 -4
- package/package.json +2 -1
- package/dist/chunk-A4GUPKHM.js.map +0 -1
- package/dist/chunk-KTOXCD6J.js.map +0 -1
- package/dist/chunk-LRIRY4DG.js.map +0 -1
- package/dist/chunk-QYFXYDBK.js.map +0 -1
- package/dist/chunk-Y4X6CAZY.js.map +0 -1
- package/dist/menu-bar-CFIWMBAA.js.map +0 -1
- /package/dist/{EmojiPicker-NV3GQYWI.js.map → EmojiPicker-ISJ6RXYG.js.map} +0 -0
- /package/dist/{chunk-F7MX3XXK.js.map → chunk-S4UHFRL3.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
Modal_default
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2P7TSXEE.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_TABLE_ROW_HEIGHT,
|
|
7
7
|
DEFAULT_UEDITOR_IMAGE_MAX_FILE_SIZE,
|
|
@@ -13,23 +13,33 @@ import {
|
|
|
13
13
|
ImageInput,
|
|
14
14
|
LinkInput,
|
|
15
15
|
MIN_TABLE_ROW_HEIGHT,
|
|
16
|
+
TABLE_WIDTH_BASIS_POINTS,
|
|
16
17
|
TableInsertGrid,
|
|
17
18
|
UEDITOR_PROSEMIRROR_CLASS_NAME,
|
|
18
19
|
applyEditorLink,
|
|
19
|
-
|
|
20
|
+
clampResponsiveTableWidthBp,
|
|
21
|
+
formatBasisPointsAsPercentage,
|
|
20
22
|
getTableAnchorPos,
|
|
23
|
+
normalizeColumnRatios,
|
|
24
|
+
parseColumnRatios,
|
|
25
|
+
parsePercentageToBasisPoints,
|
|
26
|
+
resolveResponsiveTableOffsetBp,
|
|
27
|
+
resolveUEditorImageFiles,
|
|
21
28
|
sanitizeUEditorUrl,
|
|
29
|
+
trackEditorInsertionPosition,
|
|
22
30
|
useDropdownMenuClose,
|
|
23
31
|
useSharedEditorUiRenderState
|
|
24
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-37MHVJMV.js";
|
|
25
33
|
import {
|
|
26
34
|
cn,
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
resolveUEditorPortalContainer,
|
|
36
|
+
useSmartTranslations,
|
|
37
|
+
useUEditorPortalContainerGetter
|
|
38
|
+
} from "./chunk-ZP7F4ZD7.js";
|
|
29
39
|
import "./chunk-NSBPE2FW.js";
|
|
30
40
|
|
|
31
41
|
// src/components/UEditor/menu-bar.tsx
|
|
32
|
-
import React, {
|
|
42
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
33
43
|
import {
|
|
34
44
|
AlignCenter,
|
|
35
45
|
AlignJustify,
|
|
@@ -64,6 +74,68 @@ import {
|
|
|
64
74
|
} from "lucide-react";
|
|
65
75
|
|
|
66
76
|
// src/components/UEditor/preview-html.ts
|
|
77
|
+
var BLOCKED_PREVIEW_ELEMENTS = /* @__PURE__ */ new Set(["SCRIPT", "IFRAME", "OBJECT", "EMBED", "LINK", "META", "BASE", "STYLE"]);
|
|
78
|
+
var UNSAFE_INLINE_STYLE_RE = /(?:url\s*\(|expression\s*\(|@import|-moz-binding)/i;
|
|
79
|
+
function isSafeUEditorSourceHtml(html, ownerDocument) {
|
|
80
|
+
const sourceDocument = ownerDocument ?? (typeof document !== "undefined" ? document : null);
|
|
81
|
+
if (!sourceDocument) return false;
|
|
82
|
+
const container = sourceDocument.createElement("div");
|
|
83
|
+
container.innerHTML = html;
|
|
84
|
+
for (const element of Array.from(container.querySelectorAll("*"))) {
|
|
85
|
+
if (BLOCKED_PREVIEW_ELEMENTS.has(element.tagName)) return false;
|
|
86
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
87
|
+
const name = attribute.name.toLowerCase();
|
|
88
|
+
if (name.startsWith("on") || name === "srcdoc") return false;
|
|
89
|
+
}
|
|
90
|
+
const style = element.getAttribute("style");
|
|
91
|
+
if (style && UNSAFE_INLINE_STYLE_RE.test(style)) return false;
|
|
92
|
+
const isFileCard = element.getAttribute("data-type") === "file-card";
|
|
93
|
+
const urlAttributes = [
|
|
94
|
+
["href", isFileCard ? "file" : "link"],
|
|
95
|
+
["src", "image"],
|
|
96
|
+
["data-src", isFileCard ? "file" : "image"],
|
|
97
|
+
["data-url", "link"],
|
|
98
|
+
["data-image", "image"]
|
|
99
|
+
];
|
|
100
|
+
for (const [name, kind] of urlAttributes) {
|
|
101
|
+
if (element.hasAttribute(name) && !sanitizeUEditorUrl(element.getAttribute(name) ?? "", kind)) return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
function sanitizePreviewContainer(container) {
|
|
107
|
+
for (const element of Array.from(container.querySelectorAll("*"))) {
|
|
108
|
+
if (BLOCKED_PREVIEW_ELEMENTS.has(element.tagName)) {
|
|
109
|
+
element.remove();
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
113
|
+
const name = attribute.name.toLowerCase();
|
|
114
|
+
if (name.startsWith("on") || name === "srcdoc") {
|
|
115
|
+
element.removeAttribute(attribute.name);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const style = element.getAttribute("style");
|
|
119
|
+
if (style && UNSAFE_INLINE_STYLE_RE.test(style)) element.removeAttribute("style");
|
|
120
|
+
const isFileCard = element.getAttribute("data-type") === "file-card";
|
|
121
|
+
const urlAttributes = [
|
|
122
|
+
["href", isFileCard ? "file" : "link"],
|
|
123
|
+
["src", "image"],
|
|
124
|
+
["data-src", isFileCard ? "file" : "image"],
|
|
125
|
+
["data-url", "link"],
|
|
126
|
+
["data-image", "image"]
|
|
127
|
+
];
|
|
128
|
+
for (const [name, kind] of urlAttributes) {
|
|
129
|
+
if (!element.hasAttribute(name)) continue;
|
|
130
|
+
const safeUrl = sanitizeUEditorUrl(element.getAttribute(name) ?? "", kind);
|
|
131
|
+
if (safeUrl) element.setAttribute(name, safeUrl);
|
|
132
|
+
else element.removeAttribute(name);
|
|
133
|
+
}
|
|
134
|
+
if (element.tagName === "A" && element.getAttribute("target") === "_blank") {
|
|
135
|
+
element.setAttribute("rel", "noopener noreferrer");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
67
139
|
var DEFAULT_TABLE_COLUMN_WIDTH = 100;
|
|
68
140
|
var TIPTAP_TABLE_MIN_COLUMN_WIDTH = 25;
|
|
69
141
|
function parsePixelWidth(value) {
|
|
@@ -154,6 +226,17 @@ function normalizePreviewRowHeight(row) {
|
|
|
154
226
|
function normalizePreviewTable(table) {
|
|
155
227
|
const widths = resolveColumnWidths(table);
|
|
156
228
|
if (widths.length === 0) return;
|
|
229
|
+
const storedMode = table.getAttribute("data-table-width-mode");
|
|
230
|
+
const responsive = storedMode === "responsive" || storedMode === "full" || parsePercentageToBasisPoints(table.style.width) !== null;
|
|
231
|
+
const storedRatios = parseColumnRatios(table.getAttribute("data-table-column-ratios"));
|
|
232
|
+
const columnRatios = normalizeColumnRatios(
|
|
233
|
+
storedRatios?.length === widths.length ? storedRatios : widths,
|
|
234
|
+
widths.length
|
|
235
|
+
);
|
|
236
|
+
const widthBp = responsive ? Number(table.getAttribute("data-table-width-bp")) || parsePercentageToBasisPoints(table.getAttribute("data-table-width") ?? table.style.width) || TABLE_WIDTH_BASIS_POINTS : TABLE_WIDTH_BASIS_POINTS;
|
|
237
|
+
const safeWidthBp = clampResponsiveTableWidthBp(widthBp);
|
|
238
|
+
const offsetBp = responsive ? Number(table.getAttribute("data-table-offset-bp")) || parsePercentageToBasisPoints(table.getAttribute("data-table-offset") ?? table.style.marginLeft) || 0 : 0;
|
|
239
|
+
const safeOffsetBp = resolveResponsiveTableOffsetBp(safeWidthBp, null, offsetBp);
|
|
157
240
|
let colgroup = table.querySelector("colgroup");
|
|
158
241
|
if (!colgroup) {
|
|
159
242
|
colgroup = document.createElement("colgroup");
|
|
@@ -162,6 +245,7 @@ function normalizePreviewTable(table) {
|
|
|
162
245
|
while (colgroup.children.length < widths.length) {
|
|
163
246
|
colgroup.appendChild(document.createElement("col"));
|
|
164
247
|
}
|
|
248
|
+
const tableWidth = widths.reduce((sum, width) => sum + width, 0);
|
|
165
249
|
Array.from(colgroup.children).forEach((child, index) => {
|
|
166
250
|
if (child.tagName.toLowerCase() !== "col") return;
|
|
167
251
|
const col = child;
|
|
@@ -169,32 +253,42 @@ function normalizePreviewTable(table) {
|
|
|
169
253
|
child.remove();
|
|
170
254
|
return;
|
|
171
255
|
}
|
|
172
|
-
col.style.width = `${widths[index]}px`;
|
|
173
|
-
col.style.minWidth = `${widths[index]}px`;
|
|
256
|
+
col.style.width = responsive ? formatBasisPointsAsPercentage(columnRatios[index]) : `${widths[index]}px`;
|
|
257
|
+
col.style.minWidth = responsive ? "" : `${widths[index]}px`;
|
|
174
258
|
col.setAttribute("width", String(widths[index]));
|
|
175
259
|
});
|
|
176
|
-
|
|
177
|
-
setStyleProperty(table, "width", `${tableWidth}px`);
|
|
178
|
-
setStyleProperty(table, "min-width", `${tableWidth}px`);
|
|
260
|
+
setStyleProperty(table, "width", responsive ? formatBasisPointsAsPercentage(safeWidthBp) : `${tableWidth}px`);
|
|
261
|
+
setStyleProperty(table, "min-width", responsive ? `${widths.length * TIPTAP_TABLE_MIN_COLUMN_WIDTH}px` : `${tableWidth}px`);
|
|
179
262
|
setStyleProperty(table, "table-layout", "fixed");
|
|
263
|
+
if (responsive) {
|
|
264
|
+
table.setAttribute("data-table-width-mode", "responsive");
|
|
265
|
+
table.setAttribute("data-table-width-bp", String(safeWidthBp));
|
|
266
|
+
table.setAttribute("data-table-offset-bp", String(safeOffsetBp));
|
|
267
|
+
table.setAttribute("data-table-column-ratios", columnRatios.join(","));
|
|
268
|
+
setStyleProperty(table, "margin-left", formatBasisPointsAsPercentage(safeOffsetBp));
|
|
269
|
+
setStyleProperty(table, "margin-right", "auto");
|
|
270
|
+
}
|
|
180
271
|
Array.from(table.rows).forEach((row) => {
|
|
181
272
|
let columnIndex = 0;
|
|
182
273
|
normalizePreviewRowHeight(row);
|
|
183
274
|
Array.from(row.cells).forEach((cell) => {
|
|
184
275
|
const colspan = getCellColspan(cell);
|
|
185
276
|
const cellWidth = widths.slice(columnIndex, columnIndex + colspan).reduce((sum, width) => sum + width, 0);
|
|
277
|
+
const cellRatio = columnRatios.slice(columnIndex, columnIndex + colspan).reduce((sum, ratio) => sum + ratio, 0);
|
|
186
278
|
if (cellWidth > 0) {
|
|
187
|
-
cell.style.width = `${cellWidth}px`;
|
|
188
|
-
cell.style.minWidth = `${cellWidth}px`;
|
|
279
|
+
cell.style.width = responsive ? formatBasisPointsAsPercentage(cellRatio) : `${cellWidth}px`;
|
|
280
|
+
cell.style.minWidth = responsive ? "" : `${cellWidth}px`;
|
|
189
281
|
}
|
|
190
282
|
columnIndex += colspan;
|
|
191
283
|
});
|
|
192
284
|
});
|
|
193
285
|
}
|
|
194
|
-
function prepareUEditorPreviewHtml(html) {
|
|
195
|
-
|
|
196
|
-
|
|
286
|
+
function prepareUEditorPreviewHtml(html, ownerDocument) {
|
|
287
|
+
const previewDocument = ownerDocument ?? (typeof document !== "undefined" ? document : null);
|
|
288
|
+
if (!previewDocument || !html) return html;
|
|
289
|
+
const container = previewDocument.createElement("div");
|
|
197
290
|
container.innerHTML = html;
|
|
291
|
+
sanitizePreviewContainer(container);
|
|
198
292
|
container.querySelectorAll("table").forEach((table) => normalizePreviewTable(table));
|
|
199
293
|
return container.innerHTML;
|
|
200
294
|
}
|
|
@@ -262,13 +356,17 @@ function buildFileMenuItems(t, editor, { onSave, onExport }) {
|
|
|
262
356
|
onExport();
|
|
263
357
|
} else {
|
|
264
358
|
const html = editor.getHTML();
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
const
|
|
359
|
+
const editorDocument = editor.view.dom.ownerDocument;
|
|
360
|
+
const editorWindow = editorDocument.defaultView;
|
|
361
|
+
const BlobCtor = editorWindow?.Blob ?? Blob;
|
|
362
|
+
const URLApi = editorWindow?.URL ?? URL;
|
|
363
|
+
const blob = new BlobCtor([`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>${html}</body></html>`], { type: "text/html;charset=utf-8" });
|
|
364
|
+
const url = URLApi.createObjectURL(blob);
|
|
365
|
+
const a = editorDocument.createElement("a");
|
|
268
366
|
a.href = url;
|
|
269
367
|
a.download = "document.html";
|
|
270
368
|
a.click();
|
|
271
|
-
|
|
369
|
+
editorWindow?.setTimeout(() => URLApi.revokeObjectURL(url), 0);
|
|
272
370
|
}
|
|
273
371
|
}
|
|
274
372
|
}
|
|
@@ -298,29 +396,31 @@ function buildEditMenuItems(t, editor) {
|
|
|
298
396
|
label: t("menubar.cut"),
|
|
299
397
|
icon: Scissors,
|
|
300
398
|
shortcut: t("menubar.cutShortcut"),
|
|
301
|
-
onClick: () =>
|
|
399
|
+
onClick: () => editor.view.dom.ownerDocument.execCommand("cut")
|
|
302
400
|
},
|
|
303
401
|
{
|
|
304
402
|
type: "action",
|
|
305
403
|
label: t("menubar.copy"),
|
|
306
404
|
shortcut: t("menubar.copyShortcut"),
|
|
307
|
-
onClick: () =>
|
|
405
|
+
onClick: () => editor.view.dom.ownerDocument.execCommand("copy")
|
|
308
406
|
},
|
|
309
407
|
{
|
|
310
408
|
type: "action",
|
|
311
409
|
label: t("menubar.paste"),
|
|
312
410
|
shortcut: t("menubar.pasteShortcut"),
|
|
313
|
-
onClick: () =>
|
|
411
|
+
onClick: () => editor.view.dom.ownerDocument.execCommand("paste")
|
|
314
412
|
},
|
|
315
413
|
{
|
|
316
414
|
type: "action",
|
|
317
415
|
label: t("menubar.pasteAsText"),
|
|
318
416
|
onClick: async () => {
|
|
319
417
|
try {
|
|
320
|
-
const
|
|
418
|
+
const clipboard = editor.view.dom.ownerDocument.defaultView?.navigator.clipboard;
|
|
419
|
+
if (!clipboard) throw new Error("Clipboard API is unavailable");
|
|
420
|
+
const text = await clipboard.readText();
|
|
321
421
|
editor.chain().focus().insertContent(text).run();
|
|
322
422
|
} catch {
|
|
323
|
-
|
|
423
|
+
editor.view.dom.ownerDocument.execCommand("paste");
|
|
324
424
|
}
|
|
325
425
|
}
|
|
326
426
|
},
|
|
@@ -333,7 +433,7 @@ function buildEditMenuItems(t, editor) {
|
|
|
333
433
|
}
|
|
334
434
|
];
|
|
335
435
|
}
|
|
336
|
-
function buildViewMenuItems(t, {
|
|
436
|
+
function buildViewMenuItems(t, editor, {
|
|
337
437
|
containerRef,
|
|
338
438
|
onSourceCode,
|
|
339
439
|
openSourceDialog,
|
|
@@ -361,10 +461,11 @@ function buildViewMenuItems(t, {
|
|
|
361
461
|
onClick: () => {
|
|
362
462
|
const el = containerRef.current;
|
|
363
463
|
if (!el) return;
|
|
364
|
-
|
|
464
|
+
const editorDocument = editor.view.dom.ownerDocument;
|
|
465
|
+
if (!editorDocument.fullscreenElement) {
|
|
365
466
|
el.requestFullscreen?.();
|
|
366
467
|
} else {
|
|
367
|
-
|
|
468
|
+
editorDocument.exitFullscreen?.();
|
|
368
469
|
}
|
|
369
470
|
}
|
|
370
471
|
}
|
|
@@ -643,6 +744,8 @@ var MenuBar = ({
|
|
|
643
744
|
imageInsertMode = "base64",
|
|
644
745
|
maxImageFileSize = DEFAULT_UEDITOR_IMAGE_MAX_FILE_SIZE,
|
|
645
746
|
allowedImageMimeTypes = DEFAULT_UEDITOR_IMAGE_MIME_TYPES,
|
|
747
|
+
onImageUploadError,
|
|
748
|
+
fallbackToDataUrl = true,
|
|
646
749
|
onSave,
|
|
647
750
|
onExport,
|
|
648
751
|
onSourceCode,
|
|
@@ -651,22 +754,45 @@ var MenuBar = ({
|
|
|
651
754
|
}) => {
|
|
652
755
|
const t = useSmartTranslations("UEditor");
|
|
653
756
|
useSharedEditorUiRenderState(editor);
|
|
757
|
+
const getPortalContainer = useUEditorPortalContainerGetter();
|
|
654
758
|
const fileInputRef = useRef(null);
|
|
759
|
+
const sourceTextareaRef = useRef(null);
|
|
655
760
|
const [showImageInput, setShowImageInput] = useState(false);
|
|
656
761
|
const [showLinkInput, setShowLinkInput] = useState(false);
|
|
762
|
+
const [isUploadingImage, setIsUploadingImage] = useState(false);
|
|
763
|
+
const [imageUploadError, setImageUploadError] = useState(null);
|
|
657
764
|
const [openMenuKey, setOpenMenuKey] = useState(null);
|
|
658
765
|
const [showSourceDialog, setShowSourceDialog] = useState(false);
|
|
659
766
|
const [sourceHtml, setSourceHtml] = useState("");
|
|
767
|
+
const [sourceError, setSourceError] = useState("");
|
|
768
|
+
const sourceErrorId = React.useId();
|
|
660
769
|
const [showPreviewDialog, setShowPreviewDialog] = useState(false);
|
|
661
|
-
const previewHtml =
|
|
662
|
-
|
|
663
|
-
|
|
770
|
+
const [previewHtml, setPreviewHtml] = useState("");
|
|
771
|
+
const modalPortalContainer = resolveUEditorPortalContainer(
|
|
772
|
+
getPortalContainer,
|
|
773
|
+
void 0,
|
|
774
|
+
editor.view.dom.ownerDocument
|
|
664
775
|
);
|
|
776
|
+
useEffect(() => {
|
|
777
|
+
if (!showPreviewDialog) return;
|
|
778
|
+
const updatePreview = () => {
|
|
779
|
+
if (!editor.isDestroyed) {
|
|
780
|
+
setPreviewHtml(prepareUEditorPreviewHtml(editor.getHTML(), editor.view.dom.ownerDocument));
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
updatePreview();
|
|
784
|
+
editor.on("update", updatePreview);
|
|
785
|
+
return () => {
|
|
786
|
+
editor.off("update", updatePreview);
|
|
787
|
+
};
|
|
788
|
+
}, [editor, showPreviewDialog]);
|
|
665
789
|
const openSourceDialog = () => {
|
|
666
790
|
setSourceHtml(editor.getHTML());
|
|
791
|
+
setSourceError("");
|
|
667
792
|
setShowSourceDialog(true);
|
|
668
793
|
};
|
|
669
794
|
const openPreviewDialog = () => {
|
|
795
|
+
setPreviewHtml(prepareUEditorPreviewHtml(editor.getHTML(), editor.view.dom.ownerDocument));
|
|
670
796
|
setShowPreviewDialog(true);
|
|
671
797
|
};
|
|
672
798
|
const handlePreview = () => {
|
|
@@ -674,13 +800,23 @@ var MenuBar = ({
|
|
|
674
800
|
openPreviewDialog();
|
|
675
801
|
};
|
|
676
802
|
const applySourceHtml = () => {
|
|
677
|
-
|
|
678
|
-
|
|
803
|
+
const nextSourceHtml = sourceTextareaRef.current?.value ?? sourceHtml;
|
|
804
|
+
try {
|
|
805
|
+
if (!isSafeUEditorSourceHtml(nextSourceHtml, editor.view.dom.ownerDocument)) {
|
|
806
|
+
throw new Error("Unsafe source HTML");
|
|
807
|
+
}
|
|
808
|
+
editor.chain().focus().setContent(nextSourceHtml, { errorOnInvalidContent: true }).run();
|
|
809
|
+
setSourceError("");
|
|
810
|
+
setShowSourceDialog(false);
|
|
811
|
+
} catch {
|
|
812
|
+
setSourceError(t("menubar.invalidSource"));
|
|
813
|
+
}
|
|
679
814
|
};
|
|
680
815
|
const closeInsertMenu = () => {
|
|
681
816
|
setOpenMenuKey(null);
|
|
682
817
|
setShowImageInput(false);
|
|
683
818
|
setShowLinkInput(false);
|
|
819
|
+
setImageUploadError(null);
|
|
684
820
|
};
|
|
685
821
|
const handleImageUrl = (url, alt) => {
|
|
686
822
|
const safe = sanitizeUEditorUrl(url, "image");
|
|
@@ -691,21 +827,35 @@ var MenuBar = ({
|
|
|
691
827
|
closeInsertMenu();
|
|
692
828
|
};
|
|
693
829
|
const handleImageFiles = async (files) => {
|
|
694
|
-
if (
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
830
|
+
if (files.length === 0 || isUploadingImage) return;
|
|
831
|
+
setIsUploadingImage(true);
|
|
832
|
+
setImageUploadError(null);
|
|
833
|
+
const trackedPosition = trackEditorInsertionPosition(editor);
|
|
834
|
+
try {
|
|
835
|
+
const { images, hadError } = await resolveUEditorImageFiles(files, {
|
|
836
|
+
maxFileSize: maxImageFileSize,
|
|
837
|
+
allowedMimeTypes: allowedImageMimeTypes,
|
|
838
|
+
upload: uploadImage,
|
|
839
|
+
fallbackToDataUrl,
|
|
840
|
+
insertMode: imageInsertMode,
|
|
841
|
+
onError: onImageUploadError
|
|
842
|
+
});
|
|
843
|
+
if (!editor.isDestroyed && images.length > 0) {
|
|
844
|
+
const content = images.map((image) => ({
|
|
845
|
+
type: "image",
|
|
846
|
+
attrs: { src: image.src, alt: image.file.name }
|
|
847
|
+
}));
|
|
848
|
+
editor.commands.insertContentAt(trackedPosition.current, content, { updateSelection: false });
|
|
849
|
+
}
|
|
850
|
+
if (hadError) {
|
|
851
|
+
setImageUploadError(t("imageInput.uploadError"));
|
|
852
|
+
} else {
|
|
853
|
+
closeInsertMenu();
|
|
706
854
|
}
|
|
855
|
+
} finally {
|
|
856
|
+
trackedPosition.stop();
|
|
857
|
+
setIsUploadingImage(false);
|
|
707
858
|
}
|
|
708
|
-
closeInsertMenu();
|
|
709
859
|
};
|
|
710
860
|
const handleInsertTable = (rows, cols) => {
|
|
711
861
|
editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
|
|
@@ -724,12 +874,14 @@ var MenuBar = ({
|
|
|
724
874
|
/* @__PURE__ */ jsx(
|
|
725
875
|
DropdownMenuItem,
|
|
726
876
|
{
|
|
727
|
-
label: t("menubar.imageUpload"),
|
|
877
|
+
label: isUploadingImage ? t("imageInput.uploading") : t("menubar.imageUpload"),
|
|
728
878
|
icon: Upload,
|
|
729
879
|
onClick: () => fileInputRef.current?.click(),
|
|
730
|
-
closeOnSelect: false
|
|
880
|
+
closeOnSelect: false,
|
|
881
|
+
disabled: isUploadingImage
|
|
731
882
|
}
|
|
732
|
-
)
|
|
883
|
+
),
|
|
884
|
+
imageUploadError ? /* @__PURE__ */ jsx(DropdownMenuItem, { label: imageUploadError, disabled: true, destructive: true }) : null
|
|
733
885
|
] })
|
|
734
886
|
},
|
|
735
887
|
{ type: "separator" },
|
|
@@ -810,7 +962,13 @@ var MenuBar = ({
|
|
|
810
962
|
{
|
|
811
963
|
key: "view",
|
|
812
964
|
label: t("menubar.view"),
|
|
813
|
-
items: buildViewMenuItems(t,
|
|
965
|
+
items: buildViewMenuItems(t, editor, {
|
|
966
|
+
containerRef,
|
|
967
|
+
onSourceCode,
|
|
968
|
+
openSourceDialog,
|
|
969
|
+
onPreview: handlePreview,
|
|
970
|
+
openPreviewDialog
|
|
971
|
+
})
|
|
814
972
|
},
|
|
815
973
|
{
|
|
816
974
|
key: "insert",
|
|
@@ -834,10 +992,14 @@ var MenuBar = ({
|
|
|
834
992
|
accept: allowedImageMimeTypes.join(","),
|
|
835
993
|
multiple: true,
|
|
836
994
|
className: "hidden",
|
|
837
|
-
onChange: (e) =>
|
|
995
|
+
onChange: (e) => {
|
|
996
|
+
const files = Array.from(e.target.files ?? []);
|
|
997
|
+
e.target.value = "";
|
|
998
|
+
void handleImageFiles(files);
|
|
999
|
+
}
|
|
838
1000
|
}
|
|
839
1001
|
),
|
|
840
|
-
/* @__PURE__ */ jsxs("
|
|
1002
|
+
/* @__PURE__ */ jsxs("nav", { "aria-label": t("toolbar.showMenuBar"), className: "flex items-center gap-0.5 border-b border-border/35 bg-muted/20 px-1.5 py-0.5", children: [
|
|
841
1003
|
menus.map(({ key, label, items }) => /* @__PURE__ */ jsx(
|
|
842
1004
|
DropdownMenu,
|
|
843
1005
|
{
|
|
@@ -878,18 +1040,28 @@ var MenuBar = ({
|
|
|
878
1040
|
onClose: () => setShowSourceDialog(false),
|
|
879
1041
|
title: t("menubar.sourceCode"),
|
|
880
1042
|
size: "lg",
|
|
1043
|
+
portalContainer: modalPortalContainer,
|
|
881
1044
|
children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
882
1045
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("menubar.sourceCodeHint") }),
|
|
883
1046
|
/* @__PURE__ */ jsx(
|
|
884
1047
|
"textarea",
|
|
885
1048
|
{
|
|
1049
|
+
ref: sourceTextareaRef,
|
|
886
1050
|
"data-testid": "source-code-textarea",
|
|
1051
|
+
"aria-label": t("menubar.sourceCode"),
|
|
1052
|
+
name: "ueditor-source-html",
|
|
887
1053
|
className: "w-full h-64 font-mono text-xs p-3 bg-muted rounded-lg border border-border resize-y focus:outline-none focus:ring-2 focus:ring-primary/20",
|
|
888
1054
|
value: sourceHtml,
|
|
889
|
-
onChange: (e) =>
|
|
1055
|
+
onChange: (e) => {
|
|
1056
|
+
setSourceHtml(e.target.value);
|
|
1057
|
+
if (sourceError) setSourceError("");
|
|
1058
|
+
},
|
|
1059
|
+
"aria-invalid": Boolean(sourceError),
|
|
1060
|
+
"aria-describedby": sourceError ? sourceErrorId : void 0,
|
|
890
1061
|
spellCheck: false
|
|
891
1062
|
}
|
|
892
1063
|
),
|
|
1064
|
+
sourceError ? /* @__PURE__ */ jsx("p", { id: sourceErrorId, role: "alert", className: "text-xs text-destructive", children: sourceError }) : null,
|
|
893
1065
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 justify-end", children: [
|
|
894
1066
|
/* @__PURE__ */ jsx(
|
|
895
1067
|
"button",
|
|
@@ -920,6 +1092,7 @@ var MenuBar = ({
|
|
|
920
1092
|
onClose: () => setShowPreviewDialog(false),
|
|
921
1093
|
title: t("menubar.preview"),
|
|
922
1094
|
size: "full",
|
|
1095
|
+
portalContainer: modalPortalContainer,
|
|
923
1096
|
width: "min(1180px, calc(100vw - 2rem))",
|
|
924
1097
|
height: "min(860px, calc(100vh - 2rem))",
|
|
925
1098
|
className: "flex flex-col overflow-hidden rounded-xl md:rounded-2xl",
|
|
@@ -945,4 +1118,4 @@ var MenuBar = ({
|
|
|
945
1118
|
export {
|
|
946
1119
|
MenuBar
|
|
947
1120
|
};
|
|
948
|
-
//# sourceMappingURL=menu-bar-
|
|
1121
|
+
//# sourceMappingURL=menu-bar-DPCNNUX5.js.map
|