smartrte-react 0.1.4 → 0.1.5
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/ClassicEditor.d.ts +6 -1
- package/dist/components/ClassicEditor.js +56 -42
- package/dist/components/MediaManager.d.ts +31 -0
- package/dist/components/MediaManager.js +167 -0
- package/dist/index.d.ts +1 -0
- package/dist/standalone/classic-editor-embed.js +1 -1
- package/dist/standalone/editor.js +66 -66
- package/package.json +14 -13
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MediaManagerAdapter } from "./MediaManager";
|
|
1
2
|
type ClassicEditorProps = {
|
|
2
3
|
value?: string;
|
|
3
4
|
onChange?: (html: string) => void;
|
|
@@ -5,6 +6,10 @@ type ClassicEditorProps = {
|
|
|
5
6
|
minHeight?: number | string;
|
|
6
7
|
maxHeight?: number | string;
|
|
7
8
|
readOnly?: boolean;
|
|
9
|
+
table?: boolean;
|
|
10
|
+
media?: boolean;
|
|
11
|
+
formula?: boolean;
|
|
12
|
+
mediaManager?: MediaManagerAdapter;
|
|
8
13
|
};
|
|
9
|
-
export declare function ClassicEditor({ value, onChange, placeholder, minHeight, maxHeight, readOnly, }: ClassicEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function ClassicEditor({ value, onChange, placeholder, minHeight, maxHeight, readOnly, table, media, formula, mediaManager, }: ClassicEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
10
15
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
|
|
3
|
+
import { MediaManager } from "./MediaManager";
|
|
4
|
+
export function ClassicEditor({ value, onChange, placeholder = "Type here…", minHeight = 200, maxHeight = 500, readOnly = false, table = true, media = true, formula = true, mediaManager, }) {
|
|
4
5
|
const editableRef = useRef(null);
|
|
5
6
|
const lastEmittedRef = useRef("");
|
|
6
7
|
const isComposingRef = useRef(false);
|
|
@@ -16,6 +17,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
16
17
|
const [tableMenu, setTableMenu] = useState(null);
|
|
17
18
|
const selectionRef = useRef(null);
|
|
18
19
|
const selectingRef = useRef(null);
|
|
20
|
+
const [showMediaManager, setShowMediaManager] = useState(false);
|
|
19
21
|
useEffect(() => {
|
|
20
22
|
const el = editableRef.current;
|
|
21
23
|
if (!el)
|
|
@@ -62,6 +64,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
62
64
|
exec("createLink", url);
|
|
63
65
|
};
|
|
64
66
|
const insertImage = () => {
|
|
67
|
+
if (!media)
|
|
68
|
+
return;
|
|
65
69
|
fileInputRef.current?.click();
|
|
66
70
|
};
|
|
67
71
|
const scheduleImageOverlay = () => {
|
|
@@ -148,6 +152,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
148
152
|
const insertFormulaAtSelection = (tex) => {
|
|
149
153
|
if (!tex)
|
|
150
154
|
return;
|
|
155
|
+
if (!formula)
|
|
156
|
+
return;
|
|
151
157
|
try {
|
|
152
158
|
const host = editableRef.current;
|
|
153
159
|
if (!host)
|
|
@@ -229,6 +235,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
229
235
|
return s;
|
|
230
236
|
};
|
|
231
237
|
const handleLocalImageFiles = async (files) => {
|
|
238
|
+
if (!media)
|
|
239
|
+
return;
|
|
232
240
|
const list = Array.from(files).filter((f) => f.type.startsWith("image/"));
|
|
233
241
|
for (const f of list) {
|
|
234
242
|
await new Promise((resolve) => {
|
|
@@ -648,11 +656,11 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
648
656
|
position: "sticky",
|
|
649
657
|
top: 0,
|
|
650
658
|
zIndex: 1,
|
|
651
|
-
}, children: [_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", multiple: true, style: { display: "none" }, onChange: (e) => {
|
|
659
|
+
}, children: [media && (_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", multiple: true, style: { display: "none" }, onChange: (e) => {
|
|
652
660
|
if (e.currentTarget.files)
|
|
653
661
|
handleLocalImageFiles(e.currentTarget.files);
|
|
654
662
|
e.currentTarget.value = "";
|
|
655
|
-
} }), _jsxs("select", { defaultValue: "p", onChange: (e) => {
|
|
663
|
+
} })), _jsxs("select", { defaultValue: "p", onChange: (e) => {
|
|
656
664
|
const val = e.target.value;
|
|
657
665
|
if (val === "p")
|
|
658
666
|
applyFormatBlock("<p>");
|
|
@@ -662,39 +670,42 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
662
670
|
applyFormatBlock("<h2>");
|
|
663
671
|
else if (val === "h3")
|
|
664
672
|
applyFormatBlock("<h3>");
|
|
665
|
-
}, title: "Paragraph/Heading", children: [_jsx("option", { value: "p", children: "Paragraph" }), _jsx("option", { value: "h1", children: "Heading 1" }), _jsx("option", { value: "h2", children: "Heading 2" }), _jsx("option", { value: "h3", children: "Heading 3" })] }), _jsx("button", { onClick: () => exec("bold"), children: "B" }), _jsx("button", { onClick: () => exec("italic"), children: "I" }), _jsx("button", { onClick: () => exec("underline"), children: "U" }), _jsx("button", { onClick: () => exec("strikeThrough"), children: "S" }), _jsx("button", { onClick: () => exec("insertUnorderedList"), children: "\u2022 List" }), _jsx("button", { onClick: () => exec("insertOrderedList"), children: "1. List" }), _jsx("button", { onClick: () => exec("formatBlock", "<blockquote>"), children: "\u275D" }), _jsx("button", { onClick: () => exec("formatBlock", "<pre>"), children: "< />" }), _jsx("button", { title: "Formula", onClick: () => setShowFormulaDialog(true), children: "\u2211" }), _jsx("button", { onClick: insertLink, children: "Link" }), _jsx("button", { onClick: () => exec("unlink"), children: "Unlink" }), _jsx("button", { onClick: insertImage, children: "Image" }), _jsxs("div", { style: {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
673
|
+
}, title: "Paragraph/Heading", children: [_jsx("option", { value: "p", children: "Paragraph" }), _jsx("option", { value: "h1", children: "Heading 1" }), _jsx("option", { value: "h2", children: "Heading 2" }), _jsx("option", { value: "h3", children: "Heading 3" })] }), _jsx("button", { onClick: () => exec("bold"), children: "B" }), _jsx("button", { onClick: () => exec("italic"), children: "I" }), _jsx("button", { onClick: () => exec("underline"), children: "U" }), _jsx("button", { onClick: () => exec("strikeThrough"), children: "S" }), _jsx("button", { onClick: () => exec("insertUnorderedList"), children: "\u2022 List" }), _jsx("button", { onClick: () => exec("insertOrderedList"), children: "1. List" }), _jsx("button", { onClick: () => exec("formatBlock", "<blockquote>"), children: "\u275D" }), _jsx("button", { onClick: () => exec("formatBlock", "<pre>"), children: "< />" }), formula && (_jsx("button", { title: "Formula", onClick: () => setShowFormulaDialog(true), children: "\u2211" })), _jsx("button", { onClick: insertLink, children: "Link" }), _jsx("button", { onClick: () => exec("unlink"), children: "Unlink" }), media && (_jsxs(_Fragment, { children: [_jsx("button", { onClick: insertImage, children: "Image" }), mediaManager && (_jsx("button", { onClick: () => setShowMediaManager(true), children: "Media manager" })), _jsxs("div", { style: {
|
|
674
|
+
display: "inline-flex",
|
|
675
|
+
gap: 4,
|
|
676
|
+
alignItems: "center",
|
|
677
|
+
marginLeft: 6,
|
|
678
|
+
}, children: [_jsx("span", { style: { fontSize: 12, opacity: 0.7 }, children: "Image align:" }), _jsx("button", { onClick: () => {
|
|
679
|
+
const img = selectedImage;
|
|
680
|
+
if (!img)
|
|
681
|
+
return;
|
|
682
|
+
img.style.display = "block";
|
|
683
|
+
img.style.margin = "0 auto";
|
|
684
|
+
img.style.float = "none";
|
|
685
|
+
scheduleImageOverlay();
|
|
686
|
+
handleInput();
|
|
687
|
+
}, title: "Center", children: "\u2299" }), _jsx("button", { onClick: () => {
|
|
688
|
+
const img = selectedImage;
|
|
689
|
+
if (!img)
|
|
690
|
+
return;
|
|
691
|
+
img.style.display = "inline";
|
|
692
|
+
img.style.float = "left";
|
|
693
|
+
img.style.margin = "0 8px 8px 0";
|
|
694
|
+
scheduleImageOverlay();
|
|
695
|
+
handleInput();
|
|
696
|
+
}, title: "Float left", children: "\u27F8" }), _jsx("button", { onClick: () => {
|
|
697
|
+
const img = selectedImage;
|
|
698
|
+
if (!img)
|
|
699
|
+
return;
|
|
700
|
+
img.style.display = "inline";
|
|
701
|
+
img.style.float = "right";
|
|
702
|
+
img.style.margin = "0 0 8px 8px";
|
|
703
|
+
scheduleImageOverlay();
|
|
704
|
+
handleInput();
|
|
705
|
+
}, title: "Float right", children: "\u27F9" })] })] })), table && (_jsx("button", { onClick: () => setShowTableDialog(true), children: "+ Table" })), _jsx("button", { onClick: () => exec("undo"), children: "Undo" }), _jsx("button", { onClick: () => exec("redo"), children: "Redo" })] }), media && mediaManager && (_jsx(MediaManager, { open: showMediaManager, onClose: () => setShowMediaManager(false), adapter: mediaManager, onSelect: (item) => {
|
|
706
|
+
if (item?.url)
|
|
707
|
+
insertImageAtSelection(item.url);
|
|
708
|
+
} })), table && showTableDialog && (_jsx("div", { style: {
|
|
698
709
|
position: "fixed",
|
|
699
710
|
inset: 0,
|
|
700
711
|
background: "rgba(0,0,0,0.35)",
|
|
@@ -737,7 +748,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
737
748
|
}, children: [_jsx("button", { onClick: () => setShowTableDialog(false), children: "Cancel" }), _jsx("button", { onClick: () => {
|
|
738
749
|
insertTable();
|
|
739
750
|
setShowTableDialog(false);
|
|
740
|
-
}, children: "Insert" })] })] }) })), showFormulaDialog && (_jsx("div", { style: {
|
|
751
|
+
}, children: "Insert" })] })] }) })), formula && showFormulaDialog && (_jsx("div", { style: {
|
|
741
752
|
position: "fixed",
|
|
742
753
|
inset: 0,
|
|
743
754
|
background: "rgba(0,0,0,0.35)",
|
|
@@ -843,7 +854,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
843
854
|
handleInput();
|
|
844
855
|
}, onPaste: (e) => {
|
|
845
856
|
const items = e.clipboardData?.files;
|
|
846
|
-
if (items && items.length) {
|
|
857
|
+
if (media && items && items.length) {
|
|
847
858
|
const hasImage = Array.from(items).some((f) => f.type.startsWith("image/"));
|
|
848
859
|
if (hasImage) {
|
|
849
860
|
e.preventDefault();
|
|
@@ -855,7 +866,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
855
866
|
e.preventDefault();
|
|
856
867
|
}
|
|
857
868
|
}, onDrop: (e) => {
|
|
858
|
-
if (e.dataTransfer?.files?.length) {
|
|
869
|
+
if (media && e.dataTransfer?.files?.length) {
|
|
859
870
|
e.preventDefault();
|
|
860
871
|
// Try to move caret to drop point
|
|
861
872
|
const x = e.clientX;
|
|
@@ -904,7 +915,9 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
904
915
|
el.innerHTML = "<p><br></p>";
|
|
905
916
|
}
|
|
906
917
|
}, onKeyDown: (e) => {
|
|
907
|
-
if (
|
|
918
|
+
if (formula &&
|
|
919
|
+
(e.metaKey || e.ctrlKey) &&
|
|
920
|
+
String(e.key).toLowerCase() === "m") {
|
|
908
921
|
e.preventDefault();
|
|
909
922
|
setShowFormulaDialog(true);
|
|
910
923
|
return;
|
|
@@ -924,7 +937,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
924
937
|
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
925
938
|
const sel = window.getSelection();
|
|
926
939
|
const cell = getClosestCell(sel?.anchorNode || null);
|
|
927
|
-
if (
|
|
940
|
+
if (table &&
|
|
941
|
+
cell &&
|
|
928
942
|
cell.parentElement &&
|
|
929
943
|
cell.parentElement.parentElement) {
|
|
930
944
|
const row = cell.parentElement;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type MediaItem = {
|
|
2
|
+
id: string;
|
|
3
|
+
url: string;
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
sizeBytes?: number;
|
|
7
|
+
mimeType?: string;
|
|
8
|
+
hashHex?: string;
|
|
9
|
+
createdAt?: string;
|
|
10
|
+
title?: string;
|
|
11
|
+
alt?: string;
|
|
12
|
+
tags?: string[];
|
|
13
|
+
};
|
|
14
|
+
export type MediaSearchQuery = {
|
|
15
|
+
q?: string;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
mimePrefix?: string;
|
|
18
|
+
hashHex?: string;
|
|
19
|
+
page?: number;
|
|
20
|
+
pageSize?: number;
|
|
21
|
+
};
|
|
22
|
+
export type MediaManagerAdapter = {
|
|
23
|
+
upload: (files: File[]) => Promise<MediaItem[]>;
|
|
24
|
+
search: (query: MediaSearchQuery) => Promise<MediaItem[]>;
|
|
25
|
+
};
|
|
26
|
+
export declare function MediaManager(props: {
|
|
27
|
+
open: boolean;
|
|
28
|
+
onClose: () => void;
|
|
29
|
+
adapter: MediaManagerAdapter;
|
|
30
|
+
onSelect: (item: MediaItem) => void;
|
|
31
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
export function MediaManager(props) {
|
|
4
|
+
const { open, onClose, adapter, onSelect } = props;
|
|
5
|
+
const [activeTab, setActiveTab] = useState("upload");
|
|
6
|
+
const [uploading, setUploading] = useState(false);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
const [query, setQuery] = useState("");
|
|
9
|
+
const [results, setResults] = useState([]);
|
|
10
|
+
const fileInputRef = useRef(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!open)
|
|
13
|
+
return;
|
|
14
|
+
setError(null);
|
|
15
|
+
if (activeTab === "library") {
|
|
16
|
+
performSearch();
|
|
17
|
+
}
|
|
18
|
+
}, [open, activeTab]);
|
|
19
|
+
const performSearch = async () => {
|
|
20
|
+
try {
|
|
21
|
+
const items = await adapter.search({ q: query, mimePrefix: "image/" });
|
|
22
|
+
setResults(items || []);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
setError("Failed to search media.");
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const computeSha256Hex = async (file) => {
|
|
29
|
+
const buf = await file.arrayBuffer();
|
|
30
|
+
const digest = await crypto.subtle.digest("SHA-256", buf);
|
|
31
|
+
const bytes = new Uint8Array(digest);
|
|
32
|
+
let hex = "";
|
|
33
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
34
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
35
|
+
}
|
|
36
|
+
return hex;
|
|
37
|
+
};
|
|
38
|
+
const handleUploadFiles = async (files) => {
|
|
39
|
+
if (!files || files.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
const list = Array.from(files).filter((f) => f.type.startsWith("image/"));
|
|
42
|
+
if (list.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
setUploading(true);
|
|
45
|
+
setError(null);
|
|
46
|
+
try {
|
|
47
|
+
// Duplicate detection by content hash (best-effort, server should also verify)
|
|
48
|
+
const duplicates = [];
|
|
49
|
+
const toUpload = [];
|
|
50
|
+
for (const f of list) {
|
|
51
|
+
try {
|
|
52
|
+
const hash = await computeSha256Hex(f);
|
|
53
|
+
const hits = await adapter.search({ hashHex: hash });
|
|
54
|
+
if (hits && hits.length) {
|
|
55
|
+
duplicates.push(hits[0]);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
toUpload.push(f);
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
}
|
|
62
|
+
if (duplicates.length) {
|
|
63
|
+
// Prefer duplicates immediately
|
|
64
|
+
onSelect(duplicates[0]);
|
|
65
|
+
setUploading(false);
|
|
66
|
+
onClose();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (toUpload.length) {
|
|
70
|
+
const uploaded = await adapter.upload(toUpload);
|
|
71
|
+
if (uploaded && uploaded.length) {
|
|
72
|
+
onSelect(uploaded[0]);
|
|
73
|
+
onClose();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
setError("Upload failed. Try again.");
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
setUploading(false);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
if (!open)
|
|
85
|
+
return null;
|
|
86
|
+
return (_jsx("div", { style: {
|
|
87
|
+
position: "fixed",
|
|
88
|
+
inset: 0,
|
|
89
|
+
background: "rgba(0,0,0,0.35)",
|
|
90
|
+
display: "flex",
|
|
91
|
+
alignItems: "center",
|
|
92
|
+
justifyContent: "center",
|
|
93
|
+
zIndex: 80,
|
|
94
|
+
}, onClick: onClose, children: _jsxs("div", { style: {
|
|
95
|
+
background: "#fff",
|
|
96
|
+
width: 820,
|
|
97
|
+
maxWidth: "90vw",
|
|
98
|
+
maxHeight: "86vh",
|
|
99
|
+
borderRadius: 10,
|
|
100
|
+
boxShadow: "0 12px 32px rgba(0,0,0,0.22)",
|
|
101
|
+
display: "flex",
|
|
102
|
+
flexDirection: "column",
|
|
103
|
+
}, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { style: {
|
|
104
|
+
display: "flex",
|
|
105
|
+
alignItems: "center",
|
|
106
|
+
justifyContent: "space-between",
|
|
107
|
+
padding: "10px 14px",
|
|
108
|
+
borderBottom: "1px solid #eee",
|
|
109
|
+
}, children: [_jsxs("div", { style: { display: "flex", gap: 8 }, children: [_jsx("button", { onClick: () => setActiveTab("upload"), style: {
|
|
110
|
+
padding: "6px 10px",
|
|
111
|
+
borderRadius: 6,
|
|
112
|
+
border: "1px solid #ddd",
|
|
113
|
+
background: activeTab === "upload" ? "#f2f2f2" : "#fff",
|
|
114
|
+
}, children: "Upload" }), _jsx("button", { onClick: () => setActiveTab("library"), style: {
|
|
115
|
+
padding: "6px 10px",
|
|
116
|
+
borderRadius: 6,
|
|
117
|
+
border: "1px solid #ddd",
|
|
118
|
+
background: activeTab === "library" ? "#f2f2f2" : "#fff",
|
|
119
|
+
}, children: "Library" })] }), _jsx("button", { onClick: onClose, children: "\u2715" })] }), error && (_jsx("div", { style: { color: "#b00020", padding: "8px 14px" }, children: error })), activeTab === "upload" ? (_jsxs("div", { style: { padding: 16 }, children: [_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", multiple: true, style: { display: "none" }, onChange: (e) => handleUploadFiles(e.currentTarget.files) }), _jsx("div", { onClick: () => fileInputRef.current?.click(), onDragOver: (e) => {
|
|
120
|
+
e.preventDefault();
|
|
121
|
+
}, onDrop: (e) => {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
handleUploadFiles(e.dataTransfer.files);
|
|
124
|
+
}, style: {
|
|
125
|
+
border: "2px dashed #bbb",
|
|
126
|
+
borderRadius: 10,
|
|
127
|
+
padding: 24,
|
|
128
|
+
textAlign: "center",
|
|
129
|
+
color: "#333",
|
|
130
|
+
background: "#fafafa",
|
|
131
|
+
cursor: uploading ? "default" : "pointer",
|
|
132
|
+
opacity: uploading ? 0.7 : 1,
|
|
133
|
+
}, children: uploading ? "Uploading…" : "Click or drag images to upload" })] })) : (_jsxs("div", { style: {
|
|
134
|
+
padding: 16,
|
|
135
|
+
display: "flex",
|
|
136
|
+
flexDirection: "column",
|
|
137
|
+
gap: 12,
|
|
138
|
+
}, children: [_jsxs("div", { style: { display: "flex", gap: 8 }, children: [_jsx("input", { value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search images by name, tag, etc.", style: {
|
|
139
|
+
flex: 1,
|
|
140
|
+
padding: "6px 8px",
|
|
141
|
+
border: "1px solid #ddd",
|
|
142
|
+
borderRadius: 6,
|
|
143
|
+
} }), _jsx("button", { onClick: performSearch, children: "Search" })] }), _jsx("div", { style: {
|
|
144
|
+
display: "grid",
|
|
145
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(120px, 1fr))",
|
|
146
|
+
gap: 12,
|
|
147
|
+
overflowY: "auto",
|
|
148
|
+
paddingBottom: 16,
|
|
149
|
+
}, children: results.map((it) => (_jsxs("button", { onClick: () => {
|
|
150
|
+
onSelect(it);
|
|
151
|
+
onClose();
|
|
152
|
+
}, title: it.title || it.url, style: {
|
|
153
|
+
display: "block",
|
|
154
|
+
border: "1px solid #eee",
|
|
155
|
+
borderRadius: 8,
|
|
156
|
+
padding: 6,
|
|
157
|
+
background: "#fff",
|
|
158
|
+
textAlign: "center",
|
|
159
|
+
}, children: [_jsx("img", { src: it.url, alt: it.alt || "", style: {
|
|
160
|
+
maxWidth: "100%",
|
|
161
|
+
maxHeight: 100,
|
|
162
|
+
display: "block",
|
|
163
|
+
margin: "0 auto",
|
|
164
|
+
objectFit: "cover",
|
|
165
|
+
borderRadius: 6,
|
|
166
|
+
} }), _jsx("div", { style: { fontSize: 11, marginTop: 6, color: "#333" }, children: it.width && it.height ? `${it.width}×${it.height}` : "" })] }, it.id || it.url))) })] }))] }) }));
|
|
167
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ function ClassicEditorHost(props, ref) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
catch { }
|
|
40
|
-
}, placeholder: props.placeholder, minHeight: props.minHeight, maxHeight: props.maxHeight, readOnly: props.readOnly }) }));
|
|
40
|
+
}, placeholder: props.placeholder, minHeight: props.minHeight, maxHeight: props.maxHeight, readOnly: props.readOnly, table: props.table, media: props.media, formula: props.formula, mediaManager: props.mediaManager }) }));
|
|
41
41
|
}
|
|
42
42
|
const ClassicEditorHostWithRef = React.forwardRef(ClassicEditorHost);
|
|
43
43
|
function initClassicEditor(opts) {
|