smartrte-react 0.1.5 → 0.1.7
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.js +423 -10
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/standalone/editor.js +68 -68
- package/package.json +13 -14
|
@@ -6,9 +6,11 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
6
6
|
const lastEmittedRef = useRef("");
|
|
7
7
|
const isComposingRef = useRef(false);
|
|
8
8
|
const fileInputRef = useRef(null);
|
|
9
|
+
const replaceTargetRef = useRef(null);
|
|
9
10
|
const [selectedImage, setSelectedImage] = useState(null);
|
|
10
11
|
const [imageOverlay, setImageOverlay] = useState(null);
|
|
11
12
|
const resizingRef = useRef(null);
|
|
13
|
+
const draggedImageRef = useRef(null);
|
|
12
14
|
const [showTableDialog, setShowTableDialog] = useState(false);
|
|
13
15
|
const [tableRows, setTableRows] = useState(3);
|
|
14
16
|
const [tableCols, setTableCols] = useState(3);
|
|
@@ -17,6 +19,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
17
19
|
const [tableMenu, setTableMenu] = useState(null);
|
|
18
20
|
const selectionRef = useRef(null);
|
|
19
21
|
const selectingRef = useRef(null);
|
|
22
|
+
const [imageMenu, setImageMenu] = useState(null);
|
|
20
23
|
const [showMediaManager, setShowMediaManager] = useState(false);
|
|
21
24
|
useEffect(() => {
|
|
22
25
|
const el = editableRef.current;
|
|
@@ -116,6 +119,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
116
119
|
}
|
|
117
120
|
const img = document.createElement("img");
|
|
118
121
|
img.src = src;
|
|
122
|
+
img.draggable = true;
|
|
119
123
|
img.style.maxWidth = "100%";
|
|
120
124
|
img.style.height = "auto";
|
|
121
125
|
img.style.display = "inline-block";
|
|
@@ -652,13 +656,36 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
652
656
|
gap: 8,
|
|
653
657
|
padding: 8,
|
|
654
658
|
borderBottom: "1px solid #eee",
|
|
655
|
-
background: "#
|
|
659
|
+
background: "#fff",
|
|
660
|
+
color: "#111",
|
|
656
661
|
position: "sticky",
|
|
657
662
|
top: 0,
|
|
658
663
|
zIndex: 1,
|
|
659
664
|
}, children: [media && (_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", multiple: true, style: { display: "none" }, onChange: (e) => {
|
|
660
|
-
|
|
661
|
-
|
|
665
|
+
const list = e.currentTarget.files;
|
|
666
|
+
if (list && list.length) {
|
|
667
|
+
if (replaceTargetRef.current) {
|
|
668
|
+
const img = replaceTargetRef.current;
|
|
669
|
+
replaceTargetRef.current = null;
|
|
670
|
+
const f = list[0];
|
|
671
|
+
if (f && f.type.startsWith("image/")) {
|
|
672
|
+
const reader = new FileReader();
|
|
673
|
+
reader.onload = () => {
|
|
674
|
+
const dataUrl = String(reader.result || "");
|
|
675
|
+
if (dataUrl) {
|
|
676
|
+
img.src = dataUrl;
|
|
677
|
+
setSelectedImage(img);
|
|
678
|
+
scheduleImageOverlay();
|
|
679
|
+
handleInput();
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
reader.readAsDataURL(f);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
handleLocalImageFiles(list);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
662
689
|
e.currentTarget.value = "";
|
|
663
690
|
} })), _jsxs("select", { defaultValue: "p", onChange: (e) => {
|
|
664
691
|
const val = e.target.value;
|
|
@@ -670,7 +697,116 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
670
697
|
applyFormatBlock("<h2>");
|
|
671
698
|
else if (val === "h3")
|
|
672
699
|
applyFormatBlock("<h3>");
|
|
673
|
-
}, title: "Paragraph/Heading",
|
|
700
|
+
}, title: "Paragraph/Heading", style: {
|
|
701
|
+
height: 32,
|
|
702
|
+
padding: "0 8px",
|
|
703
|
+
border: "1px solid #e5e7eb",
|
|
704
|
+
borderRadius: 6,
|
|
705
|
+
background: "#fff",
|
|
706
|
+
color: "#111",
|
|
707
|
+
}, 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", { title: "Bold", onClick: () => exec("bold"), style: {
|
|
708
|
+
height: 32,
|
|
709
|
+
minWidth: 32,
|
|
710
|
+
padding: "0 8px",
|
|
711
|
+
border: "1px solid #e5e7eb",
|
|
712
|
+
borderRadius: 6,
|
|
713
|
+
background: "#fff",
|
|
714
|
+
color: "#111",
|
|
715
|
+
}, children: _jsx("span", { style: { fontWeight: 700 }, children: "B" }) }), _jsx("button", { title: "Italic", onClick: () => exec("italic"), style: {
|
|
716
|
+
height: 32,
|
|
717
|
+
minWidth: 32,
|
|
718
|
+
padding: "0 8px",
|
|
719
|
+
border: "1px solid #e5e7eb",
|
|
720
|
+
borderRadius: 6,
|
|
721
|
+
background: "#fff",
|
|
722
|
+
fontStyle: "italic",
|
|
723
|
+
color: "#111",
|
|
724
|
+
}, children: "I" }), _jsx("button", { title: "Underline", onClick: () => exec("underline"), style: {
|
|
725
|
+
height: 32,
|
|
726
|
+
minWidth: 32,
|
|
727
|
+
padding: "0 8px",
|
|
728
|
+
border: "1px solid #e5e7eb",
|
|
729
|
+
borderRadius: 6,
|
|
730
|
+
background: "#fff",
|
|
731
|
+
textDecoration: "underline",
|
|
732
|
+
color: "#111",
|
|
733
|
+
}, children: "U" }), _jsx("button", { title: "Strikethrough", onClick: () => exec("strikeThrough"), style: {
|
|
734
|
+
height: 32,
|
|
735
|
+
minWidth: 32,
|
|
736
|
+
padding: "0 8px",
|
|
737
|
+
border: "1px solid #e5e7eb",
|
|
738
|
+
borderRadius: 6,
|
|
739
|
+
background: "#fff",
|
|
740
|
+
textDecoration: "line-through",
|
|
741
|
+
color: "#111",
|
|
742
|
+
}, children: "S" }), _jsx("button", { title: "Bulleted list", onClick: () => exec("insertUnorderedList"), style: {
|
|
743
|
+
height: 32,
|
|
744
|
+
padding: "0 10px",
|
|
745
|
+
border: "1px solid #e5e7eb",
|
|
746
|
+
borderRadius: 6,
|
|
747
|
+
background: "#fff",
|
|
748
|
+
color: "#111",
|
|
749
|
+
}, children: "\u2022 List" }), _jsx("button", { title: "Numbered list", onClick: () => exec("insertOrderedList"), style: {
|
|
750
|
+
height: 32,
|
|
751
|
+
padding: "0 10px",
|
|
752
|
+
border: "1px solid #e5e7eb",
|
|
753
|
+
borderRadius: 6,
|
|
754
|
+
background: "#fff",
|
|
755
|
+
color: "#111",
|
|
756
|
+
}, children: "1. List" }), _jsx("button", { title: "Blockquote", onClick: () => exec("formatBlock", "<blockquote>"), style: {
|
|
757
|
+
height: 32,
|
|
758
|
+
minWidth: 32,
|
|
759
|
+
padding: "0 8px",
|
|
760
|
+
border: "1px solid #e5e7eb",
|
|
761
|
+
borderRadius: 6,
|
|
762
|
+
background: "#fff",
|
|
763
|
+
color: "#111",
|
|
764
|
+
}, children: "\u275D" }), _jsx("button", { title: "Code block", onClick: () => exec("formatBlock", "<pre>"), style: {
|
|
765
|
+
height: 32,
|
|
766
|
+
minWidth: 36,
|
|
767
|
+
padding: "0 8px",
|
|
768
|
+
border: "1px solid #e5e7eb",
|
|
769
|
+
borderRadius: 6,
|
|
770
|
+
background: "#fff",
|
|
771
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo",
|
|
772
|
+
color: "#111",
|
|
773
|
+
}, children: "< />" }), formula && (_jsx("button", { title: "Insert formula", onClick: () => setShowFormulaDialog(true), style: {
|
|
774
|
+
height: 32,
|
|
775
|
+
minWidth: 32,
|
|
776
|
+
padding: "0 8px",
|
|
777
|
+
border: "1px solid #e5e7eb",
|
|
778
|
+
borderRadius: 6,
|
|
779
|
+
background: "#fff",
|
|
780
|
+
color: "#111",
|
|
781
|
+
}, children: "\u2211" })), _jsx("button", { title: "Insert link", onClick: insertLink, style: {
|
|
782
|
+
height: 32,
|
|
783
|
+
padding: "0 10px",
|
|
784
|
+
border: "1px solid #e5e7eb",
|
|
785
|
+
borderRadius: 6,
|
|
786
|
+
background: "#fff",
|
|
787
|
+
color: "#111",
|
|
788
|
+
}, children: "Link" }), _jsx("button", { title: "Remove link", onClick: () => exec("unlink"), style: {
|
|
789
|
+
height: 32,
|
|
790
|
+
padding: "0 10px",
|
|
791
|
+
border: "1px solid #e5e7eb",
|
|
792
|
+
borderRadius: 6,
|
|
793
|
+
background: "#fff",
|
|
794
|
+
color: "#111",
|
|
795
|
+
}, children: "Unlink" }), media && (_jsxs(_Fragment, { children: [_jsx("button", { title: "Insert image", onClick: insertImage, style: {
|
|
796
|
+
height: 32,
|
|
797
|
+
padding: "0 10px",
|
|
798
|
+
border: "1px solid #e5e7eb",
|
|
799
|
+
borderRadius: 6,
|
|
800
|
+
background: "#fff",
|
|
801
|
+
color: "#111",
|
|
802
|
+
}, children: "\uD83D\uDDBC\uFE0F Image" }), mediaManager && (_jsx("button", { title: "Open media manager", onClick: () => setShowMediaManager(true), style: {
|
|
803
|
+
height: 32,
|
|
804
|
+
padding: "0 10px",
|
|
805
|
+
border: "1px solid #e5e7eb",
|
|
806
|
+
borderRadius: 6,
|
|
807
|
+
background: "#fff",
|
|
808
|
+
color: "#111",
|
|
809
|
+
}, children: "\uD83D\uDCC1 Media" })), _jsxs("div", { style: {
|
|
674
810
|
display: "inline-flex",
|
|
675
811
|
gap: 4,
|
|
676
812
|
alignItems: "center",
|
|
@@ -684,7 +820,15 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
684
820
|
img.style.float = "none";
|
|
685
821
|
scheduleImageOverlay();
|
|
686
822
|
handleInput();
|
|
687
|
-
}, title: "Center",
|
|
823
|
+
}, title: "Center", style: {
|
|
824
|
+
height: 28,
|
|
825
|
+
minWidth: 28,
|
|
826
|
+
padding: "0 6px",
|
|
827
|
+
border: "1px solid #e5e7eb",
|
|
828
|
+
borderRadius: 6,
|
|
829
|
+
background: "#fff",
|
|
830
|
+
color: "#111",
|
|
831
|
+
}, children: "\u2299" }), _jsx("button", { onClick: () => {
|
|
688
832
|
const img = selectedImage;
|
|
689
833
|
if (!img)
|
|
690
834
|
return;
|
|
@@ -693,7 +837,15 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
693
837
|
img.style.margin = "0 8px 8px 0";
|
|
694
838
|
scheduleImageOverlay();
|
|
695
839
|
handleInput();
|
|
696
|
-
}, title: "Float left",
|
|
840
|
+
}, title: "Float left", style: {
|
|
841
|
+
height: 28,
|
|
842
|
+
minWidth: 28,
|
|
843
|
+
padding: "0 6px",
|
|
844
|
+
border: "1px solid #e5e7eb",
|
|
845
|
+
borderRadius: 6,
|
|
846
|
+
background: "#fff",
|
|
847
|
+
color: "#111",
|
|
848
|
+
}, children: "\u27F8" }), _jsx("button", { onClick: () => {
|
|
697
849
|
const img = selectedImage;
|
|
698
850
|
if (!img)
|
|
699
851
|
return;
|
|
@@ -702,7 +854,36 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
702
854
|
img.style.margin = "0 0 8px 8px";
|
|
703
855
|
scheduleImageOverlay();
|
|
704
856
|
handleInput();
|
|
705
|
-
}, title: "Float right",
|
|
857
|
+
}, title: "Float right", style: {
|
|
858
|
+
height: 28,
|
|
859
|
+
minWidth: 28,
|
|
860
|
+
padding: "0 6px",
|
|
861
|
+
border: "1px solid #e5e7eb",
|
|
862
|
+
borderRadius: 6,
|
|
863
|
+
background: "#fff",
|
|
864
|
+
color: "#111",
|
|
865
|
+
}, children: "\u27F9" })] })] })), table && (_jsx("button", { title: "Insert table", onClick: () => setShowTableDialog(true), style: {
|
|
866
|
+
height: 32,
|
|
867
|
+
padding: "0 10px",
|
|
868
|
+
border: "1px solid #e5e7eb",
|
|
869
|
+
borderRadius: 6,
|
|
870
|
+
background: "#fff",
|
|
871
|
+
color: "#111",
|
|
872
|
+
}, children: "\u2795 Table" })), _jsx("button", { title: "Undo", onClick: () => exec("undo"), style: {
|
|
873
|
+
height: 32,
|
|
874
|
+
padding: "0 10px",
|
|
875
|
+
border: "1px solid #e5e7eb",
|
|
876
|
+
borderRadius: 6,
|
|
877
|
+
background: "#fff",
|
|
878
|
+
color: "#111",
|
|
879
|
+
}, children: "\u238C Undo" }), _jsx("button", { title: "Redo", onClick: () => exec("redo"), style: {
|
|
880
|
+
height: 32,
|
|
881
|
+
padding: "0 10px",
|
|
882
|
+
border: "1px solid #e5e7eb",
|
|
883
|
+
borderRadius: 6,
|
|
884
|
+
background: "#fff",
|
|
885
|
+
color: "#111",
|
|
886
|
+
}, children: "\u293E Redo" })] }), media && mediaManager && (_jsx(MediaManager, { open: showMediaManager, onClose: () => setShowMediaManager(false), adapter: mediaManager, onSelect: (item) => {
|
|
706
887
|
if (item?.url)
|
|
707
888
|
insertImageAtSelection(item.url);
|
|
708
889
|
} })), table && showTableDialog && (_jsx("div", { style: {
|
|
@@ -862,10 +1043,65 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
862
1043
|
}
|
|
863
1044
|
}
|
|
864
1045
|
}, onDragOver: (e) => {
|
|
865
|
-
|
|
1046
|
+
// Allow dragging images within editor and file drops
|
|
1047
|
+
if (draggedImageRef.current ||
|
|
1048
|
+
e.dataTransfer?.types?.includes("Files")) {
|
|
866
1049
|
e.preventDefault();
|
|
867
1050
|
}
|
|
868
1051
|
}, onDrop: (e) => {
|
|
1052
|
+
// Move existing dragged image inside editor
|
|
1053
|
+
if (draggedImageRef.current) {
|
|
1054
|
+
e.preventDefault();
|
|
1055
|
+
const x = e.clientX;
|
|
1056
|
+
const y = e.clientY;
|
|
1057
|
+
let range = null;
|
|
1058
|
+
// @ts-ignore
|
|
1059
|
+
if (document.caretRangeFromPoint) {
|
|
1060
|
+
// @ts-ignore
|
|
1061
|
+
range = document.caretRangeFromPoint(x, y);
|
|
1062
|
+
}
|
|
1063
|
+
else if (document.caretPositionFromPoint) {
|
|
1064
|
+
const pos = document.caretPositionFromPoint(x, y);
|
|
1065
|
+
if (pos) {
|
|
1066
|
+
range = document.createRange();
|
|
1067
|
+
range.setStart(pos.offsetNode, pos.offset);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
const img = draggedImageRef.current;
|
|
1071
|
+
draggedImageRef.current = null;
|
|
1072
|
+
if (range &&
|
|
1073
|
+
img &&
|
|
1074
|
+
editableRef.current?.contains(range.commonAncestorContainer)) {
|
|
1075
|
+
// Avoid inserting inside the image itself
|
|
1076
|
+
if (range.startContainer === img || range.endContainer === img)
|
|
1077
|
+
return;
|
|
1078
|
+
// If dropping inside a link, insert right after the link element
|
|
1079
|
+
let container = range.commonAncestorContainer;
|
|
1080
|
+
let linkAncestor = null;
|
|
1081
|
+
let el = container;
|
|
1082
|
+
while (el && el !== editableRef.current) {
|
|
1083
|
+
if (el.tagName === "A") {
|
|
1084
|
+
linkAncestor = el;
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
el = el.parentElement;
|
|
1088
|
+
}
|
|
1089
|
+
if (linkAncestor) {
|
|
1090
|
+
linkAncestor.parentElement?.insertBefore(img, linkAncestor.nextSibling);
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
range.insertNode(img);
|
|
1094
|
+
}
|
|
1095
|
+
const r = document.createRange();
|
|
1096
|
+
r.setStartAfter(img);
|
|
1097
|
+
r.collapse(true);
|
|
1098
|
+
safeSelectRange(r);
|
|
1099
|
+
setSelectedImage(img);
|
|
1100
|
+
scheduleImageOverlay();
|
|
1101
|
+
handleInput();
|
|
1102
|
+
}
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
869
1105
|
if (media && e.dataTransfer?.files?.length) {
|
|
870
1106
|
e.preventDefault();
|
|
871
1107
|
// Try to move caret to drop point
|
|
@@ -901,6 +1137,30 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
901
1137
|
setSelectedImage(null);
|
|
902
1138
|
setImageOverlay(null);
|
|
903
1139
|
}
|
|
1140
|
+
}, onDragStart: (e) => {
|
|
1141
|
+
const t = e.target;
|
|
1142
|
+
if (t && t.tagName === "IMG") {
|
|
1143
|
+
draggedImageRef.current = t;
|
|
1144
|
+
try {
|
|
1145
|
+
e.dataTransfer?.setData("text/plain", "moving-image");
|
|
1146
|
+
e.dataTransfer.effectAllowed = "move";
|
|
1147
|
+
// Provide a subtle drag image
|
|
1148
|
+
const dt = e.dataTransfer;
|
|
1149
|
+
if (dt && typeof dt.setDragImage === "function") {
|
|
1150
|
+
const ghost = new Image();
|
|
1151
|
+
ghost.src = t.src;
|
|
1152
|
+
ghost.width = Math.min(120, t.width);
|
|
1153
|
+
ghost.height = Math.min(120, t.height);
|
|
1154
|
+
dt.setDragImage(ghost, 10, 10);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
catch { }
|
|
1158
|
+
}
|
|
1159
|
+
else {
|
|
1160
|
+
draggedImageRef.current = null;
|
|
1161
|
+
}
|
|
1162
|
+
}, onDragEnd: () => {
|
|
1163
|
+
draggedImageRef.current = null;
|
|
904
1164
|
}, style: {
|
|
905
1165
|
padding: 12,
|
|
906
1166
|
minHeight: typeof minHeight === "number" ? `${minHeight}px` : minHeight,
|
|
@@ -1008,6 +1268,19 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1008
1268
|
window.addEventListener("mousemove", onMove);
|
|
1009
1269
|
window.addEventListener("mouseup", onUp);
|
|
1010
1270
|
}, onContextMenu: (e) => {
|
|
1271
|
+
const target = e.target;
|
|
1272
|
+
if (target && target.tagName === "IMG") {
|
|
1273
|
+
e.preventDefault();
|
|
1274
|
+
const vw = window.innerWidth;
|
|
1275
|
+
const vh = window.innerHeight;
|
|
1276
|
+
const menuW = 220;
|
|
1277
|
+
const menuH = 200;
|
|
1278
|
+
const x = Math.max(8, Math.min(e.clientX, vw - menuW - 8));
|
|
1279
|
+
const y = Math.max(8, Math.min(e.clientY, vh - menuH - 8));
|
|
1280
|
+
setImageMenu({ x, y, img: target });
|
|
1281
|
+
setTableMenu(null);
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1011
1284
|
const cell = getClosestCell(e.target);
|
|
1012
1285
|
if (cell) {
|
|
1013
1286
|
e.preventDefault();
|
|
@@ -1021,6 +1294,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1021
1294
|
}
|
|
1022
1295
|
else {
|
|
1023
1296
|
setTableMenu(null);
|
|
1297
|
+
setImageMenu(null);
|
|
1024
1298
|
}
|
|
1025
1299
|
} }), selectedImage && imageOverlay && (_jsxs("div", { style: {
|
|
1026
1300
|
position: "fixed",
|
|
@@ -1029,7 +1303,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1029
1303
|
width: imageOverlay.width,
|
|
1030
1304
|
height: imageOverlay.height,
|
|
1031
1305
|
pointerEvents: "none",
|
|
1032
|
-
zIndex:
|
|
1306
|
+
zIndex: 49,
|
|
1033
1307
|
}, children: [_jsx("div", { style: {
|
|
1034
1308
|
position: "absolute",
|
|
1035
1309
|
inset: 0,
|
|
@@ -1145,6 +1419,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1145
1419
|
width: 200,
|
|
1146
1420
|
maxHeight: 260,
|
|
1147
1421
|
overflowY: "auto",
|
|
1422
|
+
color: "#111",
|
|
1148
1423
|
}, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { style: { fontWeight: 600, fontSize: 11, margin: "2px 6px 6px" }, children: "Table" }), _jsxs("div", { style: { display: "grid", gap: 4 }, children: [_jsxs("button", { style: {
|
|
1149
1424
|
display: "flex",
|
|
1150
1425
|
alignItems: "center",
|
|
@@ -1276,5 +1551,143 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1276
1551
|
}, onClick: () => {
|
|
1277
1552
|
deleteTable(tableMenu.cell);
|
|
1278
1553
|
setTableMenu(null);
|
|
1279
|
-
}, children: [_jsx("span", { children: "\uD83D\uDDD1" }), _jsx("span", { children: "Delete table" })] })] })] }) }))
|
|
1554
|
+
}, children: [_jsx("span", { children: "\uD83D\uDDD1" }), _jsx("span", { children: "Delete table" })] })] })] }) })), imageMenu && (_jsx("div", { style: { position: "fixed", inset: 0, zIndex: 60 }, onClick: () => setImageMenu(null), onContextMenu: (e) => {
|
|
1555
|
+
e.preventDefault();
|
|
1556
|
+
const vw = window.innerWidth;
|
|
1557
|
+
const vh = window.innerHeight;
|
|
1558
|
+
const menuW = 220;
|
|
1559
|
+
const menuH = 220;
|
|
1560
|
+
const x = Math.max(8, Math.min(e.clientX, vw - menuW - 8));
|
|
1561
|
+
const y = Math.max(8, Math.min(e.clientY, vh - menuH - 8));
|
|
1562
|
+
setImageMenu({ x, y, img: imageMenu.img });
|
|
1563
|
+
}, children: _jsxs("div", { style: {
|
|
1564
|
+
position: "fixed",
|
|
1565
|
+
left: imageMenu.x,
|
|
1566
|
+
top: imageMenu.y,
|
|
1567
|
+
background: "#fff",
|
|
1568
|
+
border: "1px solid #ddd",
|
|
1569
|
+
borderRadius: 8,
|
|
1570
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.18)",
|
|
1571
|
+
padding: 8,
|
|
1572
|
+
width: 220,
|
|
1573
|
+
color: "#111",
|
|
1574
|
+
}, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { style: { fontWeight: 600, fontSize: 11, margin: "2px 6px 6px" }, children: "Image" }), _jsxs("div", { style: { display: "grid", gap: 6 }, children: [_jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [_jsx("span", { style: { width: 48, fontSize: 12 }, children: "Link" }), _jsx("input", { defaultValue: imageMenu.img.parentElement?.tagName === "A"
|
|
1575
|
+
? imageMenu.img.parentElement.href
|
|
1576
|
+
: "", placeholder: "https://", onChange: (e) => {
|
|
1577
|
+
const url = e.target.value.trim();
|
|
1578
|
+
const curParent = imageMenu.img.parentElement;
|
|
1579
|
+
if (url) {
|
|
1580
|
+
if (curParent && curParent.tagName === "A") {
|
|
1581
|
+
curParent.href = url;
|
|
1582
|
+
}
|
|
1583
|
+
else {
|
|
1584
|
+
const a = document.createElement("a");
|
|
1585
|
+
a.href = url;
|
|
1586
|
+
curParent?.insertBefore(a, imageMenu.img);
|
|
1587
|
+
a.appendChild(imageMenu.img);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
else if (curParent && curParent.tagName === "A") {
|
|
1591
|
+
// unwrap
|
|
1592
|
+
curParent.parentElement?.insertBefore(imageMenu.img, curParent);
|
|
1593
|
+
curParent.remove();
|
|
1594
|
+
}
|
|
1595
|
+
handleInput();
|
|
1596
|
+
}, style: {
|
|
1597
|
+
flex: 1,
|
|
1598
|
+
padding: "4px 6px",
|
|
1599
|
+
border: "1px solid #eee",
|
|
1600
|
+
borderRadius: 4,
|
|
1601
|
+
color: "#111",
|
|
1602
|
+
background: "#fff",
|
|
1603
|
+
} })] }), _jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [_jsx("span", { style: { width: 48, fontSize: 12 }, children: "Target" }), _jsxs("select", { defaultValue: imageMenu.img.parentElement?.tagName === "A"
|
|
1604
|
+
? imageMenu.img.parentElement
|
|
1605
|
+
.target || "_self"
|
|
1606
|
+
: "_self", onChange: (e) => {
|
|
1607
|
+
const curParent = imageMenu.img.parentElement;
|
|
1608
|
+
if (curParent && curParent.tagName === "A") {
|
|
1609
|
+
curParent.target = e.target.value;
|
|
1610
|
+
handleInput();
|
|
1611
|
+
}
|
|
1612
|
+
}, style: {
|
|
1613
|
+
flex: 1,
|
|
1614
|
+
height: 28,
|
|
1615
|
+
padding: "0 6px",
|
|
1616
|
+
border: "1px solid #eee",
|
|
1617
|
+
borderRadius: 4,
|
|
1618
|
+
background: "#fff",
|
|
1619
|
+
color: "#111",
|
|
1620
|
+
}, children: [_jsx("option", { value: "_self", children: "Same tab" }), _jsx("option", { value: "_blank", children: "New tab" })] })] }), _jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [_jsx("span", { style: { width: 48, fontSize: 12 }, children: "Alt" }), _jsx("input", { defaultValue: imageMenu.img.alt || "", onChange: (e) => {
|
|
1621
|
+
imageMenu.img.alt = e.target.value;
|
|
1622
|
+
handleInput();
|
|
1623
|
+
}, style: {
|
|
1624
|
+
flex: 1,
|
|
1625
|
+
padding: "4px 6px",
|
|
1626
|
+
border: "1px solid #eee",
|
|
1627
|
+
borderRadius: 4,
|
|
1628
|
+
color: "#111",
|
|
1629
|
+
background: "#fff",
|
|
1630
|
+
} })] }), _jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [_jsx("span", { style: { width: 48, fontSize: 12 }, children: "Width" }), _jsx("input", { type: "number", min: 40, max: 2000, defaultValue: Math.round(imageMenu.img.getBoundingClientRect().width), onChange: (e) => {
|
|
1631
|
+
const v = Math.max(40, Math.min(2000, Number(e.target.value) || 0));
|
|
1632
|
+
imageMenu.img.style.width = v + "px";
|
|
1633
|
+
imageMenu.img.style.height = "auto";
|
|
1634
|
+
scheduleImageOverlay();
|
|
1635
|
+
}, style: {
|
|
1636
|
+
width: 90,
|
|
1637
|
+
padding: "4px 6px",
|
|
1638
|
+
border: "1px solid #eee",
|
|
1639
|
+
borderRadius: 4,
|
|
1640
|
+
color: "#111",
|
|
1641
|
+
background: "#fff",
|
|
1642
|
+
} }), _jsx("span", { style: { fontSize: 12 }, children: "px" })] }), _jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [_jsx("span", { style: { width: 48, fontSize: 12 }, children: "Radius" }), _jsx("input", { type: "number", min: 0, max: 200, defaultValue: parseInt((imageMenu.img.style.borderRadius || "0").toString()) || 0, onChange: (e) => {
|
|
1643
|
+
const v = Math.max(0, Math.min(200, Number(e.target.value) || 0));
|
|
1644
|
+
imageMenu.img.style.borderRadius = v + "px";
|
|
1645
|
+
handleInput();
|
|
1646
|
+
}, style: {
|
|
1647
|
+
width: 90,
|
|
1648
|
+
padding: "4px 6px",
|
|
1649
|
+
border: "1px solid #eee",
|
|
1650
|
+
borderRadius: 4,
|
|
1651
|
+
color: "#111",
|
|
1652
|
+
background: "#fff",
|
|
1653
|
+
} }), _jsx("span", { style: { fontSize: 12 }, children: "px" })] }), _jsxs("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [_jsx("span", { style: { width: 48, fontSize: 12 }, children: "Align" }), _jsx("button", { onClick: () => {
|
|
1654
|
+
const img = imageMenu.img;
|
|
1655
|
+
img.style.display = "block";
|
|
1656
|
+
img.style.margin = "0 auto";
|
|
1657
|
+
img.style.float = "none";
|
|
1658
|
+
scheduleImageOverlay();
|
|
1659
|
+
handleInput();
|
|
1660
|
+
}, children: "\u29BF" }), _jsx("button", { onClick: () => {
|
|
1661
|
+
const img = imageMenu.img;
|
|
1662
|
+
img.style.display = "inline";
|
|
1663
|
+
img.style.float = "left";
|
|
1664
|
+
img.style.margin = "0 8px 8px 0";
|
|
1665
|
+
scheduleImageOverlay();
|
|
1666
|
+
handleInput();
|
|
1667
|
+
}, children: "\u27F8" }), _jsx("button", { onClick: () => {
|
|
1668
|
+
const img = imageMenu.img;
|
|
1669
|
+
img.style.display = "inline";
|
|
1670
|
+
img.style.float = "right";
|
|
1671
|
+
img.style.margin = "0 0 8px 8px";
|
|
1672
|
+
scheduleImageOverlay();
|
|
1673
|
+
handleInput();
|
|
1674
|
+
}, children: "\u27F9" })] }), _jsxs("div", { style: { display: "flex", gap: 6 }, children: [_jsx("button", { onClick: () => {
|
|
1675
|
+
replaceTargetRef.current = imageMenu.img;
|
|
1676
|
+
fileInputRef.current?.click();
|
|
1677
|
+
}, children: "Replace\u2026" }), _jsx("button", { onClick: () => {
|
|
1678
|
+
const img = imageMenu.img;
|
|
1679
|
+
img.style.width = "";
|
|
1680
|
+
img.style.height = "auto";
|
|
1681
|
+
img.style.borderRadius = "";
|
|
1682
|
+
img.style.margin = "";
|
|
1683
|
+
img.style.float = "none";
|
|
1684
|
+
scheduleImageOverlay();
|
|
1685
|
+
handleInput();
|
|
1686
|
+
}, children: "Reset" })] }), _jsxs("div", { style: { display: "flex", gap: 6 }, children: [_jsx("button", { style: { color: "#b00020" }, onClick: () => {
|
|
1687
|
+
imageMenu.img.remove();
|
|
1688
|
+
setImageMenu(null);
|
|
1689
|
+
setSelectedImage(null);
|
|
1690
|
+
setImageOverlay(null);
|
|
1691
|
+
handleInput();
|
|
1692
|
+
}, children: "Delete" }), _jsx("button", { onClick: () => setImageMenu(null), children: "Close" })] })] })] }) }))] }));
|
|
1280
1693
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED