smartrte-react 0.1.18 → 0.2.2
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/README.md +83 -15
- package/dist/components/ClassicEditor.d.ts +32 -1
- package/dist/components/ClassicEditor.js +949 -251
- package/dist/components/MediaManager.d.ts +7 -0
- package/dist/components/MediaManager.js +85 -29
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/standalone/classic-editor-embed.js +1 -1
- package/dist/theme.d.ts +3 -0
- package/dist/theme.js +78 -0
- package/package.json +13 -12
- package/dist/QuillEditor.d.ts +0 -8
- package/dist/QuillEditor.js +0 -34
- package/dist/app.d.ts +0 -6
- package/dist/app.js +0 -6
- package/dist/blots/CommentBlot.d.ts +0 -8
- package/dist/blots/CommentBlot.js +0 -17
- package/dist/blots/FormulaBlot.d.ts +0 -12
- package/dist/blots/FormulaBlot.js +0 -36
- package/dist/blots/MediaBlot.d.ts +0 -11
- package/dist/blots/MediaBlot.js +0 -37
- package/dist/blots/TableBlot.d.ts +0 -10
- package/dist/blots/TableBlot.js +0 -54
- package/dist/blots/index.d.ts +0 -5
- package/dist/blots/index.js +0 -12
- package/dist/components/DiagramEditor.d.ts +0 -5
- package/dist/components/DiagramEditor.js +0 -73
- package/dist/components/FormulaEditor.d.ts +0 -6
- package/dist/components/FormulaEditor.js +0 -86
- package/dist/components/InfoBox.d.ts +0 -7
- package/dist/components/InfoBox.js +0 -18
- package/dist/components/MCQBlock.d.ts +0 -13
- package/dist/components/MCQBlock.js +0 -29
- package/dist/components/SmartEditor.d.ts +0 -0
- package/dist/components/SmartEditor.js +0 -1
- package/dist/components/SmartTable.d.ts +0 -22
- package/dist/components/SmartTable.js +0 -629
- package/dist/components/TableContextMenu.d.ts +0 -11
- package/dist/components/TableContextMenu.js +0 -15
- package/dist/components/TableInsertDialog.d.ts +0 -7
- package/dist/components/TableInsertDialog.js +0 -42
- package/dist/hooks/useEditorSync.d.ts +0 -5
- package/dist/hooks/useEditorSync.js +0 -53
- package/dist/smart-editor.d.ts +0 -0
- package/dist/smart-editor.js +0 -1
- package/dist/standalone/editor.js +0 -241
|
@@ -3,6 +3,8 @@ import { useEffect, useRef, useState } from "react";
|
|
|
3
3
|
import { MediaManager } from "./MediaManager";
|
|
4
4
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
5
5
|
import mammoth from 'mammoth';
|
|
6
|
+
import JSZip from 'jszip';
|
|
7
|
+
import { ensureStyleSheet } from '../theme';
|
|
6
8
|
// Initialize PDF.js worker
|
|
7
9
|
if (typeof window !== 'undefined') {
|
|
8
10
|
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();
|
|
@@ -15,13 +17,16 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
15
17
|
{ name: "Times New Roman", value: "'Times New Roman', Times, serif" },
|
|
16
18
|
{ name: "Verdana", value: "Verdana, Geneva, sans-serif" },
|
|
17
19
|
{ name: "Courier New", value: "'Courier New', Courier, monospace" },
|
|
18
|
-
], defaultFont, }) {
|
|
20
|
+
], defaultFont, preserveFontFamily = false, preserveColors = false, preserveDocxStyles = true, theme = "light", className, }) {
|
|
21
|
+
ensureStyleSheet();
|
|
19
22
|
const editableRef = useRef(null);
|
|
20
23
|
const lastEmittedRef = useRef("");
|
|
21
24
|
const isComposingRef = useRef(false);
|
|
22
25
|
const fileInputRef = useRef(null);
|
|
23
26
|
const pdfInputRef = useRef(null);
|
|
24
27
|
const docxInputRef = useRef(null);
|
|
28
|
+
const htmlInputRef = useRef(null);
|
|
29
|
+
const mdInputRef = useRef(null);
|
|
25
30
|
const [loadingPdf, setLoadingPdf] = useState(false);
|
|
26
31
|
const [loadingDocx, setLoadingDocx] = useState(false);
|
|
27
32
|
// State for import confirmation
|
|
@@ -43,6 +48,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
43
48
|
const [imageMenu, setImageMenu] = useState(null);
|
|
44
49
|
const [showMediaManager, setShowMediaManager] = useState(false);
|
|
45
50
|
const [showColorPicker, setShowColorPicker] = useState(false);
|
|
51
|
+
const [showSpecialChars, setShowSpecialChars] = useState(false);
|
|
46
52
|
const [colorPickerType, setColorPickerType] = useState('text');
|
|
47
53
|
const savedRangeRef = useRef(null);
|
|
48
54
|
const [currentFontSize, setCurrentFontSize] = useState("");
|
|
@@ -91,27 +97,91 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
91
97
|
const exec = (command, valueArg) => {
|
|
92
98
|
try {
|
|
93
99
|
document.execCommand(command, false, valueArg);
|
|
94
|
-
|
|
95
|
-
const el = editableRef.current;
|
|
96
|
-
if (el && onChange) {
|
|
97
|
-
const html = el.innerHTML;
|
|
98
|
-
if (html !== lastEmittedRef.current) {
|
|
99
|
-
lastEmittedRef.current = html;
|
|
100
|
-
onChange(html);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
100
|
+
emitChange();
|
|
103
101
|
}
|
|
104
102
|
catch { }
|
|
105
103
|
};
|
|
106
104
|
const applyFormatBlock = (blockName) => {
|
|
107
105
|
exec("formatBlock", blockName);
|
|
108
106
|
};
|
|
107
|
+
const emitChange = () => {
|
|
108
|
+
const el = editableRef.current;
|
|
109
|
+
if (!el || !onChange)
|
|
110
|
+
return;
|
|
111
|
+
const html = el.innerHTML;
|
|
112
|
+
if (html !== lastEmittedRef.current) {
|
|
113
|
+
lastEmittedRef.current = html;
|
|
114
|
+
onChange(html);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
109
117
|
const insertLink = () => {
|
|
110
118
|
const url = window.prompt("Enter URL", "https://");
|
|
111
119
|
if (!url)
|
|
112
120
|
return;
|
|
113
121
|
exec("createLink", url);
|
|
114
122
|
};
|
|
123
|
+
const getSelectionRangeInEditor = () => {
|
|
124
|
+
const editor = editableRef.current;
|
|
125
|
+
if (!editor)
|
|
126
|
+
return null;
|
|
127
|
+
editor.focus();
|
|
128
|
+
const sel = window.getSelection();
|
|
129
|
+
if (sel && sel.rangeCount > 0) {
|
|
130
|
+
const range = sel.getRangeAt(0);
|
|
131
|
+
if (editor.contains(range.commonAncestorContainer))
|
|
132
|
+
return range;
|
|
133
|
+
}
|
|
134
|
+
if (savedRangeRef.current && editor.contains(savedRangeRef.current.commonAncestorContainer)) {
|
|
135
|
+
return savedRangeRef.current.cloneRange();
|
|
136
|
+
}
|
|
137
|
+
const range = document.createRange();
|
|
138
|
+
range.selectNodeContents(editor);
|
|
139
|
+
range.collapse(false);
|
|
140
|
+
return range;
|
|
141
|
+
};
|
|
142
|
+
const insertTextAtSelection = (text) => {
|
|
143
|
+
if (!text)
|
|
144
|
+
return;
|
|
145
|
+
try {
|
|
146
|
+
const range = getSelectionRangeInEditor();
|
|
147
|
+
if (!range)
|
|
148
|
+
return;
|
|
149
|
+
range.deleteContents();
|
|
150
|
+
const node = document.createTextNode(text);
|
|
151
|
+
range.insertNode(node);
|
|
152
|
+
const nextRange = document.createRange();
|
|
153
|
+
nextRange.setStartAfter(node);
|
|
154
|
+
nextRange.collapse(true);
|
|
155
|
+
safeSelectRange(nextRange);
|
|
156
|
+
handleInput();
|
|
157
|
+
}
|
|
158
|
+
catch { }
|
|
159
|
+
};
|
|
160
|
+
const toggleBlockquote = () => {
|
|
161
|
+
try {
|
|
162
|
+
const range = getSelectionRangeInEditor();
|
|
163
|
+
if (!range)
|
|
164
|
+
return;
|
|
165
|
+
let node = range.commonAncestorContainer;
|
|
166
|
+
if (node.nodeType === Node.TEXT_NODE)
|
|
167
|
+
node = node.parentElement;
|
|
168
|
+
const element = node;
|
|
169
|
+
const quote = element?.closest?.('blockquote');
|
|
170
|
+
if (quote && editableRef.current?.contains(quote)) {
|
|
171
|
+
const replacement = document.createElement('p');
|
|
172
|
+
replacement.innerHTML = quote.innerHTML || '<br>';
|
|
173
|
+
quote.parentElement?.replaceChild(replacement, quote);
|
|
174
|
+
const nextRange = document.createRange();
|
|
175
|
+
nextRange.selectNodeContents(replacement);
|
|
176
|
+
nextRange.collapse(false);
|
|
177
|
+
safeSelectRange(nextRange);
|
|
178
|
+
handleInput();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
exec("formatBlock", "<blockquote>");
|
|
182
|
+
}
|
|
183
|
+
catch { }
|
|
184
|
+
};
|
|
115
185
|
const applyFontSize = (size) => {
|
|
116
186
|
try {
|
|
117
187
|
// Update current font size state
|
|
@@ -393,11 +463,12 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
393
463
|
window.removeEventListener('touchend', onTouchEnd);
|
|
394
464
|
};
|
|
395
465
|
}, [table]);
|
|
396
|
-
const insertImageAtSelection = (
|
|
466
|
+
const insertImageAtSelection = (srcOrItem) => {
|
|
397
467
|
try {
|
|
398
468
|
const host = editableRef.current;
|
|
399
469
|
if (!host)
|
|
400
470
|
return;
|
|
471
|
+
const src = typeof srcOrItem === "string" ? srcOrItem : srcOrItem.url;
|
|
401
472
|
host.focus();
|
|
402
473
|
let sel = window.getSelection();
|
|
403
474
|
let range = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
|
|
@@ -413,7 +484,21 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
413
484
|
img.style.maxWidth = "100%";
|
|
414
485
|
img.style.height = "auto";
|
|
415
486
|
img.style.display = "inline-block";
|
|
416
|
-
img.alt = "image";
|
|
487
|
+
img.alt = typeof srcOrItem === "string" ? "image" : (srcOrItem.alt || srcOrItem.title || "image");
|
|
488
|
+
if (typeof srcOrItem !== "string") {
|
|
489
|
+
if (srcOrItem.title)
|
|
490
|
+
img.title = srcOrItem.title;
|
|
491
|
+
if (srcOrItem.license?.author)
|
|
492
|
+
img.dataset.licenseAuthor = srcOrItem.license.author;
|
|
493
|
+
if (srcOrItem.license?.licenseType)
|
|
494
|
+
img.dataset.licenseType = srcOrItem.license.licenseType;
|
|
495
|
+
if (srcOrItem.license?.licenseText)
|
|
496
|
+
img.dataset.licenseText = srcOrItem.license.licenseText;
|
|
497
|
+
if (srcOrItem.license?.sourceUrl)
|
|
498
|
+
img.dataset.licenseUrl = srcOrItem.license.sourceUrl;
|
|
499
|
+
if (srcOrItem.license?.workName)
|
|
500
|
+
img.dataset.workName = srcOrItem.license.workName;
|
|
501
|
+
}
|
|
417
502
|
if (range) {
|
|
418
503
|
range.insertNode(img);
|
|
419
504
|
}
|
|
@@ -769,7 +854,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
769
854
|
cellContents[colIdx] += styledTxt;
|
|
770
855
|
}
|
|
771
856
|
cellContents.forEach(content => {
|
|
772
|
-
rowHtml += `<td style="border:1px solid
|
|
857
|
+
rowHtml += `<td style="border:1px solid var(--srte-border);padding:8px;vertical-align:top;">${content || ' '}</td>`;
|
|
773
858
|
});
|
|
774
859
|
rowHtml += '</tr>';
|
|
775
860
|
tableHtml += rowHtml;
|
|
@@ -804,30 +889,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
804
889
|
closeTable();
|
|
805
890
|
fullHtml += html;
|
|
806
891
|
}
|
|
807
|
-
|
|
808
|
-
if (el) {
|
|
809
|
-
el.focus();
|
|
810
|
-
if (mode === 'replace') {
|
|
811
|
-
// Select all and replace
|
|
812
|
-
const range = document.createRange();
|
|
813
|
-
range.selectNodeContents(el);
|
|
814
|
-
const sel = window.getSelection();
|
|
815
|
-
sel?.removeAllRanges();
|
|
816
|
-
sel?.addRange(range);
|
|
817
|
-
exec("delete"); // Clear content safely
|
|
818
|
-
exec("insertHTML", fullHtml);
|
|
819
|
-
}
|
|
820
|
-
else {
|
|
821
|
-
// Append
|
|
822
|
-
const range = document.createRange();
|
|
823
|
-
range.selectNodeContents(el);
|
|
824
|
-
range.collapse(false); // End
|
|
825
|
-
const sel = window.getSelection();
|
|
826
|
-
sel?.removeAllRanges();
|
|
827
|
-
sel?.addRange(range);
|
|
828
|
-
exec("insertHTML", "<br>" + fullHtml);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
892
|
+
insertImportedHtml(fullHtml, mode);
|
|
831
893
|
}
|
|
832
894
|
catch (error) {
|
|
833
895
|
console.error('Error reading PDF:', error);
|
|
@@ -857,55 +919,14 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
857
919
|
try {
|
|
858
920
|
setLoadingDocx(true);
|
|
859
921
|
const arrayBuffer = await file.arrayBuffer();
|
|
860
|
-
const
|
|
861
|
-
|
|
922
|
+
const html = preserveDocxStyles
|
|
923
|
+
? await convertDocxToStyledHtml(arrayBuffer)
|
|
924
|
+
: await convertDocxWithMammoth(arrayBuffer);
|
|
862
925
|
if (html) {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
const tables = temp.querySelectorAll('table');
|
|
867
|
-
tables.forEach(tbl => {
|
|
868
|
-
tbl.style.borderCollapse = 'collapse';
|
|
869
|
-
tbl.style.minWidth = '100%';
|
|
870
|
-
// Browser parser auto-adds tbody, but we verify styles
|
|
871
|
-
const cells = tbl.querySelectorAll('td, th');
|
|
872
|
-
cells.forEach(cell => {
|
|
873
|
-
cell.style.border = '1px solid #000';
|
|
874
|
-
cell.style.padding = '8px';
|
|
875
|
-
cell.style.verticalAlign = 'top';
|
|
876
|
-
});
|
|
926
|
+
insertImportedHtml(`<div class="srte-preserve-colors">${html}</div>`, mode, {
|
|
927
|
+
preserveColors: preserveDocxStyles,
|
|
928
|
+
preserveDocumentLayout: preserveDocxStyles,
|
|
877
929
|
});
|
|
878
|
-
html = temp.innerHTML;
|
|
879
|
-
const el = editableRef.current;
|
|
880
|
-
if (el) {
|
|
881
|
-
el.focus();
|
|
882
|
-
if (mode === 'replace') {
|
|
883
|
-
const range = document.createRange();
|
|
884
|
-
range.selectNodeContents(el);
|
|
885
|
-
const sel = window.getSelection();
|
|
886
|
-
sel?.removeAllRanges();
|
|
887
|
-
sel?.addRange(range);
|
|
888
|
-
exec("delete");
|
|
889
|
-
exec("insertHTML", html);
|
|
890
|
-
}
|
|
891
|
-
else {
|
|
892
|
-
const range = document.createRange();
|
|
893
|
-
range.selectNodeContents(el);
|
|
894
|
-
range.collapse(false);
|
|
895
|
-
const sel = window.getSelection();
|
|
896
|
-
sel?.removeAllRanges();
|
|
897
|
-
sel?.addRange(range);
|
|
898
|
-
exec("insertHTML", "<br>" + html);
|
|
899
|
-
}
|
|
900
|
-
// Initialize handlers for the new content
|
|
901
|
-
// We use setTimeout to let the DOM settle after execCommand
|
|
902
|
-
setTimeout(() => {
|
|
903
|
-
ensureTableWrappers(el);
|
|
904
|
-
addTableResizeHandles();
|
|
905
|
-
fixNegativeMargins(el);
|
|
906
|
-
handleInput();
|
|
907
|
-
}, 10);
|
|
908
|
-
}
|
|
909
930
|
}
|
|
910
931
|
}
|
|
911
932
|
catch (error) {
|
|
@@ -915,6 +936,341 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
915
936
|
setLoadingDocx(false);
|
|
916
937
|
}
|
|
917
938
|
};
|
|
939
|
+
const convertDocxWithMammoth = async (arrayBuffer) => {
|
|
940
|
+
const result = await mammoth.convertToHtml({ arrayBuffer });
|
|
941
|
+
const temp = document.createElement('div');
|
|
942
|
+
temp.innerHTML = result.value;
|
|
943
|
+
enhanceImportedTables(temp);
|
|
944
|
+
return temp.innerHTML;
|
|
945
|
+
};
|
|
946
|
+
const convertDocxToStyledHtml = async (arrayBuffer) => {
|
|
947
|
+
try {
|
|
948
|
+
const zip = await JSZip.loadAsync(arrayBuffer);
|
|
949
|
+
const documentXml = await zip.file('word/document.xml')?.async('text');
|
|
950
|
+
if (!documentXml)
|
|
951
|
+
return convertDocxWithMammoth(arrayBuffer);
|
|
952
|
+
const parser = new DOMParser();
|
|
953
|
+
const doc = parser.parseFromString(documentXml, 'application/xml');
|
|
954
|
+
if (doc.querySelector('parsererror'))
|
|
955
|
+
return convertDocxWithMammoth(arrayBuffer);
|
|
956
|
+
const body = Array.from(doc.getElementsByTagName('*')).find((node) => node.localName === 'body');
|
|
957
|
+
if (!body)
|
|
958
|
+
return convertDocxWithMammoth(arrayBuffer);
|
|
959
|
+
const html = directChildren(body)
|
|
960
|
+
.filter((node) => node.localName !== 'sectPr')
|
|
961
|
+
.map((node) => {
|
|
962
|
+
if (node.localName === 'p')
|
|
963
|
+
return convertDocxParagraph(node);
|
|
964
|
+
if (node.localName === 'tbl')
|
|
965
|
+
return convertDocxTable(node);
|
|
966
|
+
return '';
|
|
967
|
+
})
|
|
968
|
+
.join('');
|
|
969
|
+
if (!html.trim())
|
|
970
|
+
return convertDocxWithMammoth(arrayBuffer);
|
|
971
|
+
const temp = document.createElement('div');
|
|
972
|
+
temp.innerHTML = html;
|
|
973
|
+
enhanceImportedTables(temp);
|
|
974
|
+
return temp.innerHTML;
|
|
975
|
+
}
|
|
976
|
+
catch (error) {
|
|
977
|
+
console.warn('Falling back to Mammoth DOCX import:', error);
|
|
978
|
+
return convertDocxWithMammoth(arrayBuffer);
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
const directChildren = (node) => Array.from(node.children);
|
|
982
|
+
const firstChildByName = (node, localName) => node
|
|
983
|
+
? directChildren(node).find((child) => child.localName === localName)
|
|
984
|
+
: undefined;
|
|
985
|
+
const childrenByName = (node, localName) => node
|
|
986
|
+
? directChildren(node).filter((child) => child.localName === localName)
|
|
987
|
+
: [];
|
|
988
|
+
const docxAttr = (node, name) => {
|
|
989
|
+
if (!node)
|
|
990
|
+
return '';
|
|
991
|
+
return (node.getAttribute(`w:${name}`) ||
|
|
992
|
+
node.getAttribute(name) ||
|
|
993
|
+
node.getAttributeNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', name) ||
|
|
994
|
+
'');
|
|
995
|
+
};
|
|
996
|
+
const docxHexColor = (value) => {
|
|
997
|
+
if (!value || value.toLowerCase() === 'auto')
|
|
998
|
+
return '';
|
|
999
|
+
const normalized = value.replace(/[^0-9a-f]/gi, '');
|
|
1000
|
+
return normalized.length === 6 ? `#${normalized}` : '';
|
|
1001
|
+
};
|
|
1002
|
+
const twipsToPt = (value) => {
|
|
1003
|
+
const n = Number(value);
|
|
1004
|
+
return Number.isFinite(n) ? `${Math.max(n / 20, 0)}pt` : '';
|
|
1005
|
+
};
|
|
1006
|
+
const halfPointsToPt = (value) => {
|
|
1007
|
+
const n = Number(value);
|
|
1008
|
+
return Number.isFinite(n) ? `${Math.max(n / 2, 1)}pt` : '';
|
|
1009
|
+
};
|
|
1010
|
+
const cssRules = (rules) => rules
|
|
1011
|
+
.filter(([, value]) => Boolean(value))
|
|
1012
|
+
.map(([name, value]) => `${name}: ${value}`)
|
|
1013
|
+
.join('; ');
|
|
1014
|
+
const styleAttr = (style) => (style ? ` style="${escapeHtml(style)}"` : '');
|
|
1015
|
+
const convertDocxParagraphStyle = (paragraph) => {
|
|
1016
|
+
const pPr = firstChildByName(paragraph, 'pPr');
|
|
1017
|
+
if (!pPr)
|
|
1018
|
+
return '';
|
|
1019
|
+
const spacing = firstChildByName(pPr, 'spacing');
|
|
1020
|
+
const jc = firstChildByName(pPr, 'jc');
|
|
1021
|
+
const indent = firstChildByName(pPr, 'ind');
|
|
1022
|
+
const borderBottom = firstChildByName(firstChildByName(pPr, 'pBdr'), 'bottom');
|
|
1023
|
+
const line = docxAttr(spacing, 'line');
|
|
1024
|
+
const lineRule = docxAttr(spacing, 'lineRule');
|
|
1025
|
+
return cssRules([
|
|
1026
|
+
['text-align', docxAttr(jc, 'val')],
|
|
1027
|
+
['margin-top', twipsToPt(docxAttr(spacing, 'before'))],
|
|
1028
|
+
['margin-bottom', twipsToPt(docxAttr(spacing, 'after'))],
|
|
1029
|
+
['margin-left', twipsToPt(docxAttr(indent, 'left'))],
|
|
1030
|
+
['text-indent', twipsToPt(docxAttr(indent, 'firstLine'))],
|
|
1031
|
+
['line-height', line && lineRule === 'auto' ? `${Number(line) / 240}` : ''],
|
|
1032
|
+
['border-bottom', docxBorderCss(borderBottom)],
|
|
1033
|
+
]);
|
|
1034
|
+
};
|
|
1035
|
+
const convertDocxRunStyle = (run) => {
|
|
1036
|
+
const rPr = firstChildByName(run, 'rPr');
|
|
1037
|
+
if (!rPr)
|
|
1038
|
+
return '';
|
|
1039
|
+
const color = docxHexColor(docxAttr(firstChildByName(rPr, 'color'), 'val'));
|
|
1040
|
+
const highlight = docxHexColor(docxAttr(firstChildByName(rPr, 'highlight'), 'val'));
|
|
1041
|
+
const shade = docxHexColor(docxAttr(firstChildByName(rPr, 'shd'), 'fill'));
|
|
1042
|
+
const size = halfPointsToPt(docxAttr(firstChildByName(rPr, 'sz'), 'val'));
|
|
1043
|
+
const underline = firstChildByName(rPr, 'u');
|
|
1044
|
+
return cssRules([
|
|
1045
|
+
['font-weight', firstChildByName(rPr, 'b') ? '700' : ''],
|
|
1046
|
+
['font-style', firstChildByName(rPr, 'i') ? 'italic' : ''],
|
|
1047
|
+
['text-decoration', underline ? 'underline' : ''],
|
|
1048
|
+
['color', color],
|
|
1049
|
+
['background-color', highlight || shade],
|
|
1050
|
+
['font-size', size],
|
|
1051
|
+
]);
|
|
1052
|
+
};
|
|
1053
|
+
const convertDocxRun = (run) => {
|
|
1054
|
+
const rPr = firstChildByName(run, 'rPr');
|
|
1055
|
+
const vertAlign = docxAttr(firstChildByName(rPr, 'vertAlign'), 'val');
|
|
1056
|
+
const style = convertDocxRunStyle(run);
|
|
1057
|
+
const content = directChildren(run)
|
|
1058
|
+
.map((child) => {
|
|
1059
|
+
if (child.localName === 't')
|
|
1060
|
+
return escapeHtml(child.textContent || '');
|
|
1061
|
+
if (child.localName === 'tab')
|
|
1062
|
+
return ' ';
|
|
1063
|
+
if (child.localName === 'br') {
|
|
1064
|
+
return docxAttr(child, 'type') === 'page'
|
|
1065
|
+
? '<hr class="srte-docx-page-break">'
|
|
1066
|
+
: '<br>';
|
|
1067
|
+
}
|
|
1068
|
+
return '';
|
|
1069
|
+
})
|
|
1070
|
+
.join('');
|
|
1071
|
+
if (!content)
|
|
1072
|
+
return '';
|
|
1073
|
+
const tag = vertAlign === 'superscript' ? 'sup' : vertAlign === 'subscript' ? 'sub' : 'span';
|
|
1074
|
+
return `<${tag}${styleAttr(style)}>${content}</${tag}>`;
|
|
1075
|
+
};
|
|
1076
|
+
const convertDocxParagraph = (paragraph) => {
|
|
1077
|
+
const style = convertDocxParagraphStyle(paragraph);
|
|
1078
|
+
const content = childrenByName(paragraph, 'r').map(convertDocxRun).join('');
|
|
1079
|
+
return `<p${styleAttr(style)}>${content || '<br>'}</p>`;
|
|
1080
|
+
};
|
|
1081
|
+
const docxBorderCss = (border) => {
|
|
1082
|
+
if (!border)
|
|
1083
|
+
return '';
|
|
1084
|
+
const val = docxAttr(border, 'val');
|
|
1085
|
+
if (!val || val === 'nil' || val === 'none')
|
|
1086
|
+
return '';
|
|
1087
|
+
const size = Number(docxAttr(border, 'sz')) || 4;
|
|
1088
|
+
const width = Math.max(size / 8, 0.5);
|
|
1089
|
+
const color = docxHexColor(docxAttr(border, 'color')) || '#d1d5db';
|
|
1090
|
+
return `${width}px solid ${color}`;
|
|
1091
|
+
};
|
|
1092
|
+
const convertDocxCellStyle = (cell) => {
|
|
1093
|
+
const tcPr = firstChildByName(cell, 'tcPr');
|
|
1094
|
+
const width = twipsToPt(docxAttr(firstChildByName(tcPr, 'tcW'), 'w'));
|
|
1095
|
+
const shade = docxHexColor(docxAttr(firstChildByName(tcPr, 'shd'), 'fill'));
|
|
1096
|
+
const borders = firstChildByName(tcPr, 'tcBorders');
|
|
1097
|
+
const top = docxBorderCss(firstChildByName(borders, 'top'));
|
|
1098
|
+
const right = docxBorderCss(firstChildByName(borders, 'right'));
|
|
1099
|
+
const bottom = docxBorderCss(firstChildByName(borders, 'bottom'));
|
|
1100
|
+
const left = docxBorderCss(firstChildByName(borders, 'left'));
|
|
1101
|
+
return cssRules([
|
|
1102
|
+
['width', width],
|
|
1103
|
+
['background-color', shade],
|
|
1104
|
+
['border-top', top],
|
|
1105
|
+
['border-right', right],
|
|
1106
|
+
['border-bottom', bottom],
|
|
1107
|
+
['border-left', left],
|
|
1108
|
+
['padding', '8px'],
|
|
1109
|
+
['vertical-align', 'top'],
|
|
1110
|
+
]);
|
|
1111
|
+
};
|
|
1112
|
+
const convertDocxTable = (table) => {
|
|
1113
|
+
const rows = childrenByName(table, 'tr')
|
|
1114
|
+
.map((row) => {
|
|
1115
|
+
const cells = childrenByName(row, 'tc')
|
|
1116
|
+
.map((cell) => {
|
|
1117
|
+
const content = directChildren(cell)
|
|
1118
|
+
.filter((child) => child.localName === 'p' || child.localName === 'tbl')
|
|
1119
|
+
.map((child) => child.localName === 'p' ? convertDocxParagraph(child) : convertDocxTable(child))
|
|
1120
|
+
.join('');
|
|
1121
|
+
return `<td${styleAttr(convertDocxCellStyle(cell))}>${content || '<p><br></p>'}</td>`;
|
|
1122
|
+
})
|
|
1123
|
+
.join('');
|
|
1124
|
+
return `<tr>${cells}</tr>`;
|
|
1125
|
+
})
|
|
1126
|
+
.join('');
|
|
1127
|
+
return `<table style="border-collapse: collapse; width: 100%; margin: 12px 0;"><tbody>${rows}</tbody></table>`;
|
|
1128
|
+
};
|
|
1129
|
+
const enhanceImportedTables = (root) => {
|
|
1130
|
+
const tables = root.querySelectorAll('table');
|
|
1131
|
+
tables.forEach(tbl => {
|
|
1132
|
+
tbl.style.borderCollapse = tbl.style.borderCollapse || 'collapse';
|
|
1133
|
+
tbl.style.width = tbl.style.width || '100%';
|
|
1134
|
+
const cells = tbl.querySelectorAll('td, th');
|
|
1135
|
+
cells.forEach(cell => {
|
|
1136
|
+
const el = cell;
|
|
1137
|
+
if (!el.style.border && !el.style.borderTop && !el.style.borderRight && !el.style.borderBottom && !el.style.borderLeft) {
|
|
1138
|
+
el.style.border = '1px solid #d1d5db';
|
|
1139
|
+
}
|
|
1140
|
+
el.style.padding = el.style.padding || '8px';
|
|
1141
|
+
el.style.verticalAlign = el.style.verticalAlign || 'top';
|
|
1142
|
+
});
|
|
1143
|
+
});
|
|
1144
|
+
};
|
|
1145
|
+
const escapeHtml = (value) => value
|
|
1146
|
+
.replace(/&/g, "&")
|
|
1147
|
+
.replace(/</g, "<")
|
|
1148
|
+
.replace(/>/g, ">");
|
|
1149
|
+
const markdownToHtml = (markdown) => {
|
|
1150
|
+
const lines = markdown.replace(/\r\n/g, "\n").split("\n");
|
|
1151
|
+
let html = "";
|
|
1152
|
+
let listType = null;
|
|
1153
|
+
const closeList = () => {
|
|
1154
|
+
if (listType) {
|
|
1155
|
+
html += `</${listType}>`;
|
|
1156
|
+
listType = null;
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
const inline = (text) => escapeHtml(text)
|
|
1160
|
+
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
|
|
1161
|
+
.replace(/\*([^*]+)\*/g, "<em>$1</em>")
|
|
1162
|
+
.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
1163
|
+
lines.forEach((line) => {
|
|
1164
|
+
const trimmed = line.trim();
|
|
1165
|
+
if (!trimmed) {
|
|
1166
|
+
closeList();
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
const heading = /^(#{1,6})\s+(.+)$/.exec(trimmed);
|
|
1170
|
+
if (heading) {
|
|
1171
|
+
closeList();
|
|
1172
|
+
const level = heading[1].length;
|
|
1173
|
+
html += `<h${level}>${inline(heading[2])}</h${level}>`;
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const bullet = /^[-*]\s+(.+)$/.exec(trimmed);
|
|
1177
|
+
if (bullet) {
|
|
1178
|
+
if (listType !== "ul") {
|
|
1179
|
+
closeList();
|
|
1180
|
+
html += "<ul>";
|
|
1181
|
+
listType = "ul";
|
|
1182
|
+
}
|
|
1183
|
+
html += `<li>${inline(bullet[1])}</li>`;
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
const numbered = /^\d+[.)]\s+(.+)$/.exec(trimmed);
|
|
1187
|
+
if (numbered) {
|
|
1188
|
+
if (listType !== "ol") {
|
|
1189
|
+
closeList();
|
|
1190
|
+
html += "<ol>";
|
|
1191
|
+
listType = "ol";
|
|
1192
|
+
}
|
|
1193
|
+
html += `<li>${inline(numbered[1])}</li>`;
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
if (trimmed.startsWith("> ")) {
|
|
1197
|
+
closeList();
|
|
1198
|
+
html += `<blockquote>${inline(trimmed.slice(2))}</blockquote>`;
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
closeList();
|
|
1202
|
+
html += `<p>${inline(trimmed)}</p>`;
|
|
1203
|
+
});
|
|
1204
|
+
closeList();
|
|
1205
|
+
return html;
|
|
1206
|
+
};
|
|
1207
|
+
const htmlToMarkdown = (html) => {
|
|
1208
|
+
const root = document.createElement("div");
|
|
1209
|
+
root.innerHTML = html;
|
|
1210
|
+
const walk = (node) => {
|
|
1211
|
+
if (node.nodeType === Node.TEXT_NODE)
|
|
1212
|
+
return node.textContent || "";
|
|
1213
|
+
if (!(node instanceof HTMLElement))
|
|
1214
|
+
return "";
|
|
1215
|
+
const content = Array.from(node.childNodes).map(walk).join("");
|
|
1216
|
+
const tag = node.tagName.toLowerCase();
|
|
1217
|
+
if (tag === "strong" || tag === "b")
|
|
1218
|
+
return `**${content}**`;
|
|
1219
|
+
if (tag === "em" || tag === "i")
|
|
1220
|
+
return `*${content}*`;
|
|
1221
|
+
if (tag === "code")
|
|
1222
|
+
return `\`${content}\``;
|
|
1223
|
+
if (tag === "br")
|
|
1224
|
+
return "\n";
|
|
1225
|
+
if (/h[1-6]/.test(tag))
|
|
1226
|
+
return `${"#".repeat(Number(tag[1]))} ${content.trim()}\n\n`;
|
|
1227
|
+
if (tag === "p")
|
|
1228
|
+
return `${content.trim()}\n\n`;
|
|
1229
|
+
if (tag === "li")
|
|
1230
|
+
return `- ${content.trim()}\n`;
|
|
1231
|
+
if (tag === "ul" || tag === "ol")
|
|
1232
|
+
return `${content}\n`;
|
|
1233
|
+
if (tag === "blockquote")
|
|
1234
|
+
return `> ${content.trim()}\n\n`;
|
|
1235
|
+
if (tag === "table")
|
|
1236
|
+
return `${node.outerHTML}\n\n`;
|
|
1237
|
+
if (tag === "img")
|
|
1238
|
+
return ` || ""})`;
|
|
1239
|
+
if (tag === "a")
|
|
1240
|
+
return `[${content}](${node.getAttribute("href") || ""})`;
|
|
1241
|
+
return content;
|
|
1242
|
+
};
|
|
1243
|
+
return Array.from(root.childNodes).map(walk).join("").replace(/\n{3,}/g, "\n\n").trim();
|
|
1244
|
+
};
|
|
1245
|
+
const importTextFile = async (files, type) => {
|
|
1246
|
+
if (!files || files.length === 0)
|
|
1247
|
+
return;
|
|
1248
|
+
const file = files[0];
|
|
1249
|
+
const text = await file.text();
|
|
1250
|
+
const html = type === "html" ? text : markdownToHtml(text);
|
|
1251
|
+
const el = editableRef.current;
|
|
1252
|
+
const hasContent = el && el.textContent && el.textContent.trim().length > 0;
|
|
1253
|
+
insertImportedHtml(html, hasContent ? "append" : "replace");
|
|
1254
|
+
};
|
|
1255
|
+
const downloadText = (filename, content, mimeType) => {
|
|
1256
|
+
const blob = new Blob([content], { type: mimeType });
|
|
1257
|
+
const url = URL.createObjectURL(blob);
|
|
1258
|
+
const link = document.createElement("a");
|
|
1259
|
+
link.href = url;
|
|
1260
|
+
link.download = filename;
|
|
1261
|
+
document.body.appendChild(link);
|
|
1262
|
+
link.click();
|
|
1263
|
+
link.remove();
|
|
1264
|
+
URL.revokeObjectURL(url);
|
|
1265
|
+
};
|
|
1266
|
+
const exportHtml = () => {
|
|
1267
|
+
const html = editableRef.current?.innerHTML || "";
|
|
1268
|
+
downloadText("smart-rte-export.html", html, "text/html");
|
|
1269
|
+
};
|
|
1270
|
+
const exportMarkdown = () => {
|
|
1271
|
+
const html = editableRef.current?.innerHTML || "";
|
|
1272
|
+
downloadText("smart-rte-export.md", htmlToMarkdown(html), "text/markdown");
|
|
1273
|
+
};
|
|
918
1274
|
const fixNegativeMargins = (root) => {
|
|
919
1275
|
try {
|
|
920
1276
|
const nodes = root.querySelectorAll('*');
|
|
@@ -927,6 +1283,152 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
927
1283
|
}
|
|
928
1284
|
catch { }
|
|
929
1285
|
};
|
|
1286
|
+
const cleanPastedHtml = (html, options = {}) => {
|
|
1287
|
+
const shouldPreserveColors = options.preserveColors ?? preserveColors;
|
|
1288
|
+
const shouldPreserveDocumentLayout = options.preserveDocumentLayout ?? false;
|
|
1289
|
+
const template = document.createElement('template');
|
|
1290
|
+
template.innerHTML = html
|
|
1291
|
+
.replace(/ /gi, ' ')
|
|
1292
|
+
.replace(/\u00a0/g, ' ')
|
|
1293
|
+
.replace(/[\u200b\u200c\u200d]/g, '');
|
|
1294
|
+
template.content.querySelectorAll('meta, link, style, script').forEach((node) => node.remove());
|
|
1295
|
+
const allowedStyleNames = new Set([
|
|
1296
|
+
'font-weight',
|
|
1297
|
+
'font-style',
|
|
1298
|
+
'text-decoration',
|
|
1299
|
+
'text-align',
|
|
1300
|
+
'vertical-align',
|
|
1301
|
+
'border',
|
|
1302
|
+
'border-top',
|
|
1303
|
+
'border-right',
|
|
1304
|
+
'border-bottom',
|
|
1305
|
+
'border-left',
|
|
1306
|
+
'border-collapse',
|
|
1307
|
+
'padding',
|
|
1308
|
+
'padding-top',
|
|
1309
|
+
'padding-right',
|
|
1310
|
+
'padding-bottom',
|
|
1311
|
+
'padding-left',
|
|
1312
|
+
'list-style-type',
|
|
1313
|
+
'white-space',
|
|
1314
|
+
]);
|
|
1315
|
+
if (preserveFontFamily)
|
|
1316
|
+
allowedStyleNames.add('font-family');
|
|
1317
|
+
if (shouldPreserveColors) {
|
|
1318
|
+
allowedStyleNames.add('color');
|
|
1319
|
+
allowedStyleNames.add('background');
|
|
1320
|
+
allowedStyleNames.add('background-color');
|
|
1321
|
+
}
|
|
1322
|
+
if (shouldPreserveDocumentLayout) {
|
|
1323
|
+
[
|
|
1324
|
+
'font-size',
|
|
1325
|
+
'line-height',
|
|
1326
|
+
'margin',
|
|
1327
|
+
'margin-top',
|
|
1328
|
+
'margin-right',
|
|
1329
|
+
'margin-bottom',
|
|
1330
|
+
'margin-left',
|
|
1331
|
+
'text-indent',
|
|
1332
|
+
'width',
|
|
1333
|
+
'min-width',
|
|
1334
|
+
].forEach((name) => allowedStyleNames.add(name));
|
|
1335
|
+
}
|
|
1336
|
+
template.content.querySelectorAll('*').forEach((node) => {
|
|
1337
|
+
const className = node.getAttribute('class');
|
|
1338
|
+
if (className !== 'srte-preserve-colors')
|
|
1339
|
+
node.removeAttribute('class');
|
|
1340
|
+
node.removeAttribute('id');
|
|
1341
|
+
if (!shouldPreserveDocumentLayout) {
|
|
1342
|
+
node.removeAttribute('width');
|
|
1343
|
+
node.removeAttribute('height');
|
|
1344
|
+
}
|
|
1345
|
+
const style = node.getAttribute('style');
|
|
1346
|
+
if (!style)
|
|
1347
|
+
return;
|
|
1348
|
+
const safeRules = style
|
|
1349
|
+
.split(';')
|
|
1350
|
+
.map((rule) => rule.trim())
|
|
1351
|
+
.filter(Boolean)
|
|
1352
|
+
.filter((rule) => {
|
|
1353
|
+
const separator = rule.indexOf(':');
|
|
1354
|
+
if (separator === -1)
|
|
1355
|
+
return false;
|
|
1356
|
+
const name = rule.slice(0, separator).trim().toLowerCase();
|
|
1357
|
+
const value = rule.slice(separator + 1).trim().toLowerCase();
|
|
1358
|
+
if (!allowedStyleNames.has(name))
|
|
1359
|
+
return false;
|
|
1360
|
+
if (value.includes('position') || value.includes('expression') || value.includes('javascript:'))
|
|
1361
|
+
return false;
|
|
1362
|
+
if (name === 'white-space' && value !== 'pre-wrap')
|
|
1363
|
+
return false;
|
|
1364
|
+
if ((name === 'width' || name === 'min-width') && !/^[\d.]+(px|pt|em|rem|%)$/.test(value))
|
|
1365
|
+
return false;
|
|
1366
|
+
return true;
|
|
1367
|
+
});
|
|
1368
|
+
if (safeRules.length)
|
|
1369
|
+
node.setAttribute('style', safeRules.join('; '));
|
|
1370
|
+
else
|
|
1371
|
+
node.removeAttribute('style');
|
|
1372
|
+
});
|
|
1373
|
+
return template.innerHTML;
|
|
1374
|
+
};
|
|
1375
|
+
const normalizeEditorContent = () => {
|
|
1376
|
+
const el = editableRef.current;
|
|
1377
|
+
if (!el)
|
|
1378
|
+
return;
|
|
1379
|
+
fixNegativeMargins(el);
|
|
1380
|
+
ensureTableWrappers(el);
|
|
1381
|
+
addTableResizeHandles();
|
|
1382
|
+
};
|
|
1383
|
+
const insertHtmlAtEnd = (html) => {
|
|
1384
|
+
const el = editableRef.current;
|
|
1385
|
+
if (!el)
|
|
1386
|
+
return;
|
|
1387
|
+
el.focus();
|
|
1388
|
+
const range = document.createRange();
|
|
1389
|
+
range.selectNodeContents(el);
|
|
1390
|
+
range.collapse(false);
|
|
1391
|
+
const sel = window.getSelection();
|
|
1392
|
+
sel?.removeAllRanges();
|
|
1393
|
+
sel?.addRange(range);
|
|
1394
|
+
const separator = el.textContent?.trim() ? '<p><br></p>' : '';
|
|
1395
|
+
document.execCommand('insertHTML', false, `${separator}${html}`);
|
|
1396
|
+
};
|
|
1397
|
+
const replaceEditorHtml = (html) => {
|
|
1398
|
+
const el = editableRef.current;
|
|
1399
|
+
if (!el)
|
|
1400
|
+
return;
|
|
1401
|
+
el.innerHTML = html;
|
|
1402
|
+
el.focus();
|
|
1403
|
+
const range = document.createRange();
|
|
1404
|
+
range.selectNodeContents(el);
|
|
1405
|
+
range.collapse(false);
|
|
1406
|
+
const sel = window.getSelection();
|
|
1407
|
+
sel?.removeAllRanges();
|
|
1408
|
+
sel?.addRange(range);
|
|
1409
|
+
};
|
|
1410
|
+
const insertImportedHtml = (html, mode, cleanOptions) => {
|
|
1411
|
+
try {
|
|
1412
|
+
const cleanHtml = cleanPastedHtml(html, cleanOptions);
|
|
1413
|
+
if (mode === 'replace')
|
|
1414
|
+
replaceEditorHtml(cleanHtml);
|
|
1415
|
+
else
|
|
1416
|
+
insertHtmlAtEnd(cleanHtml);
|
|
1417
|
+
normalizeEditorContent();
|
|
1418
|
+
emitChange();
|
|
1419
|
+
}
|
|
1420
|
+
catch (error) {
|
|
1421
|
+
console.error('Error inserting imported content:', error);
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
const insertCleanHtml = (html) => {
|
|
1425
|
+
try {
|
|
1426
|
+
document.execCommand("insertHTML", false, cleanPastedHtml(html));
|
|
1427
|
+
normalizeEditorContent();
|
|
1428
|
+
emitChange();
|
|
1429
|
+
}
|
|
1430
|
+
catch { }
|
|
1431
|
+
};
|
|
930
1432
|
const ensureTableWrappers = (root) => {
|
|
931
1433
|
try {
|
|
932
1434
|
const tables = root.querySelectorAll('table');
|
|
@@ -987,7 +1489,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
987
1489
|
html += "<tr>";
|
|
988
1490
|
for (let c = 0; c < safeCols; c++) {
|
|
989
1491
|
html +=
|
|
990
|
-
'<td style="border:1px solid
|
|
1492
|
+
'<td style="border:1px solid var(--srte-border);padding:6px;min-width:60px;"> </td>';
|
|
991
1493
|
}
|
|
992
1494
|
html += "</tr>";
|
|
993
1495
|
}
|
|
@@ -1119,8 +1621,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1119
1621
|
continue;
|
|
1120
1622
|
cell.__rtePrevBg =
|
|
1121
1623
|
cell.style.background || "";
|
|
1122
|
-
cell.style.background = "
|
|
1123
|
-
cell.style.outline = "2px solid
|
|
1624
|
+
cell.style.background = "var(--srte-accent-bg)";
|
|
1625
|
+
cell.style.outline = "2px solid var(--srte-accent)";
|
|
1124
1626
|
cell.style.outlineOffset = "-2px";
|
|
1125
1627
|
}
|
|
1126
1628
|
}
|
|
@@ -1189,7 +1691,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1189
1691
|
const numCols = Array.from(row.children).filter((c) => ["TD", "TH"].includes(c.tagName)).length;
|
|
1190
1692
|
for (let i = 0; i < numCols; i++) {
|
|
1191
1693
|
const td = document.createElement("td");
|
|
1192
|
-
td.style.border = "1px solid
|
|
1694
|
+
td.style.border = "1px solid var(--srte-border)";
|
|
1193
1695
|
td.style.padding = "6px";
|
|
1194
1696
|
td.style.minWidth = "60px";
|
|
1195
1697
|
td.innerHTML = " ";
|
|
@@ -1219,7 +1721,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1219
1721
|
for (const r of rows) {
|
|
1220
1722
|
const cells = Array.from(r.children).filter((c) => ["TD", "TH"].includes(c.tagName));
|
|
1221
1723
|
const td = document.createElement("td");
|
|
1222
|
-
td.style.border = "1px solid
|
|
1724
|
+
td.style.border = "1px solid var(--srte-border)";
|
|
1223
1725
|
td.style.padding = "6px";
|
|
1224
1726
|
td.style.minWidth = "60px";
|
|
1225
1727
|
td.innerHTML = " ";
|
|
@@ -1252,7 +1754,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1252
1754
|
const replacement = document.createElement(isTh ? "td" : "th");
|
|
1253
1755
|
replacement.innerHTML = cell.innerHTML || " ";
|
|
1254
1756
|
replacement.style.border =
|
|
1255
|
-
cell.style.border || "1px solid
|
|
1757
|
+
cell.style.border || "1px solid var(--srte-border)";
|
|
1256
1758
|
replacement.style.padding = cell.style.padding || "6px";
|
|
1257
1759
|
replacement.style.minWidth = cell.style.minWidth || "60px";
|
|
1258
1760
|
cell.parentElement?.replaceChild(replacement, cell);
|
|
@@ -1280,7 +1782,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1280
1782
|
const currentRow = Array.from(tbody.querySelectorAll("tr"))[rIdx];
|
|
1281
1783
|
for (let j = 1; j < cs; j++) {
|
|
1282
1784
|
const td = document.createElement("td");
|
|
1283
|
-
td.style.border = "1px solid
|
|
1785
|
+
td.style.border = "1px solid var(--srte-border)";
|
|
1284
1786
|
td.style.padding = "6px";
|
|
1285
1787
|
td.style.minWidth = "60px";
|
|
1286
1788
|
td.innerHTML = " ";
|
|
@@ -1293,7 +1795,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1293
1795
|
const row = Array.from(tbody.querySelectorAll("tr"))[rIdx + i];
|
|
1294
1796
|
for (let j = 0; j < cs; j++) {
|
|
1295
1797
|
const td = document.createElement("td");
|
|
1296
|
-
td.style.border = "1px solid
|
|
1798
|
+
td.style.border = "1px solid var(--srte-border)";
|
|
1297
1799
|
td.style.padding = "6px";
|
|
1298
1800
|
td.style.minWidth = "60px";
|
|
1299
1801
|
td.innerHTML = " ";
|
|
@@ -1319,7 +1821,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1319
1821
|
if (shouldMakeHeader && !isTh) {
|
|
1320
1822
|
const th = document.createElement("th");
|
|
1321
1823
|
th.innerHTML = c.innerHTML || " ";
|
|
1322
|
-
th.style.border = c.style.border || "1px solid
|
|
1824
|
+
th.style.border = c.style.border || "1px solid var(--srte-border)";
|
|
1323
1825
|
th.style.padding = c.style.padding || "6px";
|
|
1324
1826
|
th.style.minWidth = c.style.minWidth || "60px";
|
|
1325
1827
|
firstRow.replaceChild(th, c);
|
|
@@ -1327,12 +1829,33 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1327
1829
|
else if (!shouldMakeHeader && isTh) {
|
|
1328
1830
|
const td = document.createElement("td");
|
|
1329
1831
|
td.innerHTML = c.innerHTML || " ";
|
|
1330
|
-
td.style.border = c.style.border || "1px solid
|
|
1832
|
+
td.style.border = c.style.border || "1px solid var(--srte-border)";
|
|
1331
1833
|
td.style.padding = c.style.padding || "6px";
|
|
1332
1834
|
td.style.minWidth = c.style.minWidth || "60px";
|
|
1333
1835
|
firstRow.replaceChild(td, c);
|
|
1334
1836
|
}
|
|
1335
1837
|
}
|
|
1838
|
+
handleInput();
|
|
1839
|
+
};
|
|
1840
|
+
const toggleHeaderColumn = (cell) => {
|
|
1841
|
+
const pos = getCellPosition(cell);
|
|
1842
|
+
if (!pos)
|
|
1843
|
+
return;
|
|
1844
|
+
const { tbody, cIdx } = pos;
|
|
1845
|
+
const rows = Array.from(tbody.querySelectorAll("tr"));
|
|
1846
|
+
const columnCells = rows
|
|
1847
|
+
.map((row) => cellsOfRow(row)[cIdx])
|
|
1848
|
+
.filter(Boolean);
|
|
1849
|
+
const shouldMakeHeader = columnCells.some((c) => c.tagName !== "TH");
|
|
1850
|
+
for (const c of columnCells) {
|
|
1851
|
+
const replacement = document.createElement(shouldMakeHeader ? "th" : "td");
|
|
1852
|
+
replacement.innerHTML = c.innerHTML || " ";
|
|
1853
|
+
replacement.style.border = c.style.border || "1px solid var(--srte-border)";
|
|
1854
|
+
replacement.style.padding = c.style.padding || "6px";
|
|
1855
|
+
replacement.style.minWidth = c.style.minWidth || "60px";
|
|
1856
|
+
c.parentElement?.replaceChild(replacement, c);
|
|
1857
|
+
}
|
|
1858
|
+
handleInput();
|
|
1336
1859
|
};
|
|
1337
1860
|
const applyBgToSelection = (hex, fallbackCell) => {
|
|
1338
1861
|
const sel = selectionRef.current;
|
|
@@ -1495,15 +2018,17 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1495
2018
|
});
|
|
1496
2019
|
});
|
|
1497
2020
|
};
|
|
1498
|
-
|
|
1499
|
-
|
|
2021
|
+
const editorClass = `srte-editor${theme === 'dark' ? ' srte-dark' : ''}${className ? ' ' + className : ''}`;
|
|
2022
|
+
return (_jsxs("div", { className: editorClass, style: {
|
|
2023
|
+
border: "1px solid var(--srte-border)",
|
|
1500
2024
|
borderRadius: 6,
|
|
1501
2025
|
width: "100%",
|
|
1502
2026
|
maxWidth: "100vw",
|
|
1503
2027
|
overflow: "hidden",
|
|
1504
2028
|
display: "flex",
|
|
1505
2029
|
flexDirection: "column",
|
|
1506
|
-
background: "
|
|
2030
|
+
background: "var(--srte-bg)",
|
|
2031
|
+
color: "var(--srte-text)",
|
|
1507
2032
|
boxSizing: "border-box"
|
|
1508
2033
|
}, children: [_jsxs("div", { style: {
|
|
1509
2034
|
display: "flex",
|
|
@@ -1511,7 +2036,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1511
2036
|
maxWidth: "100%",
|
|
1512
2037
|
gap: 8,
|
|
1513
2038
|
padding: 8,
|
|
1514
|
-
borderBottom: "1px solid
|
|
2039
|
+
borderBottom: "1px solid var(--srte-border-light)",
|
|
2040
|
+
background: "var(--srte-toolbar-bg)",
|
|
1515
2041
|
position: "sticky",
|
|
1516
2042
|
top: 0,
|
|
1517
2043
|
zIndex: 1,
|
|
@@ -1547,6 +2073,12 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1547
2073
|
} }), _jsx("input", { ref: docxInputRef, type: "file", accept: ".docx", style: { display: "none" }, onChange: (e) => {
|
|
1548
2074
|
handleDocxFiles(e.currentTarget.files);
|
|
1549
2075
|
e.currentTarget.value = "";
|
|
2076
|
+
} }), _jsx("input", { ref: htmlInputRef, type: "file", accept: ".html,.htm,text/html", style: { display: "none" }, onChange: (e) => {
|
|
2077
|
+
importTextFile(e.currentTarget.files, "html");
|
|
2078
|
+
e.currentTarget.value = "";
|
|
2079
|
+
} }), _jsx("input", { ref: mdInputRef, type: "file", accept: ".md,.markdown,text/markdown,text/plain", style: { display: "none" }, onChange: (e) => {
|
|
2080
|
+
importTextFile(e.currentTarget.files, "md");
|
|
2081
|
+
e.currentTarget.value = "";
|
|
1550
2082
|
} }), _jsxs("select", { defaultValue: "p", onChange: (e) => {
|
|
1551
2083
|
const val = e.target.value;
|
|
1552
2084
|
if (val === "p")
|
|
@@ -1560,45 +2092,45 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1560
2092
|
}, title: "Paragraph/Heading", style: {
|
|
1561
2093
|
height: 32,
|
|
1562
2094
|
padding: "0 8px",
|
|
1563
|
-
border: "1px solid
|
|
2095
|
+
border: "1px solid var(--srte-input-border)",
|
|
1564
2096
|
borderRadius: 6,
|
|
1565
|
-
background: "
|
|
1566
|
-
color: "
|
|
2097
|
+
background: "var(--srte-input-bg)",
|
|
2098
|
+
color: "var(--srte-input-text)",
|
|
1567
2099
|
}, 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: {
|
|
1568
2100
|
height: 32,
|
|
1569
2101
|
minWidth: 32,
|
|
1570
2102
|
padding: "0 8px",
|
|
1571
|
-
border: "1px solid
|
|
2103
|
+
border: "1px solid var(--srte-input-border)",
|
|
1572
2104
|
borderRadius: 6,
|
|
1573
|
-
background: "
|
|
1574
|
-
color: "
|
|
2105
|
+
background: "var(--srte-input-bg)",
|
|
2106
|
+
color: "var(--srte-input-text)",
|
|
1575
2107
|
}, children: _jsx("span", { style: { fontWeight: 700 }, children: "B" }) }), _jsx("button", { title: "Italic", onClick: () => exec("italic"), style: {
|
|
1576
2108
|
height: 32,
|
|
1577
2109
|
minWidth: 32,
|
|
1578
2110
|
padding: "0 8px",
|
|
1579
|
-
border: "1px solid
|
|
2111
|
+
border: "1px solid var(--srte-input-border)",
|
|
1580
2112
|
borderRadius: 6,
|
|
1581
|
-
background: "
|
|
2113
|
+
background: "var(--srte-input-bg)",
|
|
1582
2114
|
fontStyle: "italic",
|
|
1583
|
-
color: "
|
|
2115
|
+
color: "var(--srte-input-text)",
|
|
1584
2116
|
}, children: "I" }), _jsx("button", { title: "Underline", onClick: () => exec("underline"), style: {
|
|
1585
2117
|
height: 32,
|
|
1586
2118
|
minWidth: 32,
|
|
1587
2119
|
padding: "0 8px",
|
|
1588
|
-
border: "1px solid
|
|
2120
|
+
border: "1px solid var(--srte-input-border)",
|
|
1589
2121
|
borderRadius: 6,
|
|
1590
|
-
background: "
|
|
2122
|
+
background: "var(--srte-input-bg)",
|
|
1591
2123
|
textDecoration: "underline",
|
|
1592
|
-
color: "
|
|
2124
|
+
color: "var(--srte-input-text)",
|
|
1593
2125
|
}, children: "U" }), _jsx("button", { title: "Strikethrough", onClick: () => exec("strikeThrough"), style: {
|
|
1594
2126
|
height: 32,
|
|
1595
2127
|
minWidth: 32,
|
|
1596
2128
|
padding: "0 8px",
|
|
1597
|
-
border: "1px solid
|
|
2129
|
+
border: "1px solid var(--srte-input-border)",
|
|
1598
2130
|
borderRadius: 6,
|
|
1599
|
-
background: "
|
|
2131
|
+
background: "var(--srte-input-bg)",
|
|
1600
2132
|
textDecoration: "line-through",
|
|
1601
|
-
color: "
|
|
2133
|
+
color: "var(--srte-input-text)",
|
|
1602
2134
|
}, children: "S" }), _jsxs("select", { value: currentFontSize, onMouseDown: () => {
|
|
1603
2135
|
// Save selection before dropdown interaction
|
|
1604
2136
|
const sel = window.getSelection();
|
|
@@ -1612,11 +2144,11 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1612
2144
|
}, onChange: (e) => applyFontSize(e.target.value), title: "Font Size", style: {
|
|
1613
2145
|
height: 32,
|
|
1614
2146
|
padding: "0 8px",
|
|
1615
|
-
border: "1px solid
|
|
2147
|
+
border: "1px solid var(--srte-input-border)",
|
|
1616
2148
|
borderRadius: 6,
|
|
1617
|
-
background: "
|
|
1618
|
-
color: "
|
|
1619
|
-
}, children: [_jsx("option", { value: "", disabled: true, children: "Size" }), _jsx("option", { value: "8", children: "8" }), _jsx("option", { value: "9", children: "9" }), _jsx("option", { value: "10", children: "10" }), _jsx("option", { value: "11", children: "11" }), _jsx("option", { value: "12", children: "12" }), _jsx("option", { value: "14", children: "14" }), _jsx("option", { value: "18", children: "18" }), _jsx("option", { value: "24", children: "24" }), _jsx("option", { value: "30", children: "30" }), _jsx("option", { value: "36", children: "36" }), _jsx("option", { value: "48", children: "48" }), _jsx("option", { value: "60", children: "60" }), _jsx("option", { value: "72", children: "72" }), _jsx("option", { value: "96", children: "96" })] }), _jsxs("select", { value: currentFont, onMouseDown: () => {
|
|
2149
|
+
background: "var(--srte-input-bg)",
|
|
2150
|
+
color: "var(--srte-input-text)",
|
|
2151
|
+
}, children: [_jsx("option", { value: "", disabled: true, children: "Size" }), _jsx("option", { value: "8", children: "8" }), _jsx("option", { value: "9", children: "9" }), _jsx("option", { value: "10", children: "10" }), _jsx("option", { value: "11", children: "11" }), _jsx("option", { value: "12", children: "12" }), _jsx("option", { value: "14", children: "14" }), _jsx("option", { value: "18", children: "18" }), _jsx("option", { value: "24", children: "24" }), _jsx("option", { value: "30", children: "30" }), _jsx("option", { value: "36", children: "36" }), _jsx("option", { value: "48", children: "48" }), _jsx("option", { value: "60", children: "60" }), _jsx("option", { value: "72", children: "72" }), _jsx("option", { value: "96", children: "96" })] }), preserveFontFamily && (_jsxs("select", { value: currentFont, onMouseDown: () => {
|
|
1620
2152
|
const sel = window.getSelection();
|
|
1621
2153
|
if (sel && sel.rangeCount > 0) {
|
|
1622
2154
|
const range = sel.getRangeAt(0);
|
|
@@ -1628,118 +2160,170 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1628
2160
|
}, onChange: (e) => applyFontFamily(e.target.value), title: "Font Family", style: {
|
|
1629
2161
|
height: 32,
|
|
1630
2162
|
padding: "0 8px",
|
|
1631
|
-
border: "1px solid
|
|
2163
|
+
border: "1px solid var(--srte-input-border)",
|
|
1632
2164
|
borderRadius: 6,
|
|
1633
|
-
background: "
|
|
1634
|
-
color: "
|
|
2165
|
+
background: "var(--srte-input-bg)",
|
|
2166
|
+
color: "var(--srte-input-text)",
|
|
1635
2167
|
maxWidth: 100,
|
|
1636
|
-
}, children: [_jsx("option", { value: "", disabled: true, children: "Font" }), fonts.map((f) => (_jsx("option", { value: f.value, children: f.name }, f.value)))] }), _jsx("button", { title: "Text Color", onClick: () => {
|
|
2168
|
+
}, children: [_jsx("option", { value: "", disabled: true, children: "Font" }), fonts.map((f) => (_jsx("option", { value: f.value, children: f.name }, f.value)))] })), _jsx("button", { title: "Text Color", onClick: () => {
|
|
1637
2169
|
setColorPickerType('text');
|
|
1638
2170
|
setShowColorPicker(true);
|
|
1639
2171
|
}, style: {
|
|
1640
2172
|
height: 32,
|
|
1641
2173
|
minWidth: 32,
|
|
1642
2174
|
padding: "0 8px",
|
|
1643
|
-
border: "1px solid
|
|
2175
|
+
border: "1px solid var(--srte-input-border)",
|
|
1644
2176
|
borderRadius: 6,
|
|
1645
|
-
background: "
|
|
1646
|
-
color: "
|
|
2177
|
+
background: "var(--srte-input-bg)",
|
|
2178
|
+
color: "var(--srte-input-text)",
|
|
1647
2179
|
position: "relative",
|
|
1648
|
-
}, children: _jsx("span", { style: { fontWeight: 700 }, children: "A" }) }), _jsx("button", { title: "Background Color", onClick: () => {
|
|
2180
|
+
}, children: _jsx("span", { style: { fontWeight: 700, borderBottom: "3px solid currentColor", lineHeight: 1 }, children: "A" }) }), _jsx("button", { title: "Background Color", onClick: () => {
|
|
1649
2181
|
setColorPickerType('background');
|
|
1650
2182
|
setShowColorPicker(true);
|
|
1651
2183
|
}, style: {
|
|
1652
2184
|
height: 32,
|
|
1653
2185
|
minWidth: 32,
|
|
1654
2186
|
padding: "0 8px",
|
|
1655
|
-
border: "1px solid
|
|
2187
|
+
border: "1px solid var(--srte-input-border)",
|
|
2188
|
+
borderRadius: 6,
|
|
2189
|
+
background: "var(--srte-input-bg)",
|
|
2190
|
+
color: "var(--srte-input-text)",
|
|
2191
|
+
}, children: _jsx("span", { style: { fontWeight: 700, padding: "1px 4px", background: "var(--srte-accent-bg)", borderRadius: 3 }, children: "A" }) }), _jsxs("button", { title: "Subscript", onClick: () => exec("subscript"), style: {
|
|
2192
|
+
height: 32,
|
|
2193
|
+
minWidth: 32,
|
|
2194
|
+
padding: "0 8px",
|
|
2195
|
+
border: "1px solid var(--srte-input-border)",
|
|
1656
2196
|
borderRadius: 6,
|
|
1657
|
-
background: "
|
|
1658
|
-
color: "
|
|
1659
|
-
}, children: _jsx("
|
|
2197
|
+
background: "var(--srte-input-bg)",
|
|
2198
|
+
color: "var(--srte-input-text)",
|
|
2199
|
+
}, children: ["X", _jsx("sub", { children: "2" })] }), _jsxs("button", { title: "Superscript", onClick: () => exec("superscript"), style: {
|
|
2200
|
+
height: 32,
|
|
2201
|
+
minWidth: 32,
|
|
2202
|
+
padding: "0 8px",
|
|
2203
|
+
border: "1px solid var(--srte-input-border)",
|
|
2204
|
+
borderRadius: 6,
|
|
2205
|
+
background: "var(--srte-input-bg)",
|
|
2206
|
+
color: "var(--srte-input-text)",
|
|
2207
|
+
}, children: ["X", _jsx("sup", { children: "2" })] }), _jsx("button", { title: "Bulleted list", onClick: () => exec("insertUnorderedList"), style: {
|
|
1660
2208
|
height: 32,
|
|
1661
2209
|
padding: "0 10px",
|
|
1662
|
-
border: "1px solid
|
|
2210
|
+
border: "1px solid var(--srte-input-border)",
|
|
1663
2211
|
borderRadius: 6,
|
|
1664
|
-
background: "
|
|
1665
|
-
color: "
|
|
2212
|
+
background: "var(--srte-input-bg)",
|
|
2213
|
+
color: "var(--srte-input-text)",
|
|
1666
2214
|
}, children: "\u2022 List" }), _jsx("button", { title: "Numbered list", onClick: () => exec("insertOrderedList"), style: {
|
|
1667
2215
|
height: 32,
|
|
1668
2216
|
padding: "0 10px",
|
|
1669
|
-
border: "1px solid
|
|
2217
|
+
border: "1px solid var(--srte-input-border)",
|
|
1670
2218
|
borderRadius: 6,
|
|
1671
|
-
background: "
|
|
1672
|
-
color: "
|
|
1673
|
-
}, children: "1. List" }), _jsx("button", { title: "Blockquote", onClick:
|
|
2219
|
+
background: "var(--srte-input-bg)",
|
|
2220
|
+
color: "var(--srte-input-text)",
|
|
2221
|
+
}, children: "1. List" }), _jsx("button", { title: "Blockquote", onClick: toggleBlockquote, style: {
|
|
1674
2222
|
height: 32,
|
|
1675
2223
|
minWidth: 32,
|
|
1676
2224
|
padding: "0 8px",
|
|
1677
|
-
border: "1px solid
|
|
2225
|
+
border: "1px solid var(--srte-input-border)",
|
|
1678
2226
|
borderRadius: 6,
|
|
1679
|
-
background: "
|
|
1680
|
-
color: "
|
|
1681
|
-
}, children: "\u275D" }), _jsx("button", { title: "
|
|
2227
|
+
background: "var(--srte-input-bg)",
|
|
2228
|
+
color: "var(--srte-input-text)",
|
|
2229
|
+
}, children: "\u275D" }), _jsx("button", { title: "Special characters", onClick: () => setShowSpecialChars(true), style: {
|
|
2230
|
+
height: 32,
|
|
2231
|
+
minWidth: 32,
|
|
2232
|
+
padding: "0 8px",
|
|
2233
|
+
border: "1px solid var(--srte-input-border)",
|
|
2234
|
+
borderRadius: 6,
|
|
2235
|
+
background: "var(--srte-input-bg)",
|
|
2236
|
+
color: "var(--srte-input-text)",
|
|
2237
|
+
}, children: "\u03A9" }), _jsx("button", { title: "Code block", onClick: () => exec("formatBlock", "<pre>"), style: {
|
|
1682
2238
|
height: 32,
|
|
1683
2239
|
minWidth: 36,
|
|
1684
2240
|
padding: "0 8px",
|
|
1685
|
-
border: "1px solid
|
|
2241
|
+
border: "1px solid var(--srte-input-border)",
|
|
1686
2242
|
borderRadius: 6,
|
|
1687
|
-
background: "
|
|
2243
|
+
background: "var(--srte-input-bg)",
|
|
1688
2244
|
fontFamily: "ui-monospace, SFMono-Regular, Menlo",
|
|
1689
|
-
color: "
|
|
2245
|
+
color: "var(--srte-input-text)",
|
|
1690
2246
|
}, children: "< />" }), formula && (_jsx("button", { title: "Insert formula", onClick: () => setShowFormulaDialog(true), style: {
|
|
1691
2247
|
height: 32,
|
|
1692
2248
|
minWidth: 32,
|
|
1693
2249
|
padding: "0 8px",
|
|
1694
|
-
border: "1px solid
|
|
2250
|
+
border: "1px solid var(--srte-input-border)",
|
|
1695
2251
|
borderRadius: 6,
|
|
1696
|
-
background: "
|
|
1697
|
-
color: "
|
|
2252
|
+
background: "var(--srte-input-bg)",
|
|
2253
|
+
color: "var(--srte-input-text)",
|
|
1698
2254
|
}, children: "\u2211" })), _jsx("button", { title: "Insert link", onClick: insertLink, style: {
|
|
1699
2255
|
height: 32,
|
|
1700
2256
|
padding: "0 10px",
|
|
1701
|
-
border: "1px solid
|
|
2257
|
+
border: "1px solid var(--srte-input-border)",
|
|
1702
2258
|
borderRadius: 6,
|
|
1703
|
-
background: "
|
|
1704
|
-
color: "
|
|
2259
|
+
background: "var(--srte-input-bg)",
|
|
2260
|
+
color: "var(--srte-input-text)",
|
|
1705
2261
|
}, children: "Link" }), _jsx("button", { title: "Remove link", onClick: () => exec("unlink"), style: {
|
|
1706
2262
|
height: 32,
|
|
1707
2263
|
padding: "0 10px",
|
|
1708
|
-
border: "1px solid
|
|
2264
|
+
border: "1px solid var(--srte-input-border)",
|
|
1709
2265
|
borderRadius: 6,
|
|
1710
|
-
background: "
|
|
1711
|
-
color: "
|
|
2266
|
+
background: "var(--srte-input-bg)",
|
|
2267
|
+
color: "var(--srte-input-text)",
|
|
1712
2268
|
}, children: "Unlink" }), media && (_jsxs(_Fragment, { children: [_jsx("button", { title: "Insert image", onClick: insertImage, style: {
|
|
1713
2269
|
height: 32,
|
|
1714
2270
|
padding: "0 10px",
|
|
1715
|
-
border: "1px solid
|
|
2271
|
+
border: "1px solid var(--srte-input-border)",
|
|
1716
2272
|
borderRadius: 6,
|
|
1717
|
-
background: "
|
|
1718
|
-
color: "
|
|
2273
|
+
background: "var(--srte-input-bg)",
|
|
2274
|
+
color: "var(--srte-input-text)",
|
|
1719
2275
|
}, children: "\uD83D\uDDBC\uFE0F Image" }), mediaManager && (_jsx("button", { title: "Open media manager", onClick: () => setShowMediaManager(true), style: {
|
|
1720
2276
|
height: 32,
|
|
1721
2277
|
padding: "0 10px",
|
|
1722
|
-
border: "1px solid
|
|
2278
|
+
border: "1px solid var(--srte-input-border)",
|
|
1723
2279
|
borderRadius: 6,
|
|
1724
|
-
background: "
|
|
1725
|
-
color: "
|
|
2280
|
+
background: "var(--srte-input-bg)",
|
|
2281
|
+
color: "var(--srte-input-text)",
|
|
1726
2282
|
}, children: "\uD83D\uDCC1 Media" })), _jsx("button", { title: "Import PDF", onClick: () => pdfInputRef.current?.click(), disabled: loadingPdf, style: {
|
|
1727
2283
|
height: 32,
|
|
1728
2284
|
padding: "0 10px",
|
|
1729
|
-
border: "1px solid
|
|
2285
|
+
border: "1px solid var(--srte-input-border)",
|
|
1730
2286
|
borderRadius: 6,
|
|
1731
|
-
background: "
|
|
1732
|
-
color: "
|
|
2287
|
+
background: "var(--srte-input-bg)",
|
|
2288
|
+
color: "var(--srte-input-text)",
|
|
1733
2289
|
opacity: loadingPdf ? 0.5 : 1,
|
|
1734
2290
|
}, children: loadingPdf ? '⌛ Importing...' : '📄 PDF' }), _jsx("button", { title: "Import DOCX", onClick: () => docxInputRef.current?.click(), disabled: loadingDocx, style: {
|
|
1735
2291
|
height: 32,
|
|
1736
2292
|
padding: "0 10px",
|
|
1737
|
-
border: "1px solid
|
|
2293
|
+
border: "1px solid var(--srte-input-border)",
|
|
1738
2294
|
borderRadius: 6,
|
|
1739
|
-
background: "
|
|
1740
|
-
color: "
|
|
2295
|
+
background: "var(--srte-input-bg)",
|
|
2296
|
+
color: "var(--srte-input-text)",
|
|
1741
2297
|
opacity: loadingDocx ? 0.5 : 1,
|
|
1742
|
-
}, children: loadingDocx ? '⌛ Importing...' : '📝 DOCX' }),
|
|
2298
|
+
}, children: loadingDocx ? '⌛ Importing...' : '📝 DOCX' }), _jsx("button", { title: "Import HTML", onClick: () => htmlInputRef.current?.click(), style: {
|
|
2299
|
+
height: 32,
|
|
2300
|
+
padding: "0 10px",
|
|
2301
|
+
border: "1px solid var(--srte-input-border)",
|
|
2302
|
+
borderRadius: 6,
|
|
2303
|
+
background: "var(--srte-input-bg)",
|
|
2304
|
+
color: "var(--srte-input-text)",
|
|
2305
|
+
}, children: "HTML" }), _jsx("button", { title: "Import Markdown", onClick: () => mdInputRef.current?.click(), style: {
|
|
2306
|
+
height: 32,
|
|
2307
|
+
padding: "0 10px",
|
|
2308
|
+
border: "1px solid var(--srte-input-border)",
|
|
2309
|
+
borderRadius: 6,
|
|
2310
|
+
background: "var(--srte-input-bg)",
|
|
2311
|
+
color: "var(--srte-input-text)",
|
|
2312
|
+
}, children: "MD" }), _jsx("button", { title: "Export HTML", onClick: exportHtml, style: {
|
|
2313
|
+
height: 32,
|
|
2314
|
+
padding: "0 10px",
|
|
2315
|
+
border: "1px solid var(--srte-input-border)",
|
|
2316
|
+
borderRadius: 6,
|
|
2317
|
+
background: "var(--srte-input-bg)",
|
|
2318
|
+
color: "var(--srte-input-text)",
|
|
2319
|
+
}, children: "Export HTML" }), _jsx("button", { title: "Export Markdown", onClick: exportMarkdown, style: {
|
|
2320
|
+
height: 32,
|
|
2321
|
+
padding: "0 10px",
|
|
2322
|
+
border: "1px solid var(--srte-input-border)",
|
|
2323
|
+
borderRadius: 6,
|
|
2324
|
+
background: "var(--srte-input-bg)",
|
|
2325
|
+
color: "var(--srte-input-text)",
|
|
2326
|
+
}, children: "Export MD" }), _jsxs("div", { style: {
|
|
1743
2327
|
display: "inline-flex",
|
|
1744
2328
|
gap: 4,
|
|
1745
2329
|
alignItems: "center",
|
|
@@ -1757,10 +2341,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1757
2341
|
height: 28,
|
|
1758
2342
|
minWidth: 28,
|
|
1759
2343
|
padding: "0 6px",
|
|
1760
|
-
border: "1px solid
|
|
2344
|
+
border: "1px solid var(--srte-input-border)",
|
|
1761
2345
|
borderRadius: 6,
|
|
1762
|
-
background: "
|
|
1763
|
-
color: "
|
|
2346
|
+
background: "var(--srte-input-bg)",
|
|
2347
|
+
color: "var(--srte-input-text)",
|
|
1764
2348
|
}, children: "\u2299" }), _jsx("button", { onClick: () => {
|
|
1765
2349
|
const img = selectedImage;
|
|
1766
2350
|
if (!img)
|
|
@@ -1774,10 +2358,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1774
2358
|
height: 28,
|
|
1775
2359
|
minWidth: 28,
|
|
1776
2360
|
padding: "0 6px",
|
|
1777
|
-
border: "1px solid
|
|
2361
|
+
border: "1px solid var(--srte-input-border)",
|
|
1778
2362
|
borderRadius: 6,
|
|
1779
|
-
background: "
|
|
1780
|
-
color: "
|
|
2363
|
+
background: "var(--srte-input-bg)",
|
|
2364
|
+
color: "var(--srte-input-text)",
|
|
1781
2365
|
}, children: "\u27F8" }), _jsx("button", { onClick: () => {
|
|
1782
2366
|
const img = selectedImage;
|
|
1783
2367
|
if (!img)
|
|
@@ -1791,44 +2375,45 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1791
2375
|
height: 28,
|
|
1792
2376
|
minWidth: 28,
|
|
1793
2377
|
padding: "0 6px",
|
|
1794
|
-
border: "1px solid
|
|
2378
|
+
border: "1px solid var(--srte-input-border)",
|
|
1795
2379
|
borderRadius: 6,
|
|
1796
|
-
background: "
|
|
1797
|
-
color: "
|
|
2380
|
+
background: "var(--srte-input-bg)",
|
|
2381
|
+
color: "var(--srte-input-text)",
|
|
1798
2382
|
}, children: "\u27F9" })] })] })), table && (_jsx("button", { title: "Insert table", onClick: () => setShowTableDialog(true), style: {
|
|
1799
2383
|
height: 32,
|
|
1800
2384
|
padding: "0 10px",
|
|
1801
|
-
border: "1px solid
|
|
2385
|
+
border: "1px solid var(--srte-input-border)",
|
|
1802
2386
|
borderRadius: 6,
|
|
1803
|
-
background: "
|
|
1804
|
-
color: "
|
|
2387
|
+
background: "var(--srte-input-bg)",
|
|
2388
|
+
color: "var(--srte-input-text)",
|
|
1805
2389
|
}, children: "\u2795 Table" })), _jsx("button", { title: "Undo", onClick: () => exec("undo"), style: {
|
|
1806
2390
|
height: 32,
|
|
1807
2391
|
padding: "0 10px",
|
|
1808
|
-
border: "1px solid
|
|
2392
|
+
border: "1px solid var(--srte-input-border)",
|
|
1809
2393
|
borderRadius: 6,
|
|
1810
|
-
background: "
|
|
1811
|
-
color: "
|
|
2394
|
+
background: "var(--srte-input-bg)",
|
|
2395
|
+
color: "var(--srte-input-text)",
|
|
1812
2396
|
}, children: "\u238C Undo" }), _jsx("button", { title: "Redo", onClick: () => exec("redo"), style: {
|
|
1813
2397
|
height: 32,
|
|
1814
2398
|
padding: "0 10px",
|
|
1815
|
-
border: "1px solid
|
|
2399
|
+
border: "1px solid var(--srte-input-border)",
|
|
1816
2400
|
borderRadius: 6,
|
|
1817
|
-
background: "
|
|
1818
|
-
color: "
|
|
2401
|
+
background: "var(--srte-input-bg)",
|
|
2402
|
+
color: "var(--srte-input-text)",
|
|
1819
2403
|
}, children: "\u293E Redo" })] }), media && mediaManager && (_jsx(MediaManager, { open: showMediaManager, onClose: () => setShowMediaManager(false), adapter: mediaManager, onSelect: (item) => {
|
|
1820
2404
|
if (item?.url)
|
|
1821
|
-
insertImageAtSelection(item
|
|
2405
|
+
insertImageAtSelection(item);
|
|
1822
2406
|
} })), table && showTableDialog && (_jsx("div", { style: {
|
|
1823
2407
|
position: "fixed",
|
|
1824
2408
|
inset: 0,
|
|
1825
|
-
background: "
|
|
2409
|
+
background: "var(--srte-modal-backdrop)",
|
|
1826
2410
|
display: "flex",
|
|
1827
2411
|
alignItems: "center",
|
|
1828
2412
|
justifyContent: "center",
|
|
1829
2413
|
zIndex: 50,
|
|
1830
2414
|
}, onClick: () => setShowTableDialog(false), children: _jsxs("div", { style: {
|
|
1831
|
-
background: "
|
|
2415
|
+
background: "var(--srte-modal-bg)",
|
|
2416
|
+
color: "var(--srte-modal-text)",
|
|
1832
2417
|
padding: 16,
|
|
1833
2418
|
borderRadius: 8,
|
|
1834
2419
|
minWidth: 280,
|
|
@@ -1837,7 +2422,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1837
2422
|
gridTemplateColumns: "repeat(10, 18px)",
|
|
1838
2423
|
gap: 2,
|
|
1839
2424
|
padding: 6,
|
|
1840
|
-
border: "1px solid
|
|
2425
|
+
border: "1px solid var(--srte-border-light)",
|
|
1841
2426
|
}, children: Array.from({ length: 100 }).map((_, i) => {
|
|
1842
2427
|
const r = Math.floor(i / 10) + 1;
|
|
1843
2428
|
const c = (i % 10) + 1;
|
|
@@ -1851,8 +2436,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1851
2436
|
}, style: {
|
|
1852
2437
|
width: 16,
|
|
1853
2438
|
height: 16,
|
|
1854
|
-
border: "1px solid
|
|
1855
|
-
background: active ? "
|
|
2439
|
+
border: "1px solid var(--srte-border)",
|
|
2440
|
+
background: active ? "var(--srte-accent)" : "var(--srte-input-bg)",
|
|
1856
2441
|
} }, i));
|
|
1857
2442
|
}) }), _jsxs("div", { style: { fontSize: 12, minWidth: 48 }, children: [tableRows, " \u00D7 ", tableCols] })] }), _jsxs("div", { style: {
|
|
1858
2443
|
display: "flex",
|
|
@@ -1865,7 +2450,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1865
2450
|
}, children: "Insert" })] })] }) })), pendingImport && (_jsx("div", { style: {
|
|
1866
2451
|
position: "fixed",
|
|
1867
2452
|
inset: 0,
|
|
1868
|
-
background: "
|
|
2453
|
+
background: "var(--srte-modal-backdrop)",
|
|
1869
2454
|
display: "flex",
|
|
1870
2455
|
alignItems: "center",
|
|
1871
2456
|
justifyContent: "center",
|
|
@@ -1877,16 +2462,17 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1877
2462
|
if (docxInputRef.current)
|
|
1878
2463
|
docxInputRef.current.value = "";
|
|
1879
2464
|
}, children: _jsxs("div", { style: {
|
|
1880
|
-
background: "
|
|
2465
|
+
background: "var(--srte-modal-bg)",
|
|
2466
|
+
color: "var(--srte-modal-text)",
|
|
1881
2467
|
padding: 20,
|
|
1882
2468
|
borderRadius: 8,
|
|
1883
2469
|
maxWidth: 400,
|
|
1884
2470
|
width: "90%",
|
|
1885
|
-
boxShadow: "
|
|
1886
|
-
}, onClick: (e) => e.stopPropagation(), children: [_jsx("h3", { style: { margin: "0 0 12px 0", fontSize: 18, fontWeight: 600 }, children: "Import Content" }), _jsx("p", { style: { margin: "0 0 20px 0", color: "
|
|
2471
|
+
boxShadow: "var(--srte-menu-shadow)",
|
|
2472
|
+
}, onClick: (e) => e.stopPropagation(), children: [_jsx("h3", { style: { margin: "0 0 12px 0", fontSize: 18, fontWeight: 600 }, children: "Import Content" }), _jsx("p", { style: { margin: "0 0 20px 0", color: "var(--srte-text-muted)", fontSize: 14 }, children: "The editor already contains content. How would you like to handle the imported document?" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [_jsx("button", { onClick: () => processImport(pendingImport.file, pendingImport.type, 'replace'), style: {
|
|
1887
2473
|
padding: "8px 16px",
|
|
1888
|
-
background: "
|
|
1889
|
-
color: "
|
|
2474
|
+
background: "var(--srte-danger)",
|
|
2475
|
+
color: "var(--srte-on-primary)",
|
|
1890
2476
|
border: "none",
|
|
1891
2477
|
borderRadius: 6,
|
|
1892
2478
|
cursor: "pointer",
|
|
@@ -1894,8 +2480,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1894
2480
|
textAlign: "left"
|
|
1895
2481
|
}, children: "Replace Check existing content (Overwrite)" }), _jsx("button", { onClick: () => processImport(pendingImport.file, pendingImport.type, 'append'), style: {
|
|
1896
2482
|
padding: "8px 16px",
|
|
1897
|
-
background: "
|
|
1898
|
-
color: "
|
|
2483
|
+
background: "var(--srte-primary)",
|
|
2484
|
+
color: "var(--srte-on-primary)",
|
|
1899
2485
|
border: "none",
|
|
1900
2486
|
borderRadius: 6,
|
|
1901
2487
|
cursor: "pointer",
|
|
@@ -1909,27 +2495,27 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1909
2495
|
docxInputRef.current.value = "";
|
|
1910
2496
|
}, style: {
|
|
1911
2497
|
padding: "8px 16px",
|
|
1912
|
-
background: "
|
|
1913
|
-
color: "
|
|
1914
|
-
border: "1px solid
|
|
2498
|
+
background: "var(--srte-cancel-bg)",
|
|
2499
|
+
color: "var(--srte-text)",
|
|
2500
|
+
border: "1px solid var(--srte-border)",
|
|
1915
2501
|
borderRadius: 6,
|
|
1916
2502
|
cursor: "pointer",
|
|
1917
2503
|
marginTop: 4
|
|
1918
2504
|
}, children: "Cancel" })] })] }) })), showColorPicker && (_jsx("div", { style: {
|
|
1919
2505
|
position: "fixed",
|
|
1920
2506
|
inset: 0,
|
|
1921
|
-
background: "
|
|
2507
|
+
background: "var(--srte-modal-backdrop)",
|
|
1922
2508
|
display: "flex",
|
|
1923
2509
|
alignItems: "center",
|
|
1924
2510
|
justifyContent: "center",
|
|
1925
2511
|
zIndex: 50,
|
|
1926
2512
|
}, onClick: () => setShowColorPicker(false), children: _jsxs("div", { style: {
|
|
1927
|
-
background: "
|
|
2513
|
+
background: "var(--srte-modal-bg)",
|
|
1928
2514
|
padding: 16,
|
|
1929
2515
|
borderRadius: 8,
|
|
1930
2516
|
minWidth: 320,
|
|
1931
2517
|
maxWidth: "90vw",
|
|
1932
|
-
color: "
|
|
2518
|
+
color: "var(--srte-modal-text)",
|
|
1933
2519
|
}, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 12 }, children: colorPickerType === 'text' ? 'Select Text Color' : 'Select Background Color' }), _jsx("div", { style: {
|
|
1934
2520
|
display: "grid",
|
|
1935
2521
|
gridTemplateColumns: "repeat(8, 1fr)",
|
|
@@ -1957,7 +2543,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1957
2543
|
}, style: {
|
|
1958
2544
|
width: 32,
|
|
1959
2545
|
height: 32,
|
|
1960
|
-
border: color === '#ffffff' ? '1px solid
|
|
2546
|
+
border: color === '#ffffff' ? '1px solid var(--srte-border)' : 'none',
|
|
1961
2547
|
borderRadius: 4,
|
|
1962
2548
|
background: color,
|
|
1963
2549
|
cursor: 'pointer',
|
|
@@ -1971,31 +2557,75 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
1971
2557
|
}, style: {
|
|
1972
2558
|
width: '100%',
|
|
1973
2559
|
height: 40,
|
|
1974
|
-
border: '1px solid
|
|
2560
|
+
border: '1px solid var(--srte-border)',
|
|
1975
2561
|
borderRadius: 6,
|
|
1976
2562
|
cursor: 'pointer',
|
|
1977
2563
|
} })] }), _jsx("div", { style: { display: 'flex', justifyContent: 'end' }, children: _jsx("button", { onClick: () => setShowColorPicker(false), style: {
|
|
1978
2564
|
padding: '6px 16px',
|
|
1979
|
-
border: '1px solid
|
|
2565
|
+
border: '1px solid var(--srte-input-border)',
|
|
1980
2566
|
borderRadius: 6,
|
|
1981
|
-
background: '
|
|
1982
|
-
color: '
|
|
2567
|
+
background: 'var(--srte-input-bg)',
|
|
2568
|
+
color: 'var(--srte-input-text)',
|
|
1983
2569
|
cursor: 'pointer',
|
|
2570
|
+
}, children: "Close" }) })] }) })), showSpecialChars && (_jsx("div", { style: {
|
|
2571
|
+
position: "fixed",
|
|
2572
|
+
inset: 0,
|
|
2573
|
+
background: "var(--srte-modal-backdrop)",
|
|
2574
|
+
display: "flex",
|
|
2575
|
+
alignItems: "center",
|
|
2576
|
+
justifyContent: "center",
|
|
2577
|
+
zIndex: 50,
|
|
2578
|
+
}, onClick: () => setShowSpecialChars(false), children: _jsxs("div", { style: {
|
|
2579
|
+
background: "var(--srte-modal-bg)",
|
|
2580
|
+
color: "var(--srte-modal-text)",
|
|
2581
|
+
padding: 16,
|
|
2582
|
+
borderRadius: 8,
|
|
2583
|
+
width: 420,
|
|
2584
|
+
maxWidth: "90vw",
|
|
2585
|
+
boxShadow: "var(--srte-menu-shadow)",
|
|
2586
|
+
}, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 12 }, children: "Special characters" }), [
|
|
2587
|
+
{
|
|
2588
|
+
label: "Greek",
|
|
2589
|
+
chars: ["α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "π", "ρ", "σ", "τ", "φ", "χ", "ψ", "ω", "Δ", "Σ", "Ω"],
|
|
2590
|
+
},
|
|
2591
|
+
{
|
|
2592
|
+
label: "Medical / Math",
|
|
2593
|
+
chars: ["±", "≤", "≥", "≠", "≈", "∞", "°", "µ", "×", "÷", "→", "←", "↑", "↓", "∴", "∵", "√", "∑", "∫", "₂", "₃", "²", "³"],
|
|
2594
|
+
},
|
|
2595
|
+
].map((group) => (_jsxs("div", { style: { marginBottom: 12 }, children: [_jsx("div", { style: { fontSize: 12, color: "var(--srte-text-muted)", marginBottom: 6 }, children: group.label }), _jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: group.chars.map((char) => (_jsx("button", { type: "button", onClick: () => {
|
|
2596
|
+
insertTextAtSelection(char);
|
|
2597
|
+
setShowSpecialChars(false);
|
|
2598
|
+
}, style: {
|
|
2599
|
+
height: 32,
|
|
2600
|
+
minWidth: 32,
|
|
2601
|
+
padding: "0 8px",
|
|
2602
|
+
border: "1px solid var(--srte-input-border)",
|
|
2603
|
+
borderRadius: 6,
|
|
2604
|
+
background: "var(--srte-input-bg)",
|
|
2605
|
+
color: "var(--srte-input-text)",
|
|
2606
|
+
fontSize: 16,
|
|
2607
|
+
}, children: char }, char))) })] }, group.label))), _jsx("div", { style: { display: "flex", justifyContent: "flex-end" }, children: _jsx("button", { type: "button", onClick: () => setShowSpecialChars(false), style: {
|
|
2608
|
+
padding: "6px 16px",
|
|
2609
|
+
border: "1px solid var(--srte-input-border)",
|
|
2610
|
+
borderRadius: 6,
|
|
2611
|
+
background: "var(--srte-input-bg)",
|
|
2612
|
+
color: "var(--srte-input-text)",
|
|
2613
|
+
cursor: "pointer",
|
|
1984
2614
|
}, children: "Close" }) })] }) })), formula && showFormulaDialog && (_jsx("div", { style: {
|
|
1985
2615
|
position: "fixed",
|
|
1986
2616
|
inset: 0,
|
|
1987
|
-
background: "
|
|
2617
|
+
background: "var(--srte-modal-backdrop)",
|
|
1988
2618
|
display: "flex",
|
|
1989
2619
|
alignItems: "center",
|
|
1990
2620
|
justifyContent: "center",
|
|
1991
2621
|
zIndex: 50,
|
|
1992
2622
|
}, onClick: () => setShowFormulaDialog(false), children: _jsxs("div", { style: {
|
|
1993
|
-
background: "
|
|
2623
|
+
background: "var(--srte-modal-bg)",
|
|
1994
2624
|
padding: 16,
|
|
1995
2625
|
borderRadius: 8,
|
|
1996
2626
|
minWidth: 520,
|
|
1997
2627
|
maxWidth: 720,
|
|
1998
|
-
color: "
|
|
2628
|
+
color: "var(--srte-modal-text)",
|
|
1999
2629
|
}, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { style: {
|
|
2000
2630
|
display: "flex",
|
|
2001
2631
|
justifyContent: "space-between",
|
|
@@ -2004,10 +2634,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2004
2634
|
}, children: [_jsx("div", { style: { fontWeight: 600 }, children: "Insert formula" }), _jsx("div", { style: { fontSize: 12, opacity: 0.7 }, children: "Shortcut: Cmd/Ctrl+M" })] }), _jsxs("div", { style: { display: "flex", gap: 8, marginBottom: 8 }, children: [_jsx("input", { value: formulaInput, onChange: (e) => setFormulaInput(e.target.value), placeholder: "Type LaTeX or shortcuts: sqrt(x), x^2, x_1, frac(a,b)", style: {
|
|
2005
2635
|
flex: 1,
|
|
2006
2636
|
padding: "6px 8px",
|
|
2007
|
-
border: "1px solid
|
|
2637
|
+
border: "1px solid var(--srte-border)",
|
|
2008
2638
|
borderRadius: 6,
|
|
2009
|
-
color: "
|
|
2010
|
-
background: "
|
|
2639
|
+
color: "var(--srte-input-text)",
|
|
2640
|
+
background: "var(--srte-input-bg)",
|
|
2011
2641
|
} }), _jsx("button", { onClick: () => {
|
|
2012
2642
|
const tex = normalizeShortcutToLatex(formulaInput);
|
|
2013
2643
|
if (tex)
|
|
@@ -2052,12 +2682,12 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2052
2682
|
}, title: p.tex, style: {
|
|
2053
2683
|
textAlign: "left",
|
|
2054
2684
|
padding: "8px 10px",
|
|
2055
|
-
border: "1px solid
|
|
2685
|
+
border: "1px solid var(--srte-border-light)",
|
|
2056
2686
|
borderRadius: 6,
|
|
2057
|
-
background: "
|
|
2687
|
+
background: "var(--srte-surface-subtle)",
|
|
2058
2688
|
fontSize: 12,
|
|
2059
|
-
color: "
|
|
2060
|
-
}, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 4 }, children: p.label }), _jsxs("div", {
|
|
2689
|
+
color: "var(--srte-modal-text)",
|
|
2690
|
+
}, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 4 }, children: p.label }), _jsxs("div", { children: ["$ ", p.tex, " $"] })] }, i))) }), _jsxs("div", { style: { marginTop: 12, fontSize: 12 }, children: ["Symbols:", " ", [
|
|
2061
2691
|
`\\alpha`,
|
|
2062
2692
|
`\\beta`,
|
|
2063
2693
|
`\\gamma`,
|
|
@@ -2078,10 +2708,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2078
2708
|
marginRight: 6,
|
|
2079
2709
|
marginBottom: 6,
|
|
2080
2710
|
padding: "4px 6px",
|
|
2081
|
-
border: "1px solid
|
|
2711
|
+
border: "1px solid var(--srte-border-light)",
|
|
2082
2712
|
borderRadius: 4,
|
|
2083
|
-
background: "
|
|
2084
|
-
color: "
|
|
2713
|
+
background: "var(--srte-input-bg)",
|
|
2714
|
+
color: "var(--srte-modal-text)",
|
|
2085
2715
|
}, title: sym, children: sym }, i)))] })] }) })), _jsx("div", { style: {
|
|
2086
2716
|
width: "100%",
|
|
2087
2717
|
maxWidth: "100%",
|
|
@@ -2102,8 +2732,14 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2102
2732
|
if (hasImage) {
|
|
2103
2733
|
e.preventDefault();
|
|
2104
2734
|
handleLocalImageFiles(items);
|
|
2735
|
+
return;
|
|
2105
2736
|
}
|
|
2106
2737
|
}
|
|
2738
|
+
const html = e.clipboardData?.getData("text/html");
|
|
2739
|
+
if (html) {
|
|
2740
|
+
e.preventDefault();
|
|
2741
|
+
insertCleanHtml(cleanPastedHtml(html));
|
|
2742
|
+
}
|
|
2107
2743
|
}, onDragOver: (e) => {
|
|
2108
2744
|
// Allow dragging images within editor and file drops
|
|
2109
2745
|
if (draggedImageRef.current ||
|
|
@@ -2371,7 +3007,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2371
3007
|
}, children: [_jsx("div", { style: {
|
|
2372
3008
|
position: "absolute",
|
|
2373
3009
|
inset: 0,
|
|
2374
|
-
outline: "2px solid
|
|
3010
|
+
outline: "2px solid var(--srte-accent)",
|
|
2375
3011
|
outlineOffset: -2,
|
|
2376
3012
|
} }), _jsx("div", { title: "Resize", onMouseDown: (e) => {
|
|
2377
3013
|
e.preventDefault();
|
|
@@ -2407,7 +3043,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2407
3043
|
transform: "translateY(-50%)",
|
|
2408
3044
|
width: 8,
|
|
2409
3045
|
height: 24,
|
|
2410
|
-
background: "
|
|
3046
|
+
background: "var(--srte-accent)",
|
|
2411
3047
|
borderRadius: 2,
|
|
2412
3048
|
cursor: "ew-resize",
|
|
2413
3049
|
pointerEvents: "auto",
|
|
@@ -2445,7 +3081,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2445
3081
|
transform: "translateY(-50%)",
|
|
2446
3082
|
width: 8,
|
|
2447
3083
|
height: 24,
|
|
2448
|
-
background: "
|
|
3084
|
+
background: "var(--srte-accent)",
|
|
2449
3085
|
borderRadius: 2,
|
|
2450
3086
|
cursor: "ew-resize",
|
|
2451
3087
|
pointerEvents: "auto",
|
|
@@ -2475,15 +3111,15 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2475
3111
|
position: "fixed",
|
|
2476
3112
|
left: tableMenu.x,
|
|
2477
3113
|
top: tableMenu.y,
|
|
2478
|
-
background: "
|
|
2479
|
-
border: "1px solid
|
|
3114
|
+
background: "var(--srte-menu-bg)",
|
|
3115
|
+
border: "1px solid var(--srte-border)",
|
|
2480
3116
|
borderRadius: 8,
|
|
2481
|
-
boxShadow: "
|
|
3117
|
+
boxShadow: "var(--srte-menu-shadow)",
|
|
2482
3118
|
padding: 6,
|
|
2483
3119
|
width: 200,
|
|
2484
3120
|
maxHeight: 260,
|
|
2485
3121
|
overflowY: "auto",
|
|
2486
|
-
color: "
|
|
3122
|
+
color: "var(--srte-menu-text)",
|
|
2487
3123
|
}, 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: {
|
|
2488
3124
|
display: "flex",
|
|
2489
3125
|
alignItems: "center",
|
|
@@ -2606,7 +3242,16 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2606
3242
|
}, onClick: () => {
|
|
2607
3243
|
toggleHeaderRow(tableMenu.cell);
|
|
2608
3244
|
setTableMenu(null);
|
|
2609
|
-
}, children: [_jsx("span", { children: "H\u2081" }), _jsx("span", { children: "Toggle header row" })] }),
|
|
3245
|
+
}, children: [_jsx("span", { children: "H\u2081" }), _jsx("span", { children: "Toggle header row" })] }), _jsxs("button", { style: {
|
|
3246
|
+
display: "flex",
|
|
3247
|
+
alignItems: "center",
|
|
3248
|
+
gap: 8,
|
|
3249
|
+
padding: "6px 8px",
|
|
3250
|
+
fontSize: 12,
|
|
3251
|
+
}, onClick: () => {
|
|
3252
|
+
toggleHeaderColumn(tableMenu.cell);
|
|
3253
|
+
setTableMenu(null);
|
|
3254
|
+
}, children: [_jsx("span", { children: "H\u2195" }), _jsx("span", { children: "Toggle header column" })] }), _jsx("hr", { style: { margin: "4px 0" } }), _jsxs("button", { style: {
|
|
2610
3255
|
display: "flex",
|
|
2611
3256
|
alignItems: "center",
|
|
2612
3257
|
gap: 8,
|
|
@@ -2628,13 +3273,15 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2628
3273
|
position: "fixed",
|
|
2629
3274
|
left: imageMenu.x,
|
|
2630
3275
|
top: imageMenu.y,
|
|
2631
|
-
background: "
|
|
2632
|
-
border: "1px solid
|
|
3276
|
+
background: "var(--srte-menu-bg)",
|
|
3277
|
+
border: "1px solid var(--srte-border)",
|
|
2633
3278
|
borderRadius: 8,
|
|
2634
|
-
boxShadow: "
|
|
3279
|
+
boxShadow: "var(--srte-menu-shadow)",
|
|
2635
3280
|
padding: 8,
|
|
2636
|
-
width:
|
|
2637
|
-
|
|
3281
|
+
width: 280,
|
|
3282
|
+
maxHeight: "80vh",
|
|
3283
|
+
overflowY: "auto",
|
|
3284
|
+
color: "var(--srte-menu-text)",
|
|
2638
3285
|
}, 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"
|
|
2639
3286
|
? imageMenu.img.parentElement.href
|
|
2640
3287
|
: "", placeholder: "https://", onChange: (e) => {
|
|
@@ -2660,10 +3307,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2660
3307
|
}, style: {
|
|
2661
3308
|
flex: 1,
|
|
2662
3309
|
padding: "4px 6px",
|
|
2663
|
-
border: "1px solid
|
|
3310
|
+
border: "1px solid var(--srte-border-light)",
|
|
2664
3311
|
borderRadius: 4,
|
|
2665
|
-
color: "
|
|
2666
|
-
background: "
|
|
3312
|
+
color: "var(--srte-input-text)",
|
|
3313
|
+
background: "var(--srte-input-bg)",
|
|
2667
3314
|
} })] }), _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"
|
|
2668
3315
|
? imageMenu.img.parentElement
|
|
2669
3316
|
.target || "_self"
|
|
@@ -2677,20 +3324,20 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2677
3324
|
flex: 1,
|
|
2678
3325
|
height: 28,
|
|
2679
3326
|
padding: "0 6px",
|
|
2680
|
-
border: "1px solid
|
|
3327
|
+
border: "1px solid var(--srte-border-light)",
|
|
2681
3328
|
borderRadius: 4,
|
|
2682
|
-
background: "
|
|
2683
|
-
color: "
|
|
3329
|
+
background: "var(--srte-input-bg)",
|
|
3330
|
+
color: "var(--srte-input-text)",
|
|
2684
3331
|
}, 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) => {
|
|
2685
3332
|
imageMenu.img.alt = e.target.value;
|
|
2686
3333
|
handleInput();
|
|
2687
3334
|
}, style: {
|
|
2688
3335
|
flex: 1,
|
|
2689
3336
|
padding: "4px 6px",
|
|
2690
|
-
border: "1px solid
|
|
3337
|
+
border: "1px solid var(--srte-border-light)",
|
|
2691
3338
|
borderRadius: 4,
|
|
2692
|
-
color: "
|
|
2693
|
-
background: "
|
|
3339
|
+
color: "var(--srte-input-text)",
|
|
3340
|
+
background: "var(--srte-input-bg)",
|
|
2694
3341
|
} })] }), _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) => {
|
|
2695
3342
|
const v = Math.max(40, Math.min(2000, Number(e.target.value) || 0));
|
|
2696
3343
|
imageMenu.img.style.width = v + "px";
|
|
@@ -2699,10 +3346,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2699
3346
|
}, style: {
|
|
2700
3347
|
width: 90,
|
|
2701
3348
|
padding: "4px 6px",
|
|
2702
|
-
border: "1px solid
|
|
3349
|
+
border: "1px solid var(--srte-border-light)",
|
|
2703
3350
|
borderRadius: 4,
|
|
2704
|
-
color: "
|
|
2705
|
-
background: "
|
|
3351
|
+
color: "var(--srte-input-text)",
|
|
3352
|
+
background: "var(--srte-input-bg)",
|
|
2706
3353
|
} }), _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) => {
|
|
2707
3354
|
const v = Math.max(0, Math.min(200, Number(e.target.value) || 0));
|
|
2708
3355
|
imageMenu.img.style.borderRadius = v + "px";
|
|
@@ -2710,10 +3357,10 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2710
3357
|
}, style: {
|
|
2711
3358
|
width: 90,
|
|
2712
3359
|
padding: "4px 6px",
|
|
2713
|
-
border: "1px solid
|
|
3360
|
+
border: "1px solid var(--srte-border-light)",
|
|
2714
3361
|
borderRadius: 4,
|
|
2715
|
-
color: "
|
|
2716
|
-
background: "
|
|
3362
|
+
color: "var(--srte-input-text)",
|
|
3363
|
+
background: "var(--srte-input-bg)",
|
|
2717
3364
|
} }), _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: () => {
|
|
2718
3365
|
const img = imageMenu.img;
|
|
2719
3366
|
img.style.display = "block";
|
|
@@ -2735,7 +3382,58 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2735
3382
|
img.style.margin = "0 0 8px 8px";
|
|
2736
3383
|
scheduleImageOverlay();
|
|
2737
3384
|
handleInput();
|
|
2738
|
-
}, children: "\u27F9" })] }), _jsxs("div", { style: {
|
|
3385
|
+
}, children: "\u27F9" })] }), _jsxs("div", { style: {
|
|
3386
|
+
borderTop: "1px solid var(--srte-border-light)",
|
|
3387
|
+
paddingTop: 6,
|
|
3388
|
+
display: "grid",
|
|
3389
|
+
gap: 6,
|
|
3390
|
+
}, children: [_jsx("div", { style: { fontWeight: 600, fontSize: 11 }, children: "License" }), _jsx("input", { placeholder: "Work name", defaultValue: imageMenu.img.dataset.workName || "", onChange: (e) => {
|
|
3391
|
+
imageMenu.img.dataset.workName = e.target.value;
|
|
3392
|
+
handleInput();
|
|
3393
|
+
}, style: {
|
|
3394
|
+
padding: "4px 6px",
|
|
3395
|
+
border: "1px solid var(--srte-border-light)",
|
|
3396
|
+
borderRadius: 4,
|
|
3397
|
+
color: "var(--srte-input-text)",
|
|
3398
|
+
background: "var(--srte-input-bg)",
|
|
3399
|
+
} }), _jsx("input", { placeholder: "Author", defaultValue: imageMenu.img.dataset.licenseAuthor || "", onChange: (e) => {
|
|
3400
|
+
imageMenu.img.dataset.licenseAuthor = e.target.value;
|
|
3401
|
+
handleInput();
|
|
3402
|
+
}, style: {
|
|
3403
|
+
padding: "4px 6px",
|
|
3404
|
+
border: "1px solid var(--srte-border-light)",
|
|
3405
|
+
borderRadius: 4,
|
|
3406
|
+
color: "var(--srte-input-text)",
|
|
3407
|
+
background: "var(--srte-input-bg)",
|
|
3408
|
+
} }), _jsxs("select", { defaultValue: imageMenu.img.dataset.licenseType || "", onChange: (e) => {
|
|
3409
|
+
imageMenu.img.dataset.licenseType = e.target.value;
|
|
3410
|
+
handleInput();
|
|
3411
|
+
}, style: {
|
|
3412
|
+
height: 28,
|
|
3413
|
+
padding: "0 6px",
|
|
3414
|
+
border: "1px solid var(--srte-border-light)",
|
|
3415
|
+
borderRadius: 4,
|
|
3416
|
+
color: "var(--srte-input-text)",
|
|
3417
|
+
background: "var(--srte-input-bg)",
|
|
3418
|
+
}, children: [_jsx("option", { value: "", children: "License type" }), _jsx("option", { value: "public-domain", children: "Public domain" }), _jsx("option", { value: "cc0", children: "CC0" }), _jsx("option", { value: "cc-by", children: "CC BY" }), _jsx("option", { value: "cc-by-sa", children: "CC BY-SA" }), _jsx("option", { value: "cc-by-nc", children: "CC BY-NC" }), _jsx("option", { value: "rights-managed", children: "Rights managed" }), _jsx("option", { value: "custom", children: "Custom" })] }), _jsx("input", { placeholder: "License notes", defaultValue: imageMenu.img.dataset.licenseText || "", onChange: (e) => {
|
|
3419
|
+
imageMenu.img.dataset.licenseText = e.target.value;
|
|
3420
|
+
handleInput();
|
|
3421
|
+
}, style: {
|
|
3422
|
+
padding: "4px 6px",
|
|
3423
|
+
border: "1px solid var(--srte-border-light)",
|
|
3424
|
+
borderRadius: 4,
|
|
3425
|
+
color: "var(--srte-input-text)",
|
|
3426
|
+
background: "var(--srte-input-bg)",
|
|
3427
|
+
} }), _jsx("input", { placeholder: "Source URL", defaultValue: imageMenu.img.dataset.licenseUrl || "", onChange: (e) => {
|
|
3428
|
+
imageMenu.img.dataset.licenseUrl = e.target.value;
|
|
3429
|
+
handleInput();
|
|
3430
|
+
}, style: {
|
|
3431
|
+
padding: "4px 6px",
|
|
3432
|
+
border: "1px solid var(--srte-border-light)",
|
|
3433
|
+
borderRadius: 4,
|
|
3434
|
+
color: "var(--srte-input-text)",
|
|
3435
|
+
background: "var(--srte-input-bg)",
|
|
3436
|
+
} })] }), _jsxs("div", { style: { display: "flex", gap: 6 }, children: [_jsx("button", { onClick: () => {
|
|
2739
3437
|
replaceTargetRef.current = imageMenu.img;
|
|
2740
3438
|
fileInputRef.current?.click();
|
|
2741
3439
|
}, children: "Replace\u2026" }), _jsx("button", { onClick: () => {
|
|
@@ -2747,7 +3445,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
2747
3445
|
img.style.float = "none";
|
|
2748
3446
|
scheduleImageOverlay();
|
|
2749
3447
|
handleInput();
|
|
2750
|
-
}, children: "Reset" })] }), _jsxs("div", { style: { display: "flex", gap: 6 }, children: [_jsx("button", { style: { color: "
|
|
3448
|
+
}, children: "Reset" })] }), _jsxs("div", { style: { display: "flex", gap: 6 }, children: [_jsx("button", { style: { color: "var(--srte-danger)" }, onClick: () => {
|
|
2751
3449
|
imageMenu.img.remove();
|
|
2752
3450
|
setImageMenu(null);
|
|
2753
3451
|
setSelectedImage(null);
|