smartrte-react 0.3.5 → 1.0.0-beta.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/CHANGELOG.md +14 -0
- package/README.md +106 -14
- package/dist/adapters/domChecklistCommandBridge.js +1 -1
- package/dist/adapters/domCommandBridge.d.ts +2 -2
- package/dist/adapters/domCommandBridge.js +2 -2
- package/dist/adapters/domInlineAtomCommandBridge.d.ts +10 -9
- package/dist/adapters/domInlineAtomCommandBridge.js +154 -50
- package/dist/adapters/domInlineImageCommandBridge.d.ts +7 -7
- package/dist/adapters/domInlineImageCommandBridge.js +6 -72
- package/dist/adapters/domMoveCommandBridge.js +1 -1
- package/dist/adapters/domSelectionBridge.d.ts +3 -3
- package/dist/adapters/domSmartDocument.d.ts +4 -4
- package/dist/adapters/domSmartDocument.js +2 -2
- package/dist/adapters/domTableCommandBridge.d.ts +42 -16
- package/dist/adapters/domTableCommandBridge.js +203 -173
- package/dist/adapters/internalFlags.d.ts +0 -8
- package/dist/adapters/internalFlags.js +0 -24
- package/dist/adapters/legacyListShadowComparator.d.ts +1 -1
- package/dist/adapters/legacyListShadowComparator.js +1 -1
- package/dist/adapters/pdfPrint.d.ts +8 -0
- package/dist/adapters/pdfPrint.js +22 -0
- package/dist/adapters/shadowMode.d.ts +3 -3
- package/dist/adapters/shadowMode.js +1 -1
- package/dist/canonicalEditorRuntime.d.ts +53 -1
- package/dist/canonicalEditorRuntime.js +61 -4
- package/dist/capabilityPresets.d.ts +27 -0
- package/dist/capabilityPresets.js +21 -0
- package/dist/collabTransport.d.ts +66 -0
- package/dist/collabTransport.js +1 -0
- package/dist/commentProvider.d.ts +24 -0
- package/dist/commentProvider.js +1 -0
- package/dist/components/CanonicalAuthorityEditor.d.ts +35 -1
- package/dist/components/CanonicalAuthorityEditor.js +1086 -112
- package/dist/components/ClassicEditorAuthority.d.ts +93 -22
- package/dist/components/ClassicEditorAuthority.js +11 -43
- package/dist/components/ColorPickerPopover.d.ts +39 -0
- package/dist/components/ColorPickerPopover.js +285 -0
- package/dist/components/CommentMarkers.d.ts +25 -0
- package/dist/components/CommentMarkers.js +105 -0
- package/dist/components/CommentThreadPanel.d.ts +26 -0
- package/dist/components/CommentThreadPanel.js +47 -0
- package/dist/components/ContextMenu.d.ts +23 -0
- package/dist/components/ContextMenu.js +141 -0
- package/dist/components/FormulaLibraryPopover.d.ts +16 -0
- package/dist/components/FormulaLibraryPopover.js +107 -0
- package/dist/components/LinkEditorPopover.d.ts +3 -1
- package/dist/components/LinkEditorPopover.js +22 -6
- package/dist/components/MediaManager.d.ts +4 -20
- package/dist/components/MediaManager.js +35 -6
- package/dist/components/MediaOverlay.d.ts +36 -0
- package/dist/components/MediaOverlay.js +163 -0
- package/dist/components/SpecialCharacterPopover.d.ts +18 -0
- package/dist/components/SpecialCharacterPopover.js +99 -0
- package/dist/components/StructuralSuggestionMarkers.d.ts +20 -0
- package/dist/components/StructuralSuggestionMarkers.js +56 -0
- package/dist/components/SuggestionPanel.d.ts +26 -0
- package/dist/components/SuggestionPanel.js +33 -0
- package/dist/components/TableBorderPopover.d.ts +59 -0
- package/dist/components/TableBorderPopover.js +147 -0
- package/dist/components/TableResizeHandles.d.ts +25 -0
- package/dist/components/TableResizeHandles.js +301 -0
- package/dist/components/TableSizePickerPopover.d.ts +16 -0
- package/dist/components/TableSizePickerPopover.js +126 -0
- package/dist/components/ToolbarPrimitives.d.ts +129 -0
- package/dist/components/ToolbarPrimitives.js +146 -0
- package/dist/components/VersionHistoryPanel.d.ts +9 -0
- package/dist/components/VersionHistoryPanel.js +157 -0
- package/dist/formulaLibrary.d.ts +31 -0
- package/dist/formulaLibrary.js +90 -0
- package/dist/index.d.ts +22 -24
- package/dist/index.js +14 -11
- package/dist/mediaManagerAdapter.d.ts +12 -0
- package/dist/mediaManagerAdapter.js +34 -0
- package/dist/mediaProvider.d.ts +21 -1
- package/dist/specialCharacters.d.ts +22 -0
- package/dist/specialCharacters.js +86 -0
- package/dist/standalone/classic-editor-embed.js +19 -12
- package/dist/suggestionProvider.d.ts +17 -0
- package/dist/suggestionProvider.js +1 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +150 -20
- package/dist/versionProvider.d.ts +29 -0
- package/dist/versionProvider.js +1 -0
- package/package.json +28 -14
- package/dist/adapters/canonicalInlineCommandBridge.d.ts +0 -15
- package/dist/adapters/canonicalInlineCommandBridge.js +0 -269
- package/dist/adapters/canonicalListCommandBridge.d.ts +0 -26
- package/dist/adapters/canonicalListCommandBridge.js +0 -430
- package/dist/adapters/coreBold.d.ts +0 -5
- package/dist/adapters/coreBold.js +0 -3
- package/dist/adapters/documentFormats.d.ts +0 -26
- package/dist/adapters/documentFormats.js +0 -49
- package/dist/adapters/docxFormat.d.ts +0 -5
- package/dist/adapters/docxFormat.js +0 -272
- package/dist/adapters/domBlockCommandBridge.d.ts +0 -19
- package/dist/adapters/domBlockCommandBridge.js +0 -79
- package/dist/adapters/inlineMarkCoreExecution.d.ts +0 -9
- package/dist/adapters/inlineMarkCoreExecution.js +0 -25
- package/dist/adapters/pdfFormat.d.ts +0 -23
- package/dist/adapters/pdfFormat.js +0 -204
- package/dist/adapters/portableDocxAtoms.d.ts +0 -4
- package/dist/adapters/portableDocxAtoms.js +0 -58
- package/dist/adapters/styledDocxFormat.d.ts +0 -8
- package/dist/adapters/styledDocxFormat.js +0 -190
- package/dist/builtInFormatDefinitions.d.ts +0 -5
- package/dist/builtInFormatDefinitions.js +0 -82
- package/dist/canonicalAuthorityFlag.d.ts +0 -32
- package/dist/canonicalAuthorityFlag.js +0 -49
- package/dist/canonicalClipboardRuntime.d.ts +0 -15
- package/dist/canonicalClipboardRuntime.js +0 -76
- package/dist/components/ClassicEditor.d.ts +0 -76
- package/dist/components/ClassicEditor.js +0 -6729
- package/dist/editorController.d.ts +0 -78
- package/dist/editorController.js +0 -298
- package/dist/formatFidelity.d.ts +0 -14
- package/dist/formatFidelity.js +0 -107
- package/dist/formatRuntime.d.ts +0 -50
- package/dist/formatRuntime.js +0 -20
- package/dist/pluginRuntime.d.ts +0 -68
- package/dist/pluginRuntime.js +0 -78
- package/dist/standalone/editor.js +0 -1068
- package/dist/test-harness/atomShadowComparator.d.ts +0 -14
- package/dist/test-harness/atomShadowComparator.js +0 -63
- package/dist/test-harness/blockShadowComparator.d.ts +0 -30
- package/dist/test-harness/blockShadowComparator.js +0 -140
- package/dist/test-harness/clipboardShadowComparator.d.ts +0 -12
- package/dist/test-harness/clipboardShadowComparator.js +0 -46
- package/dist/test-harness/inlineShadowComparator.d.ts +0 -32
- package/dist/test-harness/inlineShadowComparator.js +0 -152
- package/dist/test-harness/legacyAtomEngine.d.ts +0 -10
- package/dist/test-harness/legacyAtomEngine.js +0 -15
- package/dist/test-harness/legacyBlockEngine.d.ts +0 -31
- package/dist/test-harness/legacyBlockEngine.js +0 -31
- package/dist/test-harness/legacyClipboardEngine.d.ts +0 -14
- package/dist/test-harness/legacyClipboardEngine.js +0 -67
- package/dist/test-harness/legacyInlineEngine.d.ts +0 -19
- package/dist/test-harness/legacyInlineEngine.js +0 -49
- package/dist/test-harness/legacyTableEngine.d.ts +0 -12
- package/dist/test-harness/legacyTableEngine.js +0 -25
- package/dist/test-harness/tableShadowComparator.d.ts +0 -29
- package/dist/test-harness/tableShadowComparator.js +0 -101
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
const marker = /⟦SRTE_(FORMULA|IMAGE):([^⟧]+)⟧/g;
|
|
2
|
-
export const portableFormulaMarker = (value, displayText) => `⟦SRTE_FORMULA:${encodeURIComponent(JSON.stringify({ value, displayText }))}⟧`;
|
|
3
|
-
export const portableImageMarker = (src, alt, title) => `⟦SRTE_IMAGE:${encodeURIComponent(JSON.stringify({ src, alt, title }))}⟧`;
|
|
4
|
-
/** Restores Smart RTE atom fallback markers retained by DOCX text runs. */
|
|
5
|
-
export const restorePortableDocxAtoms = (html, ownerDocument) => {
|
|
6
|
-
const root = ownerDocument.createElement("div");
|
|
7
|
-
root.innerHTML = html;
|
|
8
|
-
const walker = ownerDocument.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
9
|
-
const textNodes = [];
|
|
10
|
-
let current = walker.nextNode();
|
|
11
|
-
while (current) {
|
|
12
|
-
textNodes.push(current);
|
|
13
|
-
current = walker.nextNode();
|
|
14
|
-
}
|
|
15
|
-
textNodes.forEach((textNode) => {
|
|
16
|
-
const text = textNode.data;
|
|
17
|
-
marker.lastIndex = 0;
|
|
18
|
-
if (!marker.test(text))
|
|
19
|
-
return;
|
|
20
|
-
marker.lastIndex = 0;
|
|
21
|
-
const fragment = ownerDocument.createDocumentFragment();
|
|
22
|
-
let cursor = 0;
|
|
23
|
-
let match;
|
|
24
|
-
while ((match = marker.exec(text))) {
|
|
25
|
-
if (match.index > cursor)
|
|
26
|
-
fragment.append(text.slice(cursor, match.index));
|
|
27
|
-
try {
|
|
28
|
-
const payload = JSON.parse(decodeURIComponent(match[2]));
|
|
29
|
-
if (match[1] === "FORMULA" && payload.value) {
|
|
30
|
-
const formula = ownerDocument.createElement("span");
|
|
31
|
-
formula.dataset.formula = payload.value;
|
|
32
|
-
formula.textContent = payload.displayText || `$${payload.value}$`;
|
|
33
|
-
fragment.append(formula);
|
|
34
|
-
}
|
|
35
|
-
else if (match[1] === "IMAGE" && payload.src) {
|
|
36
|
-
const image = ownerDocument.createElement("img");
|
|
37
|
-
image.src = payload.src;
|
|
38
|
-
image.alt = payload.alt || "";
|
|
39
|
-
if (payload.title)
|
|
40
|
-
image.title = payload.title;
|
|
41
|
-
image.dataset.srteInline = "true";
|
|
42
|
-
fragment.append(image);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
fragment.append(match[0]);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
fragment.append(match[0]);
|
|
50
|
-
}
|
|
51
|
-
cursor = marker.lastIndex;
|
|
52
|
-
}
|
|
53
|
-
if (cursor < text.length)
|
|
54
|
-
fragment.append(text.slice(cursor));
|
|
55
|
-
textNode.replaceWith(fragment);
|
|
56
|
-
});
|
|
57
|
-
return root.innerHTML;
|
|
58
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type SmartDocument } from "smartrte-core";
|
|
2
|
-
export interface StyledDocxImportResult {
|
|
3
|
-
document: SmartDocument;
|
|
4
|
-
layoutHtml: string;
|
|
5
|
-
source: "wordprocessingml" | "mammoth";
|
|
6
|
-
}
|
|
7
|
-
export declare const enhanceDocxTables: (root: HTMLElement) => void;
|
|
8
|
-
export declare const importStyledDocxDocument: (arrayBuffer: ArrayBuffer, ownerDocument: Document) => Promise<StyledDocxImportResult>;
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import JSZip from "jszip";
|
|
2
|
-
import { normalizeSmartDocument } from "smartrte-core";
|
|
3
|
-
import { restorePortableDocxAtoms } from "./portableDocxAtoms.js";
|
|
4
|
-
import { serializeSmartDocument, smartDocumentFromHtml } from "./domSmartDocument.js";
|
|
5
|
-
import { importDocxDocumentWithMammoth } from "./docxFormat.js";
|
|
6
|
-
const directChildren = (node) => Array.from(node.children);
|
|
7
|
-
const firstChildByName = (node, localName) => node ? directChildren(node).find((child) => child.localName === localName) : undefined;
|
|
8
|
-
const childrenByName = (node, localName) => node ? directChildren(node).filter((child) => child.localName === localName) : [];
|
|
9
|
-
const docxAttr = (node, name) => {
|
|
10
|
-
if (!node)
|
|
11
|
-
return "";
|
|
12
|
-
return node.getAttribute(`w:${name}`)
|
|
13
|
-
|| node.getAttribute(name)
|
|
14
|
-
|| node.getAttributeNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", name)
|
|
15
|
-
|| "";
|
|
16
|
-
};
|
|
17
|
-
const escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
18
|
-
const docxHexColor = (value) => {
|
|
19
|
-
if (!value || value.toLowerCase() === "auto")
|
|
20
|
-
return "";
|
|
21
|
-
const normalized = value.replace(/[^0-9a-f]/gi, "");
|
|
22
|
-
return normalized.length === 6 ? `#${normalized}` : "";
|
|
23
|
-
};
|
|
24
|
-
const twipsToPt = (value) => {
|
|
25
|
-
if (!value)
|
|
26
|
-
return "";
|
|
27
|
-
const numeric = Number(value);
|
|
28
|
-
return Number.isFinite(numeric) ? `${Math.max(numeric / 20, 0)}pt` : "";
|
|
29
|
-
};
|
|
30
|
-
const halfPointsToPt = (value) => {
|
|
31
|
-
if (!value)
|
|
32
|
-
return "";
|
|
33
|
-
const numeric = Number(value);
|
|
34
|
-
return Number.isFinite(numeric) ? `${Math.max(numeric / 2, 1)}pt` : "";
|
|
35
|
-
};
|
|
36
|
-
const cssRules = (rules) => rules.filter(([, value]) => Boolean(value)).map(([name, value]) => `${name}: ${value}`).join("; ");
|
|
37
|
-
const styleAttr = (style) => style ? ` style="${escapeHtml(style)}"` : "";
|
|
38
|
-
const borderCss = (border) => {
|
|
39
|
-
if (!border)
|
|
40
|
-
return "";
|
|
41
|
-
const value = docxAttr(border, "val");
|
|
42
|
-
if (!value || value === "nil" || value === "none")
|
|
43
|
-
return "";
|
|
44
|
-
const size = Number(docxAttr(border, "sz")) || 4;
|
|
45
|
-
const color = docxHexColor(docxAttr(border, "color")) || "#d1d5db";
|
|
46
|
-
return `${Math.max(size / 8, 0.5)}px solid ${color}`;
|
|
47
|
-
};
|
|
48
|
-
const paragraphStyle = (paragraph) => {
|
|
49
|
-
const properties = firstChildByName(paragraph, "pPr");
|
|
50
|
-
if (!properties)
|
|
51
|
-
return "";
|
|
52
|
-
const spacing = firstChildByName(properties, "spacing");
|
|
53
|
-
const justification = firstChildByName(properties, "jc");
|
|
54
|
-
const indent = firstChildByName(properties, "ind");
|
|
55
|
-
const bottomBorder = firstChildByName(firstChildByName(properties, "pBdr"), "bottom");
|
|
56
|
-
const line = docxAttr(spacing, "line");
|
|
57
|
-
return cssRules([
|
|
58
|
-
["text-align", docxAttr(justification, "val")],
|
|
59
|
-
["margin-top", twipsToPt(docxAttr(spacing, "before"))],
|
|
60
|
-
["margin-bottom", twipsToPt(docxAttr(spacing, "after"))],
|
|
61
|
-
["margin-left", twipsToPt(docxAttr(indent, "left"))],
|
|
62
|
-
["text-indent", twipsToPt(docxAttr(indent, "firstLine"))],
|
|
63
|
-
["line-height", line && docxAttr(spacing, "lineRule") === "auto" ? `${Number(line) / 240}` : ""],
|
|
64
|
-
["border-bottom", borderCss(bottomBorder)],
|
|
65
|
-
]);
|
|
66
|
-
};
|
|
67
|
-
const runStyle = (run) => {
|
|
68
|
-
const properties = firstChildByName(run, "rPr");
|
|
69
|
-
if (!properties)
|
|
70
|
-
return "";
|
|
71
|
-
const color = docxHexColor(docxAttr(firstChildByName(properties, "color"), "val"));
|
|
72
|
-
const highlight = docxHexColor(docxAttr(firstChildByName(properties, "highlight"), "val"));
|
|
73
|
-
const shade = docxHexColor(docxAttr(firstChildByName(properties, "shd"), "fill"));
|
|
74
|
-
return cssRules([
|
|
75
|
-
["font-weight", firstChildByName(properties, "b") ? "700" : ""],
|
|
76
|
-
["font-style", firstChildByName(properties, "i") ? "italic" : ""],
|
|
77
|
-
["text-decoration", firstChildByName(properties, "u") ? "underline" : ""],
|
|
78
|
-
["color", color],
|
|
79
|
-
["background-color", highlight || shade],
|
|
80
|
-
["font-size", halfPointsToPt(docxAttr(firstChildByName(properties, "sz"), "val"))],
|
|
81
|
-
]);
|
|
82
|
-
};
|
|
83
|
-
const runHtml = (run) => {
|
|
84
|
-
const properties = firstChildByName(run, "rPr");
|
|
85
|
-
const verticalAlignment = docxAttr(firstChildByName(properties, "vertAlign"), "val");
|
|
86
|
-
const content = directChildren(run).map((child) => {
|
|
87
|
-
if (child.localName === "t")
|
|
88
|
-
return escapeHtml(child.textContent || "");
|
|
89
|
-
if (child.localName === "tab")
|
|
90
|
-
return " ";
|
|
91
|
-
if (child.localName === "br") {
|
|
92
|
-
return docxAttr(child, "type") === "page" ? '<hr class="srte-docx-page-break">' : "<br>";
|
|
93
|
-
}
|
|
94
|
-
return "";
|
|
95
|
-
}).join("");
|
|
96
|
-
if (!content)
|
|
97
|
-
return "";
|
|
98
|
-
const tag = verticalAlignment === "superscript" ? "sup" : verticalAlignment === "subscript" ? "sub" : "span";
|
|
99
|
-
return `<${tag}${styleAttr(runStyle(run))}>${content}</${tag}>`;
|
|
100
|
-
};
|
|
101
|
-
const paragraphHtml = (paragraph) => {
|
|
102
|
-
const content = childrenByName(paragraph, "r").map(runHtml).join("");
|
|
103
|
-
return `<p${styleAttr(paragraphStyle(paragraph))}>${content || "<br>"}</p>`;
|
|
104
|
-
};
|
|
105
|
-
const cellStyle = (cell) => {
|
|
106
|
-
const properties = firstChildByName(cell, "tcPr");
|
|
107
|
-
const borders = firstChildByName(properties, "tcBorders");
|
|
108
|
-
return cssRules([
|
|
109
|
-
["width", twipsToPt(docxAttr(firstChildByName(properties, "tcW"), "w"))],
|
|
110
|
-
["background-color", docxHexColor(docxAttr(firstChildByName(properties, "shd"), "fill"))],
|
|
111
|
-
["border-top", borderCss(firstChildByName(borders, "top"))],
|
|
112
|
-
["border-right", borderCss(firstChildByName(borders, "right"))],
|
|
113
|
-
["border-bottom", borderCss(firstChildByName(borders, "bottom"))],
|
|
114
|
-
["border-left", borderCss(firstChildByName(borders, "left"))],
|
|
115
|
-
["padding", "8px"],
|
|
116
|
-
["vertical-align", "top"],
|
|
117
|
-
]);
|
|
118
|
-
};
|
|
119
|
-
const tableHtml = (table) => {
|
|
120
|
-
const rows = childrenByName(table, "tr").map((row) => {
|
|
121
|
-
const cells = childrenByName(row, "tc").map((cell) => {
|
|
122
|
-
const content = directChildren(cell)
|
|
123
|
-
.filter((child) => child.localName === "p" || child.localName === "tbl")
|
|
124
|
-
.map((child) => child.localName === "p" ? paragraphHtml(child) : tableHtml(child))
|
|
125
|
-
.join("");
|
|
126
|
-
return `<td${styleAttr(cellStyle(cell))}>${content || "<p><br></p>"}</td>`;
|
|
127
|
-
}).join("");
|
|
128
|
-
return `<tr>${cells}</tr>`;
|
|
129
|
-
}).join("");
|
|
130
|
-
return `<table style="border-collapse: collapse; width: 100%; margin: 12px 0;"><tbody>${rows}</tbody></table>`;
|
|
131
|
-
};
|
|
132
|
-
export const enhanceDocxTables = (root) => {
|
|
133
|
-
root.querySelectorAll("table").forEach((table) => {
|
|
134
|
-
var _a, _b;
|
|
135
|
-
const styledTable = table;
|
|
136
|
-
(_a = styledTable.style).borderCollapse || (_a.borderCollapse = "collapse");
|
|
137
|
-
(_b = styledTable.style).width || (_b.width = "100%");
|
|
138
|
-
table.querySelectorAll("td, th").forEach((cell) => {
|
|
139
|
-
var _a, _b;
|
|
140
|
-
const styledCell = cell;
|
|
141
|
-
if (!styledCell.style.border && !styledCell.style.borderTop && !styledCell.style.borderRight
|
|
142
|
-
&& !styledCell.style.borderBottom && !styledCell.style.borderLeft) {
|
|
143
|
-
styledCell.style.border = "1px solid #d1d5db";
|
|
144
|
-
}
|
|
145
|
-
(_a = styledCell.style).padding || (_a.padding = "8px");
|
|
146
|
-
(_b = styledCell.style).verticalAlign || (_b.verticalAlign = "top");
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
};
|
|
150
|
-
const mammothFallback = async (arrayBuffer, ownerDocument) => {
|
|
151
|
-
const document = await importDocxDocumentWithMammoth(arrayBuffer, ownerDocument);
|
|
152
|
-
const container = ownerDocument.createElement("div");
|
|
153
|
-
container.innerHTML = serializeSmartDocument(document);
|
|
154
|
-
enhanceDocxTables(container);
|
|
155
|
-
return { document, layoutHtml: container.innerHTML, source: "mammoth" };
|
|
156
|
-
};
|
|
157
|
-
export const importStyledDocxDocument = async (arrayBuffer, ownerDocument) => {
|
|
158
|
-
try {
|
|
159
|
-
const zip = await JSZip.loadAsync(arrayBuffer);
|
|
160
|
-
const documentXml = await zip.file("word/document.xml")?.async("text");
|
|
161
|
-
if (!documentXml)
|
|
162
|
-
return mammothFallback(arrayBuffer, ownerDocument);
|
|
163
|
-
const parsed = new ownerDocument.defaultView.DOMParser().parseFromString(documentXml, "application/xml");
|
|
164
|
-
if (parsed.querySelector("parsererror"))
|
|
165
|
-
return mammothFallback(arrayBuffer, ownerDocument);
|
|
166
|
-
const body = Array.from(parsed.getElementsByTagName("*")).find((node) => node.localName === "body");
|
|
167
|
-
if (!body)
|
|
168
|
-
return mammothFallback(arrayBuffer, ownerDocument);
|
|
169
|
-
const rawHtml = directChildren(body).filter((node) => node.localName !== "sectPr").map((node) => {
|
|
170
|
-
if (node.localName === "p")
|
|
171
|
-
return paragraphHtml(node);
|
|
172
|
-
if (node.localName === "tbl")
|
|
173
|
-
return tableHtml(node);
|
|
174
|
-
return "";
|
|
175
|
-
}).join("");
|
|
176
|
-
if (!rawHtml.trim())
|
|
177
|
-
return mammothFallback(arrayBuffer, ownerDocument);
|
|
178
|
-
const container = ownerDocument.createElement("div");
|
|
179
|
-
container.innerHTML = restorePortableDocxAtoms(rawHtml, ownerDocument);
|
|
180
|
-
enhanceDocxTables(container);
|
|
181
|
-
return {
|
|
182
|
-
document: normalizeSmartDocument(smartDocumentFromHtml(container.innerHTML, ownerDocument)),
|
|
183
|
-
layoutHtml: container.innerHTML,
|
|
184
|
-
source: "wordprocessingml",
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
return mammothFallback(arrayBuffer, ownerDocument);
|
|
189
|
-
}
|
|
190
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { EditorFormatDefinition } from "./formatRuntime.js";
|
|
2
|
-
export interface BuiltInFormatDefinitionOptions {
|
|
3
|
-
preserveDocxStyles?: boolean;
|
|
4
|
-
}
|
|
5
|
-
export declare const createBuiltInFormatDefinitions: (options?: BuiltInFormatDefinitionOptions) => readonly EditorFormatDefinition[];
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { exportTextDocument, importTextDocument } from "./adapters/documentFormats.js";
|
|
2
|
-
import { exportDocxDocument, importDocxDocumentWithMammoth } from "./adapters/docxFormat.js";
|
|
3
|
-
import { importPdfDocument, printSmartDocumentAsPdf } from "./adapters/pdfFormat.js";
|
|
4
|
-
import { enhanceDocxTables, importStyledDocxDocument } from "./adapters/styledDocxFormat.js";
|
|
5
|
-
import { serializeSmartDocument } from "./adapters/domSmartDocument.js";
|
|
6
|
-
const standaloneHtmlDocument = (html) => `<!doctype html>
|
|
7
|
-
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
-
<title>Smart RTE Export</title><style>
|
|
9
|
-
html,body{margin:0;background:#fff;color:#111;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.6}
|
|
10
|
-
body{padding:32px}.srte-export{max-width:960px;margin:0 auto}h1,h2,h3,h4,h5,h6{line-height:1.3;margin:1.25em 0 .5em}
|
|
11
|
-
p{margin:0 0 .85em}blockquote{border-left:4px solid #1e90ff;margin:.75em 0;padding:.5em 1em;background:#f3f4f6}
|
|
12
|
-
ul,ol{margin:.75em 0;padding-left:1.75em;list-style-position:outside}li{display:list-item;margin:.25em 0;padding-left:.25em}
|
|
13
|
-
table{border-collapse:collapse;width:100%;margin:12px 0}td,th{border:1px solid #d1d5db;padding:8px;vertical-align:top;text-align:left}
|
|
14
|
-
th{background:#f3f4f6;font-weight:700}img{max-width:100%;height:auto}pre,code{background:#f3f4f6;border-radius:4px}
|
|
15
|
-
pre{padding:12px;overflow-x:auto;white-space:pre-wrap}@media print{body{padding:0}.srte-export{max-width:none}}
|
|
16
|
-
</style></head><body><main class="srte-export">${html || "<p></p>"}</main></body></html>`;
|
|
17
|
-
export const createBuiltInFormatDefinitions = (options = {}) => [
|
|
18
|
-
{
|
|
19
|
-
id: "pdf", label: "PDF", extension: "pdf", accept: "application/pdf",
|
|
20
|
-
canImport: true, canExport: true, confirmImportWhenNotEmpty: true,
|
|
21
|
-
importFile: async (file, context) => {
|
|
22
|
-
const result = await importPdfDocument(await file.arrayBuffer(), context.ownerDocument);
|
|
23
|
-
return { ...result, preserveColors: true, preserveDocumentLayout: true };
|
|
24
|
-
},
|
|
25
|
-
exportDocument: (document, context) => {
|
|
26
|
-
printSmartDocumentAsPdf(document, context.hostWindow);
|
|
27
|
-
return { kind: "handled" };
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: "docx", label: "Microsoft Word", extension: "docx", accept: ".docx",
|
|
32
|
-
canImport: true, canExport: true, confirmImportWhenNotEmpty: true,
|
|
33
|
-
importFile: async (file, context) => {
|
|
34
|
-
const buffer = await file.arrayBuffer();
|
|
35
|
-
if (options.preserveDocxStyles ?? true) {
|
|
36
|
-
const result = await importStyledDocxDocument(buffer, context.ownerDocument);
|
|
37
|
-
return {
|
|
38
|
-
document: result.document,
|
|
39
|
-
layoutHtml: `<div class="srte-preserve-colors">${result.layoutHtml}</div>`,
|
|
40
|
-
preserveColors: true,
|
|
41
|
-
preserveDocumentLayout: true,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const document = await importDocxDocumentWithMammoth(buffer, context.ownerDocument);
|
|
45
|
-
const container = context.ownerDocument.createElement("div");
|
|
46
|
-
container.innerHTML = serializeSmartDocument(document);
|
|
47
|
-
enhanceDocxTables(container);
|
|
48
|
-
return {
|
|
49
|
-
document,
|
|
50
|
-
layoutHtml: `<div class="srte-preserve-colors">${container.innerHTML}</div>`,
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
exportDocument: async (document) => ({
|
|
54
|
-
kind: "blob", filename: "smart-rte-export.docx",
|
|
55
|
-
content: await exportDocxDocument(document),
|
|
56
|
-
}),
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: "html", label: "HTML", extension: "html", accept: ".html,.htm,text/html",
|
|
60
|
-
canImport: true, canExport: true,
|
|
61
|
-
importFile: async (file, context) => ({
|
|
62
|
-
document: importTextDocument("html", await file.text(), context),
|
|
63
|
-
preserveColors: true, preserveDocumentLayout: true,
|
|
64
|
-
}),
|
|
65
|
-
exportDocument: (document) => ({
|
|
66
|
-
kind: "text", filename: "smart-rte-export.html", mediaType: "text/html;charset=utf-8",
|
|
67
|
-
content: standaloneHtmlDocument(exportTextDocument("html", document)),
|
|
68
|
-
}),
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
id: "markdown", label: "Markdown", extension: "md",
|
|
72
|
-
accept: ".md,.markdown,text/markdown,text/plain", canImport: true, canExport: true,
|
|
73
|
-
importFile: async (file, context) => ({
|
|
74
|
-
document: importTextDocument("markdown", await file.text(), context),
|
|
75
|
-
preserveColors: true, preserveDocumentLayout: true,
|
|
76
|
-
}),
|
|
77
|
-
exportDocument: (document) => ({
|
|
78
|
-
kind: "text", filename: "smart-rte-export.md", mediaType: "text/markdown;charset=utf-8",
|
|
79
|
-
content: exportTextDocument("markdown", document),
|
|
80
|
-
}),
|
|
81
|
-
},
|
|
82
|
-
];
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export interface CanonicalAuthorityContext {
|
|
2
|
-
tenantId?: string;
|
|
3
|
-
documentId?: string;
|
|
4
|
-
}
|
|
5
|
-
export interface CanonicalAuthorityFlagSnapshot {
|
|
6
|
-
global: boolean;
|
|
7
|
-
tenants: Readonly<Record<string, boolean>>;
|
|
8
|
-
documents: Readonly<Record<string, boolean>>;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Runtime rollback switch. Resolution order is direct component override,
|
|
12
|
-
* document, tenant, then global. Development stays opt-in until the Phase 8b
|
|
13
|
-
* replay and production-surface gates have passed.
|
|
14
|
-
*/
|
|
15
|
-
declare class CanonicalAuthorityFlag {
|
|
16
|
-
private globalEnabled;
|
|
17
|
-
private tenants;
|
|
18
|
-
private documents;
|
|
19
|
-
private listeners;
|
|
20
|
-
private version;
|
|
21
|
-
private changed;
|
|
22
|
-
enabled(context?: CanonicalAuthorityContext, direct?: boolean): boolean;
|
|
23
|
-
setGlobal(enabled: boolean): void;
|
|
24
|
-
setTenant(tenantId: string, enabled: boolean | null): void;
|
|
25
|
-
setDocument(documentId: string, enabled: boolean | null): void;
|
|
26
|
-
snapshot(): CanonicalAuthorityFlagSnapshot;
|
|
27
|
-
subscribe(listener: () => void): () => void;
|
|
28
|
-
getVersion(): number;
|
|
29
|
-
reset(): void;
|
|
30
|
-
}
|
|
31
|
-
export declare const canonicalAuthorityFlag: CanonicalAuthorityFlag;
|
|
32
|
-
export {};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime rollback switch. Resolution order is direct component override,
|
|
3
|
-
* document, tenant, then global. Development stays opt-in until the Phase 8b
|
|
4
|
-
* replay and production-surface gates have passed.
|
|
5
|
-
*/
|
|
6
|
-
class CanonicalAuthorityFlag {
|
|
7
|
-
constructor() {
|
|
8
|
-
this.globalEnabled = false;
|
|
9
|
-
this.tenants = new Map();
|
|
10
|
-
this.documents = new Map();
|
|
11
|
-
this.listeners = new Set();
|
|
12
|
-
this.version = 0;
|
|
13
|
-
}
|
|
14
|
-
changed() { this.version += 1; this.listeners.forEach((listener) => listener()); }
|
|
15
|
-
enabled(context = {}, direct) {
|
|
16
|
-
if (direct !== undefined)
|
|
17
|
-
return direct;
|
|
18
|
-
if (context.documentId && this.documents.has(context.documentId))
|
|
19
|
-
return this.documents.get(context.documentId);
|
|
20
|
-
if (context.tenantId && this.tenants.has(context.tenantId))
|
|
21
|
-
return this.tenants.get(context.tenantId);
|
|
22
|
-
return this.globalEnabled;
|
|
23
|
-
}
|
|
24
|
-
setGlobal(enabled) { if (this.globalEnabled !== enabled) {
|
|
25
|
-
this.globalEnabled = enabled;
|
|
26
|
-
this.changed();
|
|
27
|
-
} }
|
|
28
|
-
setTenant(tenantId, enabled) {
|
|
29
|
-
if (enabled === null)
|
|
30
|
-
this.tenants.delete(tenantId);
|
|
31
|
-
else
|
|
32
|
-
this.tenants.set(tenantId, enabled);
|
|
33
|
-
this.changed();
|
|
34
|
-
}
|
|
35
|
-
setDocument(documentId, enabled) {
|
|
36
|
-
if (enabled === null)
|
|
37
|
-
this.documents.delete(documentId);
|
|
38
|
-
else
|
|
39
|
-
this.documents.set(documentId, enabled);
|
|
40
|
-
this.changed();
|
|
41
|
-
}
|
|
42
|
-
snapshot() {
|
|
43
|
-
return { global: this.globalEnabled, tenants: Object.fromEntries(this.tenants), documents: Object.fromEntries(this.documents) };
|
|
44
|
-
}
|
|
45
|
-
subscribe(listener) { this.listeners.add(listener); return () => this.listeners.delete(listener); }
|
|
46
|
-
getVersion() { return this.version; }
|
|
47
|
-
reset() { this.globalEnabled = false; this.tenants.clear(); this.documents.clear(); this.changed(); }
|
|
48
|
-
}
|
|
49
|
-
export const canonicalAuthorityFlag = new CanonicalAuthorityFlag();
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type ClipboardDiagnosticReport } from "smartrte-core/foundation";
|
|
2
|
-
/**
|
|
3
|
-
* ROLLBACK_ADAPTER: canonical-clipboard-dom-insert; unreachable from canonical authority.
|
|
4
|
-
* Legacy rollback-only DOM insertion. The canonical product path never imports this module.
|
|
5
|
-
*/
|
|
6
|
-
export declare const insertCanonicalClipboardData: (transfer: DataTransfer, ownerDocument: Document, onDiagnostic?: (report: ClipboardDiagnosticReport) => void) => boolean;
|
|
7
|
-
export interface CanonicalClipboardRuntimeOptions {
|
|
8
|
-
ownerDocument: Document;
|
|
9
|
-
onFiles?: (files: readonly File[]) => boolean;
|
|
10
|
-
beforeInsert?: () => void;
|
|
11
|
-
afterInsert?: () => void;
|
|
12
|
-
onDiagnostic?: (report: ClipboardDiagnosticReport) => void;
|
|
13
|
-
}
|
|
14
|
-
/** Owns the product paste listener outside ClassicEditor. */
|
|
15
|
-
export declare const installCanonicalClipboardRuntime: (root: HTMLElement, options: CanonicalClipboardRuntimeOptions) => (() => void);
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { parseClipboardPayload, reportParsedClipboard, reportRejectedClipboard, serializeCanonicalListHtml, } from "smartrte-core/foundation";
|
|
2
|
-
const payloadFromTransfer = (transfer) => {
|
|
3
|
-
const representations = Object.fromEntries(Array.from(transfer.types)
|
|
4
|
-
.filter((type) => type !== "Files")
|
|
5
|
-
.map((type) => [type, transfer.getData(type)]));
|
|
6
|
-
return {
|
|
7
|
-
html: representations["text/html"], plainText: representations["text/plain"],
|
|
8
|
-
native: representations["application/x-smart-rte+json"], types: Array.from(transfer.types), representations,
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* ROLLBACK_ADAPTER: canonical-clipboard-dom-insert; unreachable from canonical authority.
|
|
13
|
-
* Legacy rollback-only DOM insertion. The canonical product path never imports this module.
|
|
14
|
-
*/
|
|
15
|
-
export const insertCanonicalClipboardData = (transfer, ownerDocument, onDiagnostic) => {
|
|
16
|
-
if (!transfer.types.length)
|
|
17
|
-
return false;
|
|
18
|
-
const payload = payloadFromTransfer(transfer);
|
|
19
|
-
try {
|
|
20
|
-
const fragment = parseClipboardPayload(payload, { ownerDocument });
|
|
21
|
-
onDiagnostic?.(reportParsedClipboard(payload, fragment));
|
|
22
|
-
const cleanHtml = serializeCanonicalListHtml(fragment.document, { clean: true });
|
|
23
|
-
if (!cleanHtml)
|
|
24
|
-
return false;
|
|
25
|
-
const selection = ownerDocument.getSelection();
|
|
26
|
-
if (!selection?.rangeCount)
|
|
27
|
-
return false;
|
|
28
|
-
const range = selection.getRangeAt(0);
|
|
29
|
-
range.deleteContents();
|
|
30
|
-
const startElement = range.startContainer.nodeType === Node.ELEMENT_NODE
|
|
31
|
-
? range.startContainer : range.startContainer.parentElement;
|
|
32
|
-
const inlineOwner = startElement?.closest("p,h1,h2,h3,h4,h5,h6,pre,li,td,th");
|
|
33
|
-
const only = fragment.document.children.length === 1 ? fragment.document.children[0] : null;
|
|
34
|
-
let insertionHtml = cleanHtml;
|
|
35
|
-
if (inlineOwner && only && only.type !== "text" && ["paragraph", "heading"].includes(only.type)) {
|
|
36
|
-
const container = ownerDocument.createElement("div");
|
|
37
|
-
container.innerHTML = cleanHtml;
|
|
38
|
-
insertionHtml = container.firstElementChild?.innerHTML || cleanHtml;
|
|
39
|
-
}
|
|
40
|
-
const fragmentNode = range.createContextualFragment(insertionHtml);
|
|
41
|
-
const last = fragmentNode.lastChild;
|
|
42
|
-
range.insertNode(fragmentNode);
|
|
43
|
-
if (last) {
|
|
44
|
-
range.setStartAfter(last);
|
|
45
|
-
range.collapse(true);
|
|
46
|
-
selection.removeAllRanges();
|
|
47
|
-
selection.addRange(range);
|
|
48
|
-
}
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
onDiagnostic?.(reportRejectedClipboard(payload, error));
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
/** Owns the product paste listener outside ClassicEditor. */
|
|
57
|
-
export const installCanonicalClipboardRuntime = (root, options) => {
|
|
58
|
-
const onPaste = (event) => {
|
|
59
|
-
const transfer = event.clipboardData;
|
|
60
|
-
if (!transfer)
|
|
61
|
-
return;
|
|
62
|
-
const files = Array.from(transfer.files || []);
|
|
63
|
-
if (files.length && options.onFiles?.(files)) {
|
|
64
|
-
event.preventDefault();
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (!transfer.types.length)
|
|
68
|
-
return;
|
|
69
|
-
event.preventDefault();
|
|
70
|
-
options.beforeInsert?.();
|
|
71
|
-
if (insertCanonicalClipboardData(transfer, options.ownerDocument, options.onDiagnostic))
|
|
72
|
-
options.afterInsert?.();
|
|
73
|
-
};
|
|
74
|
-
root.addEventListener("paste", onPaste);
|
|
75
|
-
return () => root.removeEventListener("paste", onPaste);
|
|
76
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { MediaManagerAdapter } from "./MediaManager.js";
|
|
2
|
-
import { type CoreFeatureConfig } from 'smartrte-core';
|
|
3
|
-
import { SrteTheme } from '../theme.js';
|
|
4
|
-
import { type ReactEditorPlugin } from '../pluginRuntime.js';
|
|
5
|
-
import { type EditorFormatConfig, type EditorFormatDefinition } from '../formatRuntime.js';
|
|
6
|
-
export type ClassicEditorProps = {
|
|
7
|
-
value?: string;
|
|
8
|
-
onChange?: (html: string) => void;
|
|
9
|
-
placeholder?: string;
|
|
10
|
-
minHeight?: number | string;
|
|
11
|
-
maxHeight?: number | string;
|
|
12
|
-
readOnly?: boolean;
|
|
13
|
-
table?: boolean;
|
|
14
|
-
media?: boolean;
|
|
15
|
-
formula?: boolean;
|
|
16
|
-
/** Filters the standard plugin preset. Supersedes legacy table/media/formula toggles. */
|
|
17
|
-
features?: CoreFeatureConfig;
|
|
18
|
-
/** Exact core plugin set. When provided, `features` and legacy feature toggles are ignored. */
|
|
19
|
-
plugins?: readonly ReactEditorPlugin[];
|
|
20
|
-
/** Independently enables or disables HTML, Markdown, DOCX, and PDF import/export. */
|
|
21
|
-
formats?: EditorFormatConfig;
|
|
22
|
-
/** Exact format definitions. Built-in ids may be replaced and proprietary formats may be added. */
|
|
23
|
-
formatDefinitions?: readonly EditorFormatDefinition[];
|
|
24
|
-
mediaManager?: MediaManagerAdapter;
|
|
25
|
-
/**
|
|
26
|
-
* Optional custom list of fonts to display in the toolbar.
|
|
27
|
-
* If not provided, a default set of web-safe fonts will be used.
|
|
28
|
-
* Example: [{ name: 'Robto', value: 'Roboto, sans-serif' }]
|
|
29
|
-
*/
|
|
30
|
-
fonts?: {
|
|
31
|
-
name: string;
|
|
32
|
-
value: string;
|
|
33
|
-
}[];
|
|
34
|
-
/**
|
|
35
|
-
* The default font family to apply to the editor content.
|
|
36
|
-
* This sets the font-family style of the editable area.
|
|
37
|
-
* Example: "Arial, sans-serif"
|
|
38
|
-
*/
|
|
39
|
-
defaultFont?: string;
|
|
40
|
-
/**
|
|
41
|
-
* Preserve font-family styles from pasted/imported content.
|
|
42
|
-
* Defaults to false so host applications can keep a single app font while
|
|
43
|
-
* still preserving bold, italic, headings, lists, tables, and colors.
|
|
44
|
-
*/
|
|
45
|
-
preserveFontFamily?: boolean;
|
|
46
|
-
/**
|
|
47
|
-
* Preserve foreground/background colors from pasted/imported content.
|
|
48
|
-
* Defaults to false so dark-mode editors remain readable when content is
|
|
49
|
-
* copied from sources such as Google Docs with hardcoded black-on-white styles.
|
|
50
|
-
*/
|
|
51
|
-
preserveColors?: boolean;
|
|
52
|
-
/**
|
|
53
|
-
* Preserve visual styling from imported DOCX files except font-family.
|
|
54
|
-
* This keeps Word-authored colors, spacing, borders, and table fills while
|
|
55
|
-
* still allowing the host app to control the editor font.
|
|
56
|
-
*/
|
|
57
|
-
preserveDocxStyles?: boolean;
|
|
58
|
-
/**
|
|
59
|
-
* Theme mode for the editor.
|
|
60
|
-
* - "light" (default): Uses the built-in light theme.
|
|
61
|
-
* - "dark": Uses the built-in dark theme.
|
|
62
|
-
*/
|
|
63
|
-
theme?: SrteTheme;
|
|
64
|
-
/**
|
|
65
|
-
* Show the inline font-size dropdown in the toolbar.
|
|
66
|
-
* Defaults to true. Heading block controls are independent of this option.
|
|
67
|
-
*/
|
|
68
|
-
showFontSize?: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Additional CSS class name(s) to apply to the editor's root element.
|
|
71
|
-
* Useful for custom theming by overriding CSS custom properties.
|
|
72
|
-
* Example: className="my-editor-theme"
|
|
73
|
-
*/
|
|
74
|
-
className?: string;
|
|
75
|
-
};
|
|
76
|
-
export declare function ClassicEditor({ value, onChange, placeholder, minHeight, maxHeight, readOnly, table: legacyTable, media: legacyMedia, formula: legacyFormula, features, plugins, formats, formatDefinitions, mediaManager, fonts, defaultFont, preserveFontFamily, preserveColors, preserveDocxStyles, theme, showFontSize, className, }: ClassicEditorProps): import("react/jsx-runtime").JSX.Element;
|