smartrte-react 0.3.5 → 1.0.0-beta.10
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 +55 -0
- package/README.md +205 -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 +65 -1
- package/dist/canonicalEditorRuntime.js +63 -5
- 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 +56 -1
- package/dist/components/CanonicalAuthorityEditor.js +1304 -116
- 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 +287 -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/MediaDetailsPopover.d.ts +35 -0
- package/dist/components/MediaDetailsPopover.js +136 -0
- package/dist/components/MediaManager.d.ts +4 -20
- package/dist/components/MediaManager.js +40 -11
- package/dist/components/MediaOverlay.d.ts +27 -0
- package/dist/components/MediaOverlay.js +228 -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 +149 -0
- package/dist/components/TableResizeHandles.d.ts +25 -0
- package/dist/components/TableResizeHandles.js +323 -0
- package/dist/components/TableSizePickerPopover.d.ts +16 -0
- package/dist/components/TableSizePickerPopover.js +126 -0
- package/dist/components/ToolbarPrimitives.d.ts +161 -0
- package/dist/components/ToolbarPrimitives.js +237 -0
- package/dist/components/VersionHistoryPanel.d.ts +9 -0
- package/dist/components/VersionHistoryPanel.js +157 -0
- package/dist/components/fixedPositioning.d.ts +25 -0
- package/dist/components/fixedPositioning.js +42 -0
- package/dist/formulaLibrary.d.ts +31 -0
- package/dist/formulaLibrary.js +90 -0
- package/dist/index.d.ts +25 -24
- package/dist/index.js +15 -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 +219 -30
- package/dist/toolbarTools.d.ts +95 -0
- package/dist/toolbarTools.js +17 -0
- 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,72 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* atom into the existing DOM range. Unrelated DOM and metadata stay untouched.
|
|
8
|
-
*/
|
|
9
|
-
export const executeDomInlineImageCommand = (root, input, domSelection = root.ownerDocument.defaultView?.getSelection() || null) => {
|
|
10
|
-
if (!domSelection?.rangeCount || !domSelection.isCollapsed)
|
|
11
|
-
return null;
|
|
12
|
-
const modelSelection = selectionFromDom(root, domSelection);
|
|
13
|
-
if (!modelSelection)
|
|
14
|
-
return null;
|
|
15
|
-
const { document } = smartDocumentFromEditorRoot(root);
|
|
16
|
-
const editor = createSmartEditor({
|
|
17
|
-
state: { document, selection: modelSelection },
|
|
18
|
-
plugins: [mediaPlugin],
|
|
19
|
-
});
|
|
20
|
-
if (!editor.execute("image.insert-inline", input))
|
|
21
|
-
return null;
|
|
22
|
-
const selectionAfter = editor.state.selection;
|
|
23
|
-
if (selectionAfter.type !== "text")
|
|
24
|
-
return null;
|
|
25
|
-
const imagePath = [
|
|
26
|
-
...selectionAfter.anchor.path.slice(0, -1),
|
|
27
|
-
selectionAfter.anchor.path[selectionAfter.anchor.path.length - 1] - 1,
|
|
28
|
-
];
|
|
29
|
-
const atom = getNodeAtPath(editor.state.document, imagePath);
|
|
30
|
-
if (atom?.type !== "inlineImage")
|
|
31
|
-
return null;
|
|
32
|
-
const range = domSelection.getRangeAt(0);
|
|
33
|
-
const image = root.ownerDocument.createElement("img");
|
|
34
|
-
image.src = atom.src;
|
|
35
|
-
image.alt = atom.alt || "";
|
|
36
|
-
if (atom.title)
|
|
37
|
-
image.title = atom.title;
|
|
38
|
-
if (atom.width)
|
|
39
|
-
image.width = atom.width;
|
|
40
|
-
if (atom.height)
|
|
41
|
-
image.height = atom.height;
|
|
42
|
-
image.dataset.srteInline = "true";
|
|
43
|
-
range.insertNode(image);
|
|
44
|
-
range.setStartAfter(image);
|
|
45
|
-
range.collapse(true);
|
|
46
|
-
domSelection.removeAllRanges();
|
|
47
|
-
domSelection.addRange(range);
|
|
48
|
-
return image;
|
|
49
|
-
};
|
|
50
|
-
/** Validates an inline image attribute update through core, then mutates it in place. */
|
|
51
|
-
export const executeDomInlineImageUpdate = (root, image, input) => {
|
|
52
|
-
const path = inlineAtomPathFromDom(root, image);
|
|
53
|
-
if (!path)
|
|
54
|
-
return false;
|
|
55
|
-
const selection = selectionFromDom(root, root.ownerDocument.defaultView?.getSelection() || null) || { type: "node", path };
|
|
56
|
-
const { document } = smartDocumentFromEditorRoot(root);
|
|
57
|
-
const editor = createSmartEditor({
|
|
58
|
-
state: { document, selection },
|
|
59
|
-
plugins: [mediaPlugin],
|
|
60
|
-
});
|
|
61
|
-
if (!editor.execute("image.update-inline", { path, ...input }))
|
|
62
|
-
return false;
|
|
63
|
-
if (input.alt !== undefined)
|
|
64
|
-
image.alt = input.alt;
|
|
65
|
-
if (input.title !== undefined)
|
|
66
|
-
image.title = input.title;
|
|
67
|
-
if (input.width !== undefined)
|
|
68
|
-
image.width = input.width;
|
|
69
|
-
if (input.height !== undefined)
|
|
70
|
-
image.height = input.height;
|
|
71
|
-
return true;
|
|
72
|
-
};
|
|
1
|
+
import { executeDomCanonicalAtomInsert, executeDomCanonicalAtomUpdate } from "./domInlineAtomCommandBridge.js";
|
|
2
|
+
export const executeDomInlineImageCommand = (root, input, selection = root.ownerDocument.defaultView?.getSelection() || null) => executeDomCanonicalAtomInsert(root, {
|
|
3
|
+
type: "image",
|
|
4
|
+
attrs: { src: input.src, alt: input.alt ?? "", decorative: input.decorative === true, status: input.status || "ready", ...(input.uploadId ? { uploadId: input.uploadId } : {}), ...(input.error ? { error: input.error } : {}), ...(input.title ? { title: input.title } : {}), ...(input.width ? { width: input.width } : {}), ...(input.height ? { height: input.height } : {}) },
|
|
5
|
+
}, selection);
|
|
6
|
+
export const executeDomInlineImageUpdate = (root, image, input) => executeDomCanonicalAtomUpdate(root, image, input);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSmartEditor, movePlugin } from "smartrte-core";
|
|
1
|
+
import { createSmartEditor, movePlugin } from "smartrte-core/legacy";
|
|
2
2
|
import { smartDocumentFromHtml } from "./domSmartDocument.js";
|
|
3
3
|
/**
|
|
4
4
|
* Executes model move/indent commands while preserving the existing DOM nodes.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Path,
|
|
1
|
+
import type { Path, LegacySmartSelection } from "smartrte-core/legacy";
|
|
2
2
|
export declare const isEditorOnlyElement: (node: Element) => boolean;
|
|
3
3
|
/** Returns the semantic model path for a DOM element at the adapter boundary. */
|
|
4
4
|
export declare const pathForDomElement: (element: Element, editor: HTMLElement) => Path | null;
|
|
5
5
|
/** Converts browser selection into a core selection without exposing editor UI nodes. */
|
|
6
|
-
export declare const selectionFromDom: (editor: HTMLElement, selection: Selection | null) =>
|
|
6
|
+
export declare const selectionFromDom: (editor: HTMLElement, selection: Selection | null) => LegacySmartSelection | null;
|
|
7
7
|
/** Restores a text selection from core paths after the editor DOM is rebuilt. */
|
|
8
|
-
export declare const restoreSelectionToDom: (editor: HTMLElement, smartSelection:
|
|
8
|
+
export declare const restoreSelectionToDom: (editor: HTMLElement, smartSelection: LegacySmartSelection) => boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type LegacySmartDocument } from "smartrte-core/legacy";
|
|
2
2
|
/** Removes editor UI before handing the document to the core parser boundary. */
|
|
3
3
|
export declare const cleanEditorHtml: (root: HTMLElement) => string;
|
|
4
|
-
export declare const smartDocumentFromHtml: (html: string, ownerDocument: Document) =>
|
|
4
|
+
export declare const smartDocumentFromHtml: (html: string, ownerDocument: Document) => LegacySmartDocument;
|
|
5
5
|
export declare const smartDocumentFromEditorRoot: (root: HTMLElement) => {
|
|
6
|
-
document:
|
|
6
|
+
document: LegacySmartDocument;
|
|
7
7
|
html: string;
|
|
8
8
|
};
|
|
9
9
|
/** Serializes the shadow-only model. It is not used for persisted editor HTML. */
|
|
10
|
-
export declare const serializeSmartDocument: (document:
|
|
10
|
+
export declare const serializeSmartDocument: (document: LegacySmartDocument) => string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { normalizeCompatibilityHtml, sanitizeLinkAttrs, } from "smartrte-core";
|
|
2
|
-
import { isSmartListPreset } from "smartrte-core";
|
|
1
|
+
import { normalizeCompatibilityHtml, sanitizeLinkAttrs, } from "smartrte-core/legacy";
|
|
2
|
+
import { isSmartListPreset } from "smartrte-core/legacy";
|
|
3
3
|
import { isEditorOnlyElement } from "./domSelectionBridge.js";
|
|
4
4
|
const blockTags = new Set(["p", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol", "blockquote", "pre", "table", "img", "video", "audio"]);
|
|
5
5
|
const unwrap = (element) => {
|
|
@@ -1,35 +1,61 @@
|
|
|
1
|
-
|
|
1
|
+
type Point = {
|
|
2
|
+
row: number;
|
|
3
|
+
column: number;
|
|
4
|
+
};
|
|
2
5
|
export type DomTableCommand = {
|
|
6
|
+
id: "table.remove";
|
|
7
|
+
input?: Record<string, never>;
|
|
8
|
+
} | {
|
|
3
9
|
id: "table.row.add" | "table.row.remove";
|
|
4
|
-
input:
|
|
10
|
+
input: {
|
|
11
|
+
index: number;
|
|
12
|
+
};
|
|
5
13
|
} | {
|
|
6
14
|
id: "table.column.add" | "table.column.remove";
|
|
7
|
-
input:
|
|
15
|
+
input: {
|
|
16
|
+
index: number;
|
|
17
|
+
};
|
|
8
18
|
} | {
|
|
9
19
|
id: "table.cell.merge";
|
|
10
|
-
input:
|
|
20
|
+
input: {
|
|
21
|
+
start: Point;
|
|
22
|
+
end: Point;
|
|
23
|
+
};
|
|
11
24
|
} | {
|
|
12
25
|
id: "table.cell.split";
|
|
13
|
-
input:
|
|
26
|
+
input: Point;
|
|
14
27
|
} | {
|
|
15
28
|
id: "table.header.cell.toggle" | "table.header.row.toggle" | "table.header.column.toggle";
|
|
16
|
-
input:
|
|
29
|
+
input: Point;
|
|
17
30
|
} | {
|
|
18
31
|
id: "table.cell.style.set";
|
|
19
|
-
input:
|
|
32
|
+
input: {
|
|
33
|
+
start: Point;
|
|
34
|
+
end?: Point;
|
|
35
|
+
backgroundColor?: string | null;
|
|
36
|
+
textColor?: string | null;
|
|
37
|
+
};
|
|
20
38
|
} | {
|
|
21
39
|
id: "table.column.width.set";
|
|
22
|
-
input:
|
|
40
|
+
input: {
|
|
41
|
+
index: number;
|
|
42
|
+
widthPx: number;
|
|
43
|
+
};
|
|
23
44
|
} | {
|
|
24
45
|
id: "table.row.height.set";
|
|
25
|
-
input:
|
|
46
|
+
input: {
|
|
47
|
+
index: number;
|
|
48
|
+
heightPx: number;
|
|
49
|
+
};
|
|
26
50
|
} | {
|
|
27
51
|
id: "table.cell.border.toggle";
|
|
28
|
-
input:
|
|
52
|
+
input: {
|
|
53
|
+
start: Point;
|
|
54
|
+
end?: Point;
|
|
55
|
+
visibleBorder?: string;
|
|
56
|
+
};
|
|
29
57
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export declare const executeDomTableCommand: (table: HTMLTableElement, command: DomTableCommand) => HTMLTableElement | null;
|
|
35
|
-
export declare const executeDomTableRemoval: (table: HTMLTableElement) => boolean;
|
|
58
|
+
export declare const executeDomTableCommand: (element: HTMLTableElement, command: DomTableCommand) => HTMLTableElement | null;
|
|
59
|
+
export declare const executeDomTableRemoval: (element: HTMLTableElement) => boolean;
|
|
60
|
+
export declare const executeDomTableInsert: (root: HTMLElement, afterBlockIndex: number, rows: number, columns: number, withHeader?: boolean) => HTMLTableElement | null;
|
|
61
|
+
export {};
|
|
@@ -1,201 +1,231 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { applyOperations, createNodeId, createScopeIndex, foundationSchema, insertTableColumnCommand, insertTableCommand, insertTableRowCommand, mergeTableCellsCommand, occupancyGridFor, parseCanonicalTableHtml, removeTableColumnCommand, removeTableRowCommand, removeTableCommand, repair, serializeCanonicalTableHtml, setTableCellAttributesCommand, setTableColumnWidthCommand, setTableHeaderCommand, setTableRowHeightCommand, splitTableCellCommand, } from "smartrte-core/foundation";
|
|
2
|
+
const canonicalTable = (element) => {
|
|
3
|
+
const repaired = repair(parseCanonicalTableHtml(element.outerHTML)).doc;
|
|
4
|
+
const table = repaired.children[0];
|
|
5
|
+
return table && table.type === "table" ? { document: repaired, table: table } : null;
|
|
6
|
+
};
|
|
7
|
+
const tableScope = (table, start, end = start) => {
|
|
8
|
+
const grid = occupancyGridFor(table);
|
|
9
|
+
const top = Math.max(0, Math.min(start.row, end.row));
|
|
10
|
+
const bottom = Math.min(grid.rows - 1, Math.max(start.row, end.row));
|
|
11
|
+
const left = Math.max(0, Math.min(start.column, end.column));
|
|
12
|
+
const right = Math.min(grid.columns - 1, Math.max(start.column, end.column));
|
|
13
|
+
const exclusive = { top, left, bottom: bottom + 1, right: right + 1 };
|
|
14
|
+
return {
|
|
15
|
+
kind: "table-grid", tableId: table.id, rect: { top, left, bottom, right },
|
|
16
|
+
cellIds: grid.anchors.filter((cell) => cell.top <= bottom && cell.bottom > top && cell.left <= right && cell.right > left).map((cell) => cell.cellId),
|
|
17
|
+
coveredCellIds: grid.coveredIn(exclusive).map((cell) => cell.cellId),
|
|
18
|
+
rectangular: grid.isRectangular(exclusive), range: { from: { path: [0], offset: 0 }, to: { path: [0], offset: 1 } },
|
|
19
|
+
isolatingAncestorId: null, clamped: false,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const commandContext = (document) => ({ schema: foundationSchema, positions: createScopeIndex().positions(document, foundationSchema) });
|
|
23
|
+
const generated = (count, prefix) => Array.from({ length: count }, () => `${prefix}-${createNodeId()}`);
|
|
24
|
+
const domGrid = (table) => {
|
|
25
|
+
const slots = [];
|
|
26
|
+
Array.from(table.rows).forEach((row, rowIndex) => {
|
|
27
|
+
slots[rowIndex] || (slots[rowIndex] = []);
|
|
9
28
|
let column = 0;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
while (grid[rowIndex][column])
|
|
29
|
+
Array.from(row.cells).forEach((cell) => {
|
|
30
|
+
while (slots[rowIndex][column])
|
|
13
31
|
column += 1;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
for (let columnOffset = 0; columnOffset < colspan; columnOffset += 1) {
|
|
19
|
-
grid[rowIndex + rowOffset][column + columnOffset] = cell;
|
|
20
|
-
}
|
|
32
|
+
for (let r = rowIndex; r < rowIndex + Math.max(1, cell.rowSpan); r += 1) {
|
|
33
|
+
slots[r] || (slots[r] = []);
|
|
34
|
+
for (let c = column; c < column + Math.max(1, cell.colSpan); c += 1)
|
|
35
|
+
slots[r][c] = cell;
|
|
21
36
|
}
|
|
22
|
-
column +=
|
|
37
|
+
column += Math.max(1, cell.colSpan);
|
|
23
38
|
});
|
|
24
39
|
});
|
|
25
|
-
return
|
|
40
|
+
return slots;
|
|
26
41
|
};
|
|
27
42
|
const copyVisualAttributes = (from, to) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
if (to.tagName === "TH") {
|
|
39
|
-
to.style.fontWeight = "700";
|
|
40
|
-
to.style.background = to.style.background || "#f3f4f6";
|
|
41
|
-
to.style.textAlign = to.style.textAlign || "left";
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (to.style.fontWeight === "700" || to.style.fontWeight === "bold")
|
|
45
|
-
to.style.fontWeight = "";
|
|
46
|
-
if (to.style.background === "rgb(243, 244, 246)" || to.style.background === "#f3f4f6") {
|
|
47
|
-
to.style.background = "";
|
|
48
|
-
}
|
|
43
|
+
if (from.className)
|
|
44
|
+
to.className = from.className;
|
|
45
|
+
const retained = from.getAttribute("style");
|
|
46
|
+
if (retained)
|
|
47
|
+
for (const declaration of retained.split(";")) {
|
|
48
|
+
const separator = declaration.indexOf(":");
|
|
49
|
+
if (separator > 0)
|
|
50
|
+
to.style.setProperty(declaration.slice(0, separator).trim(), declaration.slice(separator + 1).trim());
|
|
51
|
+
}
|
|
49
52
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return null;
|
|
58
|
-
const editor = createSmartEditor({
|
|
59
|
-
state: { document, selection: { type: "node", path: [0] } },
|
|
60
|
-
plugins: [tablePlugin],
|
|
61
|
-
});
|
|
62
|
-
if (!editor.execute(command.id, { ...command.input, tablePath: [0] }))
|
|
63
|
-
return null;
|
|
64
|
-
if (command.id === "table.column.width.set") {
|
|
65
|
-
let group = table.querySelector(":scope > colgroup");
|
|
53
|
+
const projectAttributesInPlace = (element, after) => {
|
|
54
|
+
const table = after.children[0];
|
|
55
|
+
const modelGrid = occupancyGridFor(table);
|
|
56
|
+
const grid = domGrid(element);
|
|
57
|
+
const widths = Array.isArray(table.attrs?.columnWidths) ? table.attrs.columnWidths : [];
|
|
58
|
+
if (widths.length) {
|
|
59
|
+
let group = element.querySelector(":scope > colgroup");
|
|
66
60
|
if (!group) {
|
|
67
|
-
group =
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
const logicalWidth = Math.max(...cellGrid(table).map((row) => row.length));
|
|
71
|
-
while (group.children.length < logicalWidth) {
|
|
72
|
-
group.appendChild(table.ownerDocument.createElement("col"));
|
|
73
|
-
}
|
|
74
|
-
const column = group.children[command.input.index];
|
|
75
|
-
if (!column)
|
|
76
|
-
return null;
|
|
77
|
-
column.style.width = `${command.input.widthPx}px`;
|
|
78
|
-
const seen = new Set();
|
|
79
|
-
cellGrid(table).forEach((row) => {
|
|
80
|
-
const target = row[command.input.index];
|
|
81
|
-
if (!target || seen.has(target))
|
|
82
|
-
return;
|
|
83
|
-
seen.add(target);
|
|
84
|
-
target.style.width = `${command.input.widthPx}px`;
|
|
85
|
-
target.style.minWidth = `${command.input.widthPx}px`;
|
|
86
|
-
target.style.maxWidth = `${command.input.widthPx}px`;
|
|
87
|
-
});
|
|
88
|
-
return table;
|
|
89
|
-
}
|
|
90
|
-
if (command.id === "table.row.height.set") {
|
|
91
|
-
const row = table.rows[command.input.index];
|
|
92
|
-
if (!row)
|
|
93
|
-
return null;
|
|
94
|
-
row.style.height = `${command.input.heightPx}px`;
|
|
95
|
-
cellsOf(row).forEach((target) => {
|
|
96
|
-
target.style.height = `${command.input.heightPx}px`;
|
|
97
|
-
});
|
|
98
|
-
return table;
|
|
99
|
-
}
|
|
100
|
-
if (command.id === "table.cell.style.set") {
|
|
101
|
-
const end = command.input.end || command.input.start;
|
|
102
|
-
const top = Math.min(command.input.start.row, end.row);
|
|
103
|
-
const bottom = Math.max(command.input.start.row, end.row);
|
|
104
|
-
const left = Math.min(command.input.start.column, end.column);
|
|
105
|
-
const right = Math.max(command.input.start.column, end.column);
|
|
106
|
-
const grid = cellGrid(table);
|
|
107
|
-
const targets = new Set();
|
|
108
|
-
for (let row = top; row <= bottom; row += 1) {
|
|
109
|
-
for (let column = left; column <= right; column += 1) {
|
|
110
|
-
const target = grid[row]?.[column];
|
|
111
|
-
if (target)
|
|
112
|
-
targets.add(target);
|
|
113
|
-
}
|
|
61
|
+
group = element.ownerDocument.createElement("colgroup");
|
|
62
|
+
element.prepend(group);
|
|
114
63
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
target.style.color = command.input.textColor || "";
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
return table;
|
|
64
|
+
while (group.children.length < widths.length)
|
|
65
|
+
group.appendChild(element.ownerDocument.createElement("col"));
|
|
66
|
+
while (group.children.length > widths.length)
|
|
67
|
+
group.lastElementChild?.remove();
|
|
68
|
+
widths.forEach((width, index) => { group.children[index].style.width = `${width}px`; });
|
|
124
69
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
70
|
+
(table.children || []).forEach((row, rowIndex) => {
|
|
71
|
+
if (row.type !== "table_row")
|
|
72
|
+
return;
|
|
73
|
+
const height = Number(row.attrs?.height);
|
|
74
|
+
if (Number.isFinite(height) && height > 0)
|
|
75
|
+
element.rows[rowIndex].style.height = `${height}px`;
|
|
76
|
+
});
|
|
77
|
+
modelGrid.anchors.forEach((cell) => {
|
|
78
|
+
const target = grid[cell.top]?.[cell.left];
|
|
79
|
+
if (!target)
|
|
80
|
+
return;
|
|
81
|
+
target.style.background = cell.node.attrs?.background ? String(cell.node.attrs.background) : "";
|
|
82
|
+
target.style.color = cell.node.attrs?.textColor ? String(cell.node.attrs.textColor) : "";
|
|
83
|
+
target.style.border = cell.node.attrs?.borders ? String(cell.node.attrs.borders) : "";
|
|
84
|
+
target.style.verticalAlign = cell.node.attrs?.verticalAlign ? String(cell.node.attrs.verticalAlign) : "";
|
|
85
|
+
if (widths.length) {
|
|
86
|
+
const width = widths.slice(cell.left, cell.right).reduce((sum, value) => sum + value, 0);
|
|
87
|
+
target.style.width = `${width}px`;
|
|
88
|
+
target.style.minWidth = `${width}px`;
|
|
89
|
+
target.style.maxWidth = `${width}px`;
|
|
139
90
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
91
|
+
const rowHeight = Number(table.children?.[cell.top]?.attrs?.height);
|
|
92
|
+
if (Number.isFinite(rowHeight) && rowHeight > 0)
|
|
93
|
+
target.style.height = `${rowHeight}px`;
|
|
94
|
+
});
|
|
95
|
+
return element;
|
|
96
|
+
};
|
|
97
|
+
const replaceDomTable = (table, document) => {
|
|
147
98
|
const container = table.ownerDocument.createElement("div");
|
|
148
|
-
container.innerHTML =
|
|
99
|
+
container.innerHTML = serializeCanonicalTableHtml(document, { fragment: true });
|
|
149
100
|
const replacement = container.querySelector("table");
|
|
150
101
|
if (!(replacement instanceof HTMLTableElement))
|
|
151
102
|
return null;
|
|
152
103
|
copyVisualAttributes(table, replacement);
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const previousPosition = (row, column) => {
|
|
156
|
-
if (command.id === "table.row.add") {
|
|
157
|
-
if (row === command.input.index)
|
|
158
|
-
return null;
|
|
159
|
-
return { row: row > command.input.index ? row - 1 : row, column };
|
|
160
|
-
}
|
|
161
|
-
if (command.id === "table.row.remove") {
|
|
162
|
-
return { row: row >= command.input.index ? row + 1 : row, column };
|
|
163
|
-
}
|
|
164
|
-
if (command.id === "table.column.add") {
|
|
165
|
-
if (column === command.input.index)
|
|
166
|
-
return null;
|
|
167
|
-
return { row, column: column > command.input.index ? column - 1 : column };
|
|
168
|
-
}
|
|
169
|
-
if (command.id === "table.column.remove") {
|
|
170
|
-
return { row, column: column >= command.input.index ? column + 1 : column };
|
|
171
|
-
}
|
|
172
|
-
return { row, column };
|
|
173
|
-
};
|
|
104
|
+
const beforeGrid = domGrid(table);
|
|
105
|
+
const afterGrid = domGrid(replacement);
|
|
174
106
|
const copied = new Set();
|
|
175
|
-
|
|
176
|
-
if (!
|
|
107
|
+
afterGrid.forEach((row, rowIndex) => row.forEach((cell, column) => {
|
|
108
|
+
if (!cell || copied.has(cell))
|
|
177
109
|
return;
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
110
|
+
const source = beforeGrid[rowIndex]?.[column];
|
|
111
|
+
if (source)
|
|
112
|
+
copyVisualAttributes(source, cell);
|
|
113
|
+
if (cell.tagName === "TH" && source?.tagName !== "TH") {
|
|
114
|
+
cell.style.fontWeight = "700";
|
|
115
|
+
cell.style.background = cell.style.background || "#f3f4f6";
|
|
116
|
+
cell.style.textAlign = cell.style.textAlign || "left";
|
|
117
|
+
}
|
|
118
|
+
else if (cell.tagName === "TD" && source?.tagName === "TH") {
|
|
119
|
+
if (["700", "bold"].includes(cell.style.fontWeight))
|
|
120
|
+
cell.style.fontWeight = "";
|
|
121
|
+
if (["rgb(243, 244, 246)", "#f3f4f6"].includes(cell.style.background))
|
|
122
|
+
cell.style.background = "";
|
|
123
|
+
if (cell.style.textAlign === "left")
|
|
124
|
+
cell.style.textAlign = "";
|
|
183
125
|
}
|
|
184
|
-
copied.add(
|
|
126
|
+
copied.add(cell);
|
|
185
127
|
}));
|
|
186
128
|
table.replaceWith(replacement);
|
|
187
129
|
return replacement;
|
|
188
130
|
};
|
|
189
|
-
export const
|
|
190
|
-
|
|
191
|
-
|
|
131
|
+
export const executeDomTableCommand = (element, command) => {
|
|
132
|
+
if (command.id === "table.remove")
|
|
133
|
+
return null;
|
|
134
|
+
const parsed = canonicalTable(element);
|
|
135
|
+
if (!parsed)
|
|
136
|
+
return null;
|
|
137
|
+
const { document, table } = parsed;
|
|
138
|
+
const grid = occupancyGridFor(table);
|
|
139
|
+
const start = "start" in command.input ? command.input.start : "row" in command.input ? command.input : { row: "index" in command.input ? command.input.index : 0, column: 0 };
|
|
140
|
+
const end = "end" in command.input && command.input.end ? command.input.end : start;
|
|
141
|
+
const scope = tableScope(table, start, end);
|
|
142
|
+
const ctx = commandContext(document);
|
|
143
|
+
let operations = [];
|
|
144
|
+
if (command.id === "table.row.add")
|
|
145
|
+
operations = insertTableRowCommand(document, scope, {
|
|
146
|
+
rowIndex: command.input.index, rowId: `row-${createNodeId()}`,
|
|
147
|
+
cellIds: generated(grid.columns, "cell"), paragraphIds: generated(grid.columns, "paragraph"),
|
|
148
|
+
}, ctx);
|
|
149
|
+
else if (command.id === "table.row.remove")
|
|
150
|
+
operations = removeTableRowCommand(document, scope, { rowIndex: command.input.index }, ctx);
|
|
151
|
+
else if (command.id === "table.column.add")
|
|
152
|
+
operations = insertTableColumnCommand(document, scope, {
|
|
153
|
+
columnIndex: command.input.index, cellIds: generated(grid.rows, "cell"), paragraphIds: generated(grid.rows, "paragraph"),
|
|
154
|
+
}, ctx);
|
|
155
|
+
else if (command.id === "table.column.remove")
|
|
156
|
+
operations = removeTableColumnCommand(document, scope, { columnIndex: command.input.index }, ctx);
|
|
157
|
+
else if (command.id === "table.cell.merge")
|
|
158
|
+
operations = mergeTableCellsCommand(document, scope, {}, ctx);
|
|
159
|
+
else if (command.id === "table.cell.split") {
|
|
160
|
+
const target = grid.at(command.input.row, command.input.column);
|
|
161
|
+
const count = target ? (target.bottom - target.top) * (target.right - target.left) - 1 : 0;
|
|
162
|
+
operations = splitTableCellCommand(document, scope, { cellIds: generated(count, "cell"), paragraphIds: generated(count, "paragraph") }, ctx);
|
|
163
|
+
}
|
|
164
|
+
else if (command.id.startsWith("table.header.")) {
|
|
165
|
+
const point = command.input;
|
|
166
|
+
const targetCells = command.id === "table.header.cell.toggle" ? [grid.at(point.row, point.column)].filter(Boolean)
|
|
167
|
+
: command.id === "table.header.row.toggle" ? grid.anchors.filter((cell) => cell.top <= point.row && cell.bottom > point.row)
|
|
168
|
+
: grid.anchors.filter((cell) => cell.left <= point.column && cell.right > point.column);
|
|
169
|
+
const makeHeader = targetCells.some((cell) => cell?.node.attrs?.header !== true);
|
|
170
|
+
if (command.id === "table.header.cell.toggle" && point.row > 0 && point.column > 0)
|
|
171
|
+
return null;
|
|
172
|
+
const headerScope = { ...scope, cellIds: targetCells.map((cell) => cell.cellId) };
|
|
173
|
+
operations = command.id === "table.header.cell.toggle"
|
|
174
|
+
? setTableCellAttributesCommand(document, headerScope, { attrs: { header: makeHeader } }, ctx)
|
|
175
|
+
: setTableHeaderCommand(document, scope, { target: makeHeader ? command.id === "table.header.row.toggle" ? "row" : "column" : "none" }, ctx);
|
|
176
|
+
}
|
|
177
|
+
else if (command.id === "table.cell.style.set")
|
|
178
|
+
operations = setTableCellAttributesCommand(document, scope, { attrs: {
|
|
179
|
+
...(command.input.backgroundColor !== undefined ? { background: command.input.backgroundColor || undefined } : {}),
|
|
180
|
+
...(command.input.textColor !== undefined ? { textColor: command.input.textColor || undefined } : {}),
|
|
181
|
+
} }, ctx);
|
|
182
|
+
else if (command.id === "table.cell.border.toggle") {
|
|
183
|
+
const visible = scope.cellIds.some((id) => grid.anchors.find((cell) => cell.cellId === id)?.node.attrs?.borders && grid.anchors.find((cell) => cell.cellId === id)?.node.attrs?.borders !== "none");
|
|
184
|
+
operations = setTableCellAttributesCommand(document, scope, { attrs: { borders: visible ? "none" : command.input.visibleBorder || "1px solid #d1d5db" } }, ctx);
|
|
185
|
+
}
|
|
186
|
+
else if (command.id === "table.column.width.set")
|
|
187
|
+
operations = setTableColumnWidthCommand(document, scope, { index: command.input.index, width: command.input.widthPx }, ctx);
|
|
188
|
+
else if (command.id === "table.row.height.set")
|
|
189
|
+
operations = setTableRowHeightCommand(document, scope, { index: command.input.index, height: command.input.heightPx }, ctx);
|
|
190
|
+
if (!operations.length)
|
|
191
|
+
return null;
|
|
192
|
+
const after = applyOperations(document, operations);
|
|
193
|
+
if (["table.cell.style.set", "table.cell.border.toggle", "table.column.width.set", "table.row.height.set"].includes(command.id)) {
|
|
194
|
+
return projectAttributesInPlace(element, after);
|
|
195
|
+
}
|
|
196
|
+
return replaceDomTable(element, after);
|
|
197
|
+
};
|
|
198
|
+
export const executeDomTableRemoval = (element) => {
|
|
199
|
+
const parsed = canonicalTable(element);
|
|
200
|
+
if (!parsed)
|
|
192
201
|
return false;
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
plugins: [tablePlugin],
|
|
196
|
-
});
|
|
197
|
-
if (!editor.execute("table.remove", { tablePath: [0] }))
|
|
202
|
+
const scope = tableScope(parsed.table, { row: 0, column: 0 });
|
|
203
|
+
if (!removeTableCommand(parsed.document, scope, {}, commandContext(parsed.document)).length)
|
|
198
204
|
return false;
|
|
199
|
-
|
|
205
|
+
element.remove();
|
|
200
206
|
return true;
|
|
201
207
|
};
|
|
208
|
+
export const executeDomTableInsert = (root, afterBlockIndex, rows, columns, withHeader = false) => {
|
|
209
|
+
if (rows < 1 || columns < 1)
|
|
210
|
+
return null;
|
|
211
|
+
const document = repair(parseCanonicalTableHtml(root.innerHTML)).doc;
|
|
212
|
+
const index = Math.max(0, Math.min(afterBlockIndex, document.children.length - 1));
|
|
213
|
+
const target = document.children[index];
|
|
214
|
+
if (!target || !("id" in target))
|
|
215
|
+
return null;
|
|
216
|
+
const blockScope = {
|
|
217
|
+
kind: "block-range", blockIds: [target.id], promotedFromPartial: false,
|
|
218
|
+
commonParentId: document.id, range: { from: { path: [], offset: index }, to: { path: [], offset: index + 1 } },
|
|
219
|
+
isolatingAncestorId: null, clamped: false,
|
|
220
|
+
};
|
|
221
|
+
const total = rows * columns;
|
|
222
|
+
const tableId = `table-${createNodeId()}`;
|
|
223
|
+
const operations = insertTableCommand(document, blockScope, {
|
|
224
|
+
rows, columns, withHeader, placement: "after",
|
|
225
|
+
ids: { tableId, rowIds: generated(rows, "row"), cellIds: generated(total, "cell"), paragraphIds: generated(total, "paragraph") },
|
|
226
|
+
}, commandContext(document));
|
|
227
|
+
if (!operations.length)
|
|
228
|
+
return null;
|
|
229
|
+
root.innerHTML = serializeCanonicalTableHtml(applyOperations(document, operations), { fragment: true });
|
|
230
|
+
return root.querySelector(`table[data-smart-id="${tableId}"]`);
|
|
231
|
+
};
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import type { CoreInlineMark } from "./inlineMarkCoreExecution.js";
|
|
2
1
|
export interface SmartRteInternalFlags {
|
|
3
|
-
coreBold?: boolean;
|
|
4
|
-
coreItalic?: boolean;
|
|
5
|
-
coreUnderline?: boolean;
|
|
6
|
-
coreSuperscript?: boolean;
|
|
7
|
-
coreSubscript?: boolean;
|
|
8
|
-
coreInlineMarks?: boolean;
|
|
9
2
|
shadowMode?: boolean;
|
|
10
3
|
}
|
|
11
4
|
export declare const getSmartRteInternalFlags: () => SmartRteInternalFlags;
|
|
12
|
-
export declare const isCoreInlineMarkFlagEnabled: (mark: CoreInlineMark) => boolean;
|
|
13
5
|
export declare const isShadowModeFlagEnabled: () => boolean;
|