smartrte-core 0.2.1 → 1.0.0-beta.1
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 +12 -0
- package/README.md +23 -0
- package/dist/command.d.ts +8 -8
- package/dist/editor.d.ts +32 -0
- package/dist/editor.js +121 -0
- package/dist/foundation/annotations/index.d.ts +2 -0
- package/dist/foundation/annotations/index.js +2 -0
- package/dist/foundation/annotations/range.d.ts +54 -0
- package/dist/foundation/annotations/range.js +158 -0
- package/dist/foundation/annotations/types.d.ts +33 -0
- package/dist/foundation/annotations/types.js +1 -0
- package/dist/foundation/atom/commands.d.ts +11 -0
- package/dist/foundation/atom/commands.js +118 -0
- package/dist/foundation/atom/composition.d.ts +8 -0
- package/dist/foundation/atom/composition.js +22 -0
- package/dist/foundation/atom/declarations.d.ts +2 -0
- package/dist/foundation/atom/declarations.js +17 -0
- package/dist/foundation/atom/formats.d.ts +21 -0
- package/dist/foundation/atom/formats.js +77 -0
- package/dist/foundation/atom/index.d.ts +10 -0
- package/dist/foundation/atom/index.js +10 -0
- package/dist/foundation/atom/lifecycle.d.ts +12 -0
- package/dist/foundation/atom/lifecycle.js +41 -0
- package/dist/foundation/atom/persistence.d.ts +3 -0
- package/dist/foundation/atom/persistence.js +20 -0
- package/dist/foundation/atom/plugin.d.ts +20 -0
- package/dist/foundation/atom/plugin.js +55 -0
- package/dist/foundation/atom/schema.d.ts +3 -0
- package/dist/foundation/atom/schema.js +29 -0
- package/dist/foundation/atom/security.d.ts +10 -0
- package/dist/foundation/atom/security.js +20 -0
- package/dist/foundation/atom/selection.d.ts +3 -0
- package/dist/foundation/atom/selection.js +4 -0
- package/dist/foundation/atom/types.d.ts +47 -0
- package/dist/foundation/atom/types.js +1 -0
- package/dist/foundation/block/commands.d.ts +17 -0
- package/dist/foundation/block/commands.js +197 -0
- package/dist/foundation/block/formats.d.ts +33 -0
- package/dist/foundation/block/formats.js +57 -0
- package/dist/foundation/block/index.d.ts +5 -0
- package/dist/foundation/block/index.js +5 -0
- package/dist/foundation/block/input.d.ts +19 -0
- package/dist/foundation/block/input.js +67 -0
- package/dist/foundation/block/plugin.d.ts +26 -0
- package/dist/foundation/block/plugin.js +79 -0
- package/dist/foundation/block/schema.d.ts +49 -0
- package/dist/foundation/block/schema.js +27 -0
- package/dist/foundation/block/types.d.ts +40 -0
- package/dist/foundation/block/types.js +1 -0
- package/dist/foundation/boundaries.d.ts +11 -0
- package/dist/foundation/boundaries.js +117 -0
- package/dist/foundation/clipboard/detection.d.ts +3 -0
- package/dist/foundation/clipboard/detection.js +29 -0
- package/dist/foundation/clipboard/diagnostics.d.ts +24 -0
- package/dist/foundation/clipboard/diagnostics.js +59 -0
- package/dist/foundation/clipboard/index.d.ts +8 -0
- package/dist/foundation/clipboard/index.js +8 -0
- package/dist/foundation/clipboard/insertion.d.ts +22 -0
- package/dist/foundation/clipboard/insertion.js +210 -0
- package/dist/foundation/clipboard/normalizers.d.ts +8 -0
- package/dist/foundation/clipboard/normalizers.js +229 -0
- package/dist/foundation/clipboard/pipeline.d.ts +13 -0
- package/dist/foundation/clipboard/pipeline.js +58 -0
- package/dist/foundation/clipboard/sanitizer.d.ts +3 -0
- package/dist/foundation/clipboard/sanitizer.js +58 -0
- package/dist/foundation/clipboard/serialization.d.ts +5 -0
- package/dist/foundation/clipboard/serialization.js +33 -0
- package/dist/foundation/clipboard/transfer.d.ts +11 -0
- package/dist/foundation/clipboard/transfer.js +108 -0
- package/dist/foundation/clipboard/types.d.ts +65 -0
- package/dist/foundation/clipboard/types.js +1 -0
- package/dist/foundation/collab/index.d.ts +3 -0
- package/dist/foundation/collab/index.js +3 -0
- package/dist/foundation/collab/rebase.d.ts +28 -0
- package/dist/foundation/collab/rebase.js +82 -0
- package/dist/foundation/collab/transform.d.ts +73 -0
- package/dist/foundation/collab/transform.js +251 -0
- package/dist/foundation/collab/types.d.ts +52 -0
- package/dist/foundation/collab/types.js +1 -0
- package/dist/foundation/comments/fromSelection.d.ts +16 -0
- package/dist/foundation/comments/fromSelection.js +24 -0
- package/dist/foundation/comments/index.d.ts +3 -0
- package/dist/foundation/comments/index.js +3 -0
- package/dist/foundation/comments/rebase.d.ts +31 -0
- package/dist/foundation/comments/rebase.js +43 -0
- package/dist/foundation/comments/types.d.ts +37 -0
- package/dist/foundation/comments/types.js +1 -0
- package/dist/foundation/diff/documentDiff.d.ts +12 -0
- package/dist/foundation/diff/documentDiff.js +148 -0
- package/dist/foundation/diff/index.d.ts +3 -0
- package/dist/foundation/diff/index.js +3 -0
- package/dist/foundation/diff/textDiff.d.ts +12 -0
- package/dist/foundation/diff/textDiff.js +114 -0
- package/dist/foundation/diff/types.d.ts +74 -0
- package/dist/foundation/diff/types.js +1 -0
- package/dist/foundation/editor.d.ts +138 -0
- package/dist/foundation/editor.js +398 -0
- package/dist/foundation/formats/codec.d.ts +45 -0
- package/dist/foundation/formats/codec.js +1 -0
- package/dist/foundation/formats/docx/export.d.ts +4 -0
- package/dist/foundation/formats/docx/export.js +285 -0
- package/dist/foundation/formats/docx/import.d.ts +9 -0
- package/dist/foundation/formats/docx/import.js +37 -0
- package/dist/foundation/formats/docx/nestingGuard.d.ts +40 -0
- package/dist/foundation/formats/docx/nestingGuard.js +66 -0
- package/dist/foundation/formats/docx/portableAtoms.d.ts +4 -0
- package/dist/foundation/formats/docx/portableAtoms.js +66 -0
- package/dist/foundation/formats/docx/styledImport.d.ts +10 -0
- package/dist/foundation/formats/docx/styledImport.js +205 -0
- package/dist/foundation/formats/featureCodecs.d.ts +37 -0
- package/dist/foundation/formats/featureCodecs.js +69 -0
- package/dist/foundation/formats/fidelity.d.ts +31 -0
- package/dist/foundation/formats/fidelity.js +123 -0
- package/dist/foundation/formats/index.d.ts +7 -0
- package/dist/foundation/formats/index.js +7 -0
- package/dist/foundation/formats/pdf/format.d.ts +29 -0
- package/dist/foundation/formats/pdf/format.js +190 -0
- package/dist/foundation/history.d.ts +20 -0
- package/dist/foundation/history.js +121 -0
- package/dist/foundation/identity.d.ts +8 -0
- package/dist/foundation/identity.js +30 -0
- package/dist/foundation/index.d.ts +30 -0
- package/dist/foundation/index.js +30 -0
- package/dist/foundation/list/commands.d.ts +28 -0
- package/dist/foundation/list/commands.js +422 -0
- package/dist/foundation/list/formats.d.ts +20 -0
- package/dist/foundation/list/formats.js +795 -0
- package/dist/foundation/list/index.d.ts +8 -0
- package/dist/foundation/list/index.js +8 -0
- package/dist/foundation/list/input.d.ts +35 -0
- package/dist/foundation/list/input.js +320 -0
- package/dist/foundation/list/plugin.d.ts +21 -0
- package/dist/foundation/list/plugin.js +71 -0
- package/dist/foundation/list/presets.d.ts +16 -0
- package/dist/foundation/list/presets.js +21 -0
- package/dist/foundation/list/schema.d.ts +35 -0
- package/dist/foundation/list/schema.js +29 -0
- package/dist/foundation/list/shadow.d.ts +54 -0
- package/dist/foundation/list/shadow.js +75 -0
- package/dist/foundation/list/shadowCorpus.d.ts +10 -0
- package/dist/foundation/list/shadowCorpus.js +41 -0
- package/dist/foundation/list/types.d.ts +50 -0
- package/dist/foundation/list/types.js +1 -0
- package/dist/foundation/mapping.d.ts +11 -0
- package/dist/foundation/mapping.js +40 -0
- package/dist/foundation/marks/canonical.d.ts +9 -0
- package/dist/foundation/marks/canonical.js +72 -0
- package/dist/foundation/marks/commands.d.ts +21 -0
- package/dist/foundation/marks/commands.js +136 -0
- package/dist/foundation/marks/dom.d.ts +2 -0
- package/dist/foundation/marks/dom.js +46 -0
- package/dist/foundation/marks/editor.d.ts +8 -0
- package/dist/foundation/marks/editor.js +50 -0
- package/dist/foundation/marks/formats.d.ts +37 -0
- package/dist/foundation/marks/formats.js +49 -0
- package/dist/foundation/marks/hardBreak.d.ts +8 -0
- package/dist/foundation/marks/hardBreak.js +80 -0
- package/dist/foundation/marks/index.d.ts +11 -0
- package/dist/foundation/marks/index.js +11 -0
- package/dist/foundation/marks/normalization.d.ts +2 -0
- package/dist/foundation/marks/normalization.js +49 -0
- package/dist/foundation/marks/plugin.d.ts +14 -0
- package/dist/foundation/marks/plugin.js +63 -0
- package/dist/foundation/marks/resolveMarkRun.d.ts +8 -0
- package/dist/foundation/marks/resolveMarkRun.js +47 -0
- package/dist/foundation/marks/schema.d.ts +167 -0
- package/dist/foundation/marks/schema.js +50 -0
- package/dist/foundation/marks/stored.d.ts +2 -0
- package/dist/foundation/marks/stored.js +31 -0
- package/dist/foundation/marks/types.d.ts +40 -0
- package/dist/foundation/marks/types.js +1 -0
- package/dist/foundation/modelDom.d.ts +38 -0
- package/dist/foundation/modelDom.js +327 -0
- package/dist/foundation/normalization.d.ts +22 -0
- package/dist/foundation/normalization.js +132 -0
- package/dist/foundation/operations.d.ts +28 -0
- package/dist/foundation/operations.js +568 -0
- package/dist/foundation/plugin/builtins.d.ts +10 -0
- package/dist/foundation/plugin/builtins.js +27 -0
- package/dist/foundation/plugin/dispatch.d.ts +33 -0
- package/dist/foundation/plugin/dispatch.js +34 -0
- package/dist/foundation/plugin/index.d.ts +4 -0
- package/dist/foundation/plugin/index.js +4 -0
- package/dist/foundation/plugin/registry.d.ts +36 -0
- package/dist/foundation/plugin/registry.js +115 -0
- package/dist/foundation/plugin/types.d.ts +141 -0
- package/dist/foundation/plugin/types.js +13 -0
- package/dist/foundation/positions.d.ts +20 -0
- package/dist/foundation/positions.js +121 -0
- package/dist/foundation/schema.d.ts +57 -0
- package/dist/foundation/schema.js +371 -0
- package/dist/foundation/schemaBuilder.d.ts +41 -0
- package/dist/foundation/schemaBuilder.js +96 -0
- package/dist/foundation/scope/index.d.ts +2 -0
- package/dist/foundation/scope/index.js +2 -0
- package/dist/foundation/scope/resolveScope.d.ts +13 -0
- package/dist/foundation/scope/resolveScope.js +860 -0
- package/dist/foundation/scope/types.d.ts +122 -0
- package/dist/foundation/scope/types.js +1 -0
- package/dist/foundation/security/urlPolicy.d.ts +21 -0
- package/dist/foundation/security/urlPolicy.js +75 -0
- package/dist/foundation/structural/contentTarget.d.ts +21 -0
- package/dist/foundation/structural/contentTarget.js +51 -0
- package/dist/foundation/structural/index.d.ts +2 -0
- package/dist/foundation/structural/index.js +2 -0
- package/dist/foundation/structural/move.d.ts +7 -0
- package/dist/foundation/structural/move.js +35 -0
- package/dist/foundation/suggestions/index.d.ts +3 -0
- package/dist/foundation/suggestions/index.js +3 -0
- package/dist/foundation/suggestions/inline.d.ts +64 -0
- package/dist/foundation/suggestions/inline.js +116 -0
- package/dist/foundation/suggestions/structural.d.ts +40 -0
- package/dist/foundation/suggestions/structural.js +47 -0
- package/dist/foundation/suggestions/types.d.ts +19 -0
- package/dist/foundation/suggestions/types.js +1 -0
- package/dist/foundation/surface/index.d.ts +3 -0
- package/dist/foundation/surface/index.js +3 -0
- package/dist/foundation/surface/input.d.ts +127 -0
- package/dist/foundation/surface/input.js +1761 -0
- package/dist/foundation/surface/renderer.d.ts +84 -0
- package/dist/foundation/surface/renderer.js +974 -0
- package/dist/foundation/surface/types.d.ts +48 -0
- package/dist/foundation/surface/types.js +1 -0
- package/dist/foundation/table/commands.d.ts +31 -0
- package/dist/foundation/table/commands.js +470 -0
- package/dist/foundation/table/formats.d.ts +26 -0
- package/dist/foundation/table/formats.js +40 -0
- package/dist/foundation/table/grid.d.ts +8 -0
- package/dist/foundation/table/grid.js +178 -0
- package/dist/foundation/table/index.d.ts +6 -0
- package/dist/foundation/table/index.js +6 -0
- package/dist/foundation/table/plugin.d.ts +23 -0
- package/dist/foundation/table/plugin.js +119 -0
- package/dist/foundation/table/schema.d.ts +2 -0
- package/dist/foundation/table/schema.js +38 -0
- package/dist/foundation/table/selection.d.ts +7 -0
- package/dist/foundation/table/selection.js +35 -0
- package/dist/foundation/table/types.d.ts +109 -0
- package/dist/foundation/table/types.js +1 -0
- package/dist/foundation/transactions.d.ts +41 -0
- package/dist/foundation/transactions.js +90 -0
- package/dist/foundation/types.d.ts +261 -0
- package/dist/foundation/types.js +1 -0
- package/dist/foundation/versioning/diffVersions.d.ts +5 -0
- package/dist/foundation/versioning/diffVersions.js +3 -0
- package/dist/foundation/versioning/index.d.ts +2 -0
- package/dist/foundation/versioning/index.js +2 -0
- package/dist/foundation/versioning/types.d.ts +17 -0
- package/dist/foundation/versioning/types.js +1 -0
- package/dist/history.d.ts +20 -0
- package/dist/history.js +165 -0
- package/dist/html/compatibility.js +7 -1
- package/dist/index.d.ts +1 -14
- package/dist/index.js +9 -14
- package/dist/legacy/index.d.ts +45 -0
- package/dist/legacy/index.js +45 -0
- package/dist/legacyCommands/alignment.d.ts +20 -0
- package/dist/{commands → legacyCommands}/alignment.js +17 -0
- package/dist/legacyCommands/blocks.d.ts +14 -0
- package/dist/legacyCommands/blocks.js +105 -0
- package/dist/legacyCommands/checklist.d.ts +11 -0
- package/dist/legacyCommands/checklist.js +45 -0
- package/dist/legacyCommands/code.d.ts +15 -0
- package/dist/{commands → legacyCommands}/code.js +25 -1
- package/dist/legacyCommands/formula.d.ts +7 -0
- package/dist/legacyCommands/formula.js +67 -0
- package/dist/legacyCommands/inlineAtoms.d.ts +7 -0
- package/dist/legacyCommands/inlineAtoms.js +58 -0
- package/dist/legacyCommands/list.d.ts +38 -0
- package/dist/legacyCommands/list.js +477 -0
- package/dist/{commands → legacyCommands}/marks.d.ts +3 -0
- package/dist/{commands → legacyCommands}/marks.js +28 -11
- package/dist/legacyCommands/media.d.ts +31 -0
- package/dist/legacyCommands/media.js +205 -0
- package/dist/legacyCommands/move.d.ts +14 -0
- package/dist/legacyCommands/move.js +91 -0
- package/dist/legacyCommands/table.d.ts +91 -0
- package/dist/legacyCommands/table.js +547 -0
- package/dist/listPresets.d.ts +12 -0
- package/dist/listPresets.js +6 -0
- package/dist/listScope.d.ts +27 -0
- package/dist/listScope.js +104 -0
- package/dist/markdown/compatibility.d.ts +2 -0
- package/dist/markdown/compatibility.js +94 -2
- package/dist/marks.d.ts +5 -5
- package/dist/model.d.ts +65 -9
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.js +31 -0
- package/dist/plugins/alignment.d.ts +3 -0
- package/dist/plugins/alignment.js +6 -0
- package/dist/plugins/basicFormatting.d.ts +9 -0
- package/dist/plugins/basicFormatting.js +24 -0
- package/dist/plugins/blockType.d.ts +3 -0
- package/dist/plugins/blockType.js +6 -0
- package/dist/plugins/blockquote.d.ts +3 -0
- package/dist/plugins/blockquote.js +6 -0
- package/dist/plugins/checklist.d.ts +3 -0
- package/dist/plugins/checklist.js +10 -0
- package/dist/plugins/codeBlock.d.ts +3 -0
- package/dist/plugins/codeBlock.js +6 -0
- package/dist/plugins/formula.d.ts +3 -0
- package/dist/plugins/formula.js +9 -0
- package/dist/plugins/list.d.ts +3 -0
- package/dist/plugins/list.js +10 -0
- package/dist/plugins/media.d.ts +3 -0
- package/dist/plugins/media.js +12 -0
- package/dist/plugins/move.d.ts +3 -0
- package/dist/plugins/move.js +9 -0
- package/dist/plugins/table.d.ts +3 -0
- package/dist/plugins/table.js +22 -0
- package/dist/preset.d.ts +12 -0
- package/dist/preset.js +40 -0
- package/dist/schema.d.ts +22 -0
- package/dist/schema.js +333 -0
- package/dist/security/urlPolicy.d.ts +1 -17
- package/dist/security/urlPolicy.js +3 -69
- package/dist/selection.d.ts +1 -1
- package/dist/selectionMapping.d.ts +4 -0
- package/dist/selectionMapping.js +222 -0
- package/dist/table.d.ts +3 -3
- package/dist/transaction.d.ts +35 -12
- package/dist/transaction.js +174 -28
- package/dist/tree.d.ts +8 -2
- package/dist/tree.js +44 -0
- package/package.json +27 -8
- package/dist/commands/alignment.d.ts +0 -18
- package/dist/commands/code.d.ts +0 -13
- package/dist/commands/list.d.ts +0 -20
- package/dist/commands/list.js +0 -52
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { getNodeAtPath, } from "../model.js";
|
|
2
|
+
import { isSmartContainer } from "../tree.js";
|
|
3
|
+
import { createDeleteInlineAtomCommand } from "./inlineAtoms.js";
|
|
4
|
+
const blockTypes = new Set([
|
|
5
|
+
"paragraph", "heading", "list", "blockquote", "codeBlock", "image", "media", "table",
|
|
6
|
+
]);
|
|
7
|
+
const isBlock = (node) => Boolean(node) && typeof node === "object" &&
|
|
8
|
+
blockTypes.has(String(node.type));
|
|
9
|
+
const canContainBlocks = (node) => {
|
|
10
|
+
const type = node?.type;
|
|
11
|
+
return type === "doc" || type === "listItem" || type === "blockquote" ||
|
|
12
|
+
type === "tableCell" || type === "tableHeaderCell";
|
|
13
|
+
};
|
|
14
|
+
const resolveInsertionPath = (context, explicit) => {
|
|
15
|
+
if (explicit) {
|
|
16
|
+
const parent = getNodeAtPath(context.document, explicit.slice(0, -1));
|
|
17
|
+
const index = explicit[explicit.length - 1];
|
|
18
|
+
return explicit.length > 0 && canContainBlocks(parent) && isSmartContainer(parent) &&
|
|
19
|
+
Number.isInteger(index) && index >= 0 && index <= parent.children.length
|
|
20
|
+
? [...explicit]
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
if (context.selection.type === "all")
|
|
24
|
+
return [context.document.children.length];
|
|
25
|
+
let path;
|
|
26
|
+
if (context.selection.type === "node")
|
|
27
|
+
path = context.selection.path;
|
|
28
|
+
if (context.selection.type === "text")
|
|
29
|
+
path = context.selection.focus.path;
|
|
30
|
+
if (context.selection.type === "cell") {
|
|
31
|
+
path = [
|
|
32
|
+
...context.selection.tablePath,
|
|
33
|
+
context.selection.start.row,
|
|
34
|
+
context.selection.start.column,
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
if (!path)
|
|
38
|
+
return null;
|
|
39
|
+
for (let length = path.length; length > 0; length -= 1) {
|
|
40
|
+
const candidatePath = path.slice(0, length);
|
|
41
|
+
if (!isBlock(getNodeAtPath(context.document, candidatePath)))
|
|
42
|
+
continue;
|
|
43
|
+
const parent = getNodeAtPath(context.document, candidatePath.slice(0, -1));
|
|
44
|
+
if (!canContainBlocks(parent))
|
|
45
|
+
continue;
|
|
46
|
+
return [
|
|
47
|
+
...candidatePath.slice(0, -1),
|
|
48
|
+
candidatePath[candidatePath.length - 1] + 1,
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
const selected = getNodeAtPath(context.document, path);
|
|
52
|
+
if (canContainBlocks(selected) && isSmartContainer(selected)) {
|
|
53
|
+
return [...path, selected.children.length];
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
const insertBlockTransaction = (context, id, path, node) => ({
|
|
58
|
+
id,
|
|
59
|
+
source: "user",
|
|
60
|
+
operations: [{ type: "insertNode", path, node }],
|
|
61
|
+
selectionBefore: context.selection,
|
|
62
|
+
selectionAfter: { type: "node", path },
|
|
63
|
+
addToHistory: true,
|
|
64
|
+
timestamp: context.now?.() ?? Date.now(),
|
|
65
|
+
});
|
|
66
|
+
const validImageInput = (input) => Boolean(input?.src.trim()) &&
|
|
67
|
+
(input?.width === undefined || Number.isFinite(input.width) && input.width > 0) &&
|
|
68
|
+
(input?.height === undefined || Number.isFinite(input.height) && input.height > 0);
|
|
69
|
+
export const insertImage = {
|
|
70
|
+
id: "image.insert",
|
|
71
|
+
isEnabled: (context, input) => validImageInput(input) && Boolean(resolveInsertionPath(context, input?.path)),
|
|
72
|
+
execute: (context, input) => {
|
|
73
|
+
const path = input && resolveInsertionPath(context, input.path);
|
|
74
|
+
if (!input || !validImageInput(input) || !path) {
|
|
75
|
+
throw new Error("image.insert requires a valid image and block insertion path.");
|
|
76
|
+
}
|
|
77
|
+
return insertBlockTransaction(context, "image.insert", path, {
|
|
78
|
+
type: "image",
|
|
79
|
+
src: input.src.trim(),
|
|
80
|
+
...(input.alt ? { alt: input.alt } : {}),
|
|
81
|
+
...(input.title ? { title: input.title } : {}),
|
|
82
|
+
...(input.width ? { width: input.width } : {}),
|
|
83
|
+
...(input.height ? { height: input.height } : {}),
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const resolveInlineImageTarget = (context) => {
|
|
88
|
+
if (context.selection.type !== "text")
|
|
89
|
+
return null;
|
|
90
|
+
const { anchor, focus } = context.selection;
|
|
91
|
+
if (anchor.offset !== focus.offset ||
|
|
92
|
+
anchor.path.length !== focus.path.length ||
|
|
93
|
+
!anchor.path.every((part, index) => focus.path[index] === part))
|
|
94
|
+
return null;
|
|
95
|
+
const node = getNodeAtPath(context.document, anchor.path);
|
|
96
|
+
const parentPath = anchor.path.slice(0, -1);
|
|
97
|
+
const parent = getNodeAtPath(context.document, parentPath);
|
|
98
|
+
if (node?.type !== "text" ||
|
|
99
|
+
!isSmartContainer(parent) ||
|
|
100
|
+
!["paragraph", "heading"].includes(String(parent.type)) ||
|
|
101
|
+
anchor.offset < 0 ||
|
|
102
|
+
anchor.offset > node.text.length)
|
|
103
|
+
return null;
|
|
104
|
+
return { node, parent, parentPath, index: anchor.path[anchor.path.length - 1], offset: anchor.offset };
|
|
105
|
+
};
|
|
106
|
+
export const insertInlineImage = {
|
|
107
|
+
id: "image.insert-inline",
|
|
108
|
+
isEnabled: (context, input) => validImageInput(input) && Boolean(resolveInlineImageTarget(context)),
|
|
109
|
+
execute: (context, input) => {
|
|
110
|
+
const target = resolveInlineImageTarget(context);
|
|
111
|
+
if (!input || !validImageInput(input) || !target) {
|
|
112
|
+
throw new Error("image.insert-inline requires a collapsed selection in paragraph or heading text.");
|
|
113
|
+
}
|
|
114
|
+
const image = {
|
|
115
|
+
type: "inlineImage",
|
|
116
|
+
src: input.src.trim(),
|
|
117
|
+
...(input.alt ? { alt: input.alt } : {}),
|
|
118
|
+
...(input.title ? { title: input.title } : {}),
|
|
119
|
+
...(input.width ? { width: input.width } : {}),
|
|
120
|
+
...(input.height ? { height: input.height } : {}),
|
|
121
|
+
};
|
|
122
|
+
const replacement = [];
|
|
123
|
+
if (target.offset > 0) {
|
|
124
|
+
replacement.push({ ...target.node, text: target.node.text.slice(0, target.offset) });
|
|
125
|
+
}
|
|
126
|
+
replacement.push(image);
|
|
127
|
+
replacement.push({ ...target.node, text: target.node.text.slice(target.offset) });
|
|
128
|
+
const imageIndex = target.index + (target.offset > 0 ? 1 : 0);
|
|
129
|
+
return {
|
|
130
|
+
id: "image.insert-inline",
|
|
131
|
+
source: "user",
|
|
132
|
+
operations: [{
|
|
133
|
+
type: "replaceNode",
|
|
134
|
+
path: target.parentPath,
|
|
135
|
+
node: {
|
|
136
|
+
...target.parent,
|
|
137
|
+
children: [
|
|
138
|
+
...target.parent.children.slice(0, target.index),
|
|
139
|
+
...replacement,
|
|
140
|
+
...target.parent.children.slice(target.index + 1),
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
}],
|
|
144
|
+
selectionBefore: context.selection,
|
|
145
|
+
selectionAfter: {
|
|
146
|
+
type: "text",
|
|
147
|
+
anchor: { path: [...target.parentPath, imageIndex + 1], offset: 0 },
|
|
148
|
+
focus: { path: [...target.parentPath, imageIndex + 1], offset: 0 },
|
|
149
|
+
},
|
|
150
|
+
addToHistory: true,
|
|
151
|
+
timestamp: context.now?.() ?? Date.now(),
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
export const deleteInlineImage = createDeleteInlineAtomCommand("image.delete-inline", "inlineImage");
|
|
156
|
+
export const updateInlineImage = {
|
|
157
|
+
id: "image.update-inline",
|
|
158
|
+
isEnabled: (context, input) => {
|
|
159
|
+
const node = input && getNodeAtPath(context.document, input.path);
|
|
160
|
+
return Boolean(node && node.type === "inlineImage" &&
|
|
161
|
+
(input?.width === undefined || Number.isFinite(input.width) && input.width > 0) &&
|
|
162
|
+
(input?.height === undefined || Number.isFinite(input.height) && input.height > 0));
|
|
163
|
+
},
|
|
164
|
+
execute: (context, input) => {
|
|
165
|
+
if (!input || !updateInlineImage.isEnabled(context, input)) {
|
|
166
|
+
throw new Error("image.update-inline requires a valid inline image path and dimensions.");
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
id: "image.update-inline",
|
|
170
|
+
source: "user",
|
|
171
|
+
operations: [{
|
|
172
|
+
type: "setNodeAttrs",
|
|
173
|
+
path: input.path,
|
|
174
|
+
attrs: {
|
|
175
|
+
alt: input.alt,
|
|
176
|
+
title: input.title,
|
|
177
|
+
width: input.width,
|
|
178
|
+
height: input.height,
|
|
179
|
+
},
|
|
180
|
+
}],
|
|
181
|
+
selectionBefore: context.selection,
|
|
182
|
+
selectionAfter: context.selection,
|
|
183
|
+
addToHistory: true,
|
|
184
|
+
timestamp: context.now?.() ?? Date.now(),
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
const validMediaInput = (input) => Boolean(input?.src.trim()) && Boolean(input && ["audio", "video", "file"].includes(input.mediaType));
|
|
189
|
+
export const insertMedia = {
|
|
190
|
+
id: "media.insert",
|
|
191
|
+
isEnabled: (context, input) => validMediaInput(input) && Boolean(resolveInsertionPath(context, input?.path)),
|
|
192
|
+
execute: (context, input) => {
|
|
193
|
+
const path = input && resolveInsertionPath(context, input.path);
|
|
194
|
+
if (!input || !validMediaInput(input) || !path) {
|
|
195
|
+
throw new Error("media.insert requires valid media and a block insertion path.");
|
|
196
|
+
}
|
|
197
|
+
return insertBlockTransaction(context, "media.insert", path, {
|
|
198
|
+
type: "media",
|
|
199
|
+
src: input.src.trim(),
|
|
200
|
+
mediaType: input.mediaType,
|
|
201
|
+
...(input.title ? { title: input.title } : {}),
|
|
202
|
+
...(input.mimeType ? { mimeType: input.mimeType } : {}),
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SmartCommand } from "../command.js";
|
|
2
|
+
import type { Path } from "../model.js";
|
|
3
|
+
export interface MoveBlocksInput {
|
|
4
|
+
parentPath: Path;
|
|
5
|
+
blockIndexes: readonly number[];
|
|
6
|
+
direction: "up" | "down";
|
|
7
|
+
}
|
|
8
|
+
export interface IndentBlocksInput {
|
|
9
|
+
parentPath: Path;
|
|
10
|
+
blockIndexes: readonly number[];
|
|
11
|
+
direction: "indent" | "outdent";
|
|
12
|
+
}
|
|
13
|
+
export declare const moveBlocks: SmartCommand<MoveBlocksInput>;
|
|
14
|
+
export declare const indentBlocks: SmartCommand<IndentBlocksInput>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { getNodeAtTreePath, isSmartContainer } from "../tree.js";
|
|
2
|
+
const normalizedIndexes = (indexes) => {
|
|
3
|
+
const result = [...new Set(indexes)].sort((left, right) => left - right);
|
|
4
|
+
if (!result.length || result.some((index) => !Number.isInteger(index) || index < 0))
|
|
5
|
+
return undefined;
|
|
6
|
+
if (result.some((index, position) => position > 0 && index !== result[position - 1] + 1))
|
|
7
|
+
return undefined;
|
|
8
|
+
return result;
|
|
9
|
+
};
|
|
10
|
+
const resolveSiblingRange = (context, parentPath, indexes) => {
|
|
11
|
+
const normalized = normalizedIndexes(indexes);
|
|
12
|
+
if (!normalized)
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
const parent = getNodeAtTreePath(context.document, parentPath);
|
|
16
|
+
if (!isSmartContainer(parent) || normalized[normalized.length - 1] >= parent.children.length)
|
|
17
|
+
return undefined;
|
|
18
|
+
return { parent, indexes: normalized };
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const moveBlocks = {
|
|
25
|
+
id: "block.move",
|
|
26
|
+
isEnabled: (context, input) => {
|
|
27
|
+
if (!input)
|
|
28
|
+
return false;
|
|
29
|
+
const range = resolveSiblingRange(context, input.parentPath, input.blockIndexes);
|
|
30
|
+
if (!range)
|
|
31
|
+
return false;
|
|
32
|
+
return input.direction === "up"
|
|
33
|
+
? range.indexes[0] > 0
|
|
34
|
+
: range.indexes[range.indexes.length - 1] < range.parent.children.length - 1;
|
|
35
|
+
},
|
|
36
|
+
execute: (context, input) => {
|
|
37
|
+
if (!input || !moveBlocks.isEnabled(context, input)) {
|
|
38
|
+
throw new Error("block.move requires a movable contiguous sibling range.");
|
|
39
|
+
}
|
|
40
|
+
const indexes = normalizedIndexes(input.blockIndexes);
|
|
41
|
+
const first = indexes[0];
|
|
42
|
+
const last = indexes[indexes.length - 1];
|
|
43
|
+
return {
|
|
44
|
+
id: "move-blocks",
|
|
45
|
+
source: "user",
|
|
46
|
+
operations: input.direction === "up"
|
|
47
|
+
? [{ type: "moveNode", from: [...input.parentPath, first - 1], to: [...input.parentPath, last + 1] }]
|
|
48
|
+
: [{ type: "moveNode", from: [...input.parentPath, last + 1], to: [...input.parentPath, first] }],
|
|
49
|
+
selectionBefore: context.selection,
|
|
50
|
+
addToHistory: true,
|
|
51
|
+
timestamp: context.now?.() ?? Date.now(),
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export const indentBlocks = {
|
|
56
|
+
id: "block.indent",
|
|
57
|
+
isEnabled: (context, input) => {
|
|
58
|
+
if (!input)
|
|
59
|
+
return false;
|
|
60
|
+
const range = resolveSiblingRange(context, input.parentPath, input.blockIndexes);
|
|
61
|
+
if (!range)
|
|
62
|
+
return false;
|
|
63
|
+
return range.indexes.some((index) => {
|
|
64
|
+
const indent = Number(range.parent.children[index].indent) || 0;
|
|
65
|
+
return input.direction === "indent" ? indent < 10 : indent > 0;
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
execute: (context, input) => {
|
|
69
|
+
if (!input || !indentBlocks.isEnabled(context, input)) {
|
|
70
|
+
throw new Error("block.indent requires a sibling range whose indentation can change.");
|
|
71
|
+
}
|
|
72
|
+
const range = resolveSiblingRange(context, input.parentPath, input.blockIndexes);
|
|
73
|
+
return {
|
|
74
|
+
id: "indent-blocks",
|
|
75
|
+
source: "user",
|
|
76
|
+
operations: range.indexes.flatMap((index) => {
|
|
77
|
+
const indent = Number(range.parent.children[index].indent) || 0;
|
|
78
|
+
const nextIndent = input.direction === "indent"
|
|
79
|
+
? Math.min(indent + 1, 10)
|
|
80
|
+
: Math.max(indent - 1, 0);
|
|
81
|
+
return nextIndent === indent
|
|
82
|
+
? []
|
|
83
|
+
: [{ type: "setNodeAttrs", path: [...input.parentPath, index], attrs: { indent: nextIndent || undefined } }];
|
|
84
|
+
}),
|
|
85
|
+
selectionBefore: context.selection,
|
|
86
|
+
selectionAfter: context.selection,
|
|
87
|
+
addToHistory: true,
|
|
88
|
+
timestamp: context.now?.() ?? Date.now(),
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { SmartCommand } from "../command.js";
|
|
2
|
+
import { type Path } from "../model.js";
|
|
3
|
+
export interface InsertTableInput {
|
|
4
|
+
path: Path;
|
|
5
|
+
rows: number;
|
|
6
|
+
columns: number;
|
|
7
|
+
headerRow?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const insertTable: SmartCommand<InsertTableInput>;
|
|
10
|
+
export interface RemoveTableInput {
|
|
11
|
+
tablePath: Path;
|
|
12
|
+
}
|
|
13
|
+
export declare const removeTable: SmartCommand<RemoveTableInput>;
|
|
14
|
+
export interface TableHeaderInput {
|
|
15
|
+
tablePath: Path;
|
|
16
|
+
row: number;
|
|
17
|
+
column: number;
|
|
18
|
+
}
|
|
19
|
+
export type TableHeaderScope = "cell" | "row" | "column";
|
|
20
|
+
export declare const toggleTableHeaderCell: SmartCommand<TableHeaderInput>;
|
|
21
|
+
export declare const toggleTableHeaderRow: SmartCommand<TableHeaderInput>;
|
|
22
|
+
export declare const toggleTableHeaderColumn: SmartCommand<TableHeaderInput>;
|
|
23
|
+
export interface SetTableCellStyleInput {
|
|
24
|
+
tablePath: Path;
|
|
25
|
+
start: {
|
|
26
|
+
row: number;
|
|
27
|
+
column: number;
|
|
28
|
+
};
|
|
29
|
+
end?: {
|
|
30
|
+
row: number;
|
|
31
|
+
column: number;
|
|
32
|
+
};
|
|
33
|
+
backgroundColor?: string | null;
|
|
34
|
+
textColor?: string | null;
|
|
35
|
+
}
|
|
36
|
+
export declare const setTableCellStyle: SmartCommand<SetTableCellStyleInput>;
|
|
37
|
+
export interface ToggleTableCellBorderInput {
|
|
38
|
+
tablePath: Path;
|
|
39
|
+
start: {
|
|
40
|
+
row: number;
|
|
41
|
+
column: number;
|
|
42
|
+
};
|
|
43
|
+
end?: {
|
|
44
|
+
row: number;
|
|
45
|
+
column: number;
|
|
46
|
+
};
|
|
47
|
+
visibleBorder?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare const toggleTableCellBorder: SmartCommand<ToggleTableCellBorderInput>;
|
|
50
|
+
export interface SetTableColumnWidthInput {
|
|
51
|
+
tablePath: Path;
|
|
52
|
+
index: number;
|
|
53
|
+
widthPx: number;
|
|
54
|
+
}
|
|
55
|
+
export declare const setTableColumnWidth: SmartCommand<SetTableColumnWidthInput>;
|
|
56
|
+
export interface SetTableRowHeightInput {
|
|
57
|
+
tablePath: Path;
|
|
58
|
+
index: number;
|
|
59
|
+
heightPx: number;
|
|
60
|
+
}
|
|
61
|
+
export declare const setTableRowHeight: SmartCommand<SetTableRowHeightInput>;
|
|
62
|
+
export interface TableRowInput {
|
|
63
|
+
tablePath: Path;
|
|
64
|
+
index: number;
|
|
65
|
+
}
|
|
66
|
+
export declare const addTableRow: SmartCommand<TableRowInput>;
|
|
67
|
+
export declare const removeTableRow: SmartCommand<TableRowInput>;
|
|
68
|
+
export interface TableColumnInput {
|
|
69
|
+
tablePath: Path;
|
|
70
|
+
index: number;
|
|
71
|
+
}
|
|
72
|
+
export declare const addTableColumn: SmartCommand<TableColumnInput>;
|
|
73
|
+
export declare const removeTableColumn: SmartCommand<TableColumnInput>;
|
|
74
|
+
export interface MergeTableCellsInput {
|
|
75
|
+
tablePath: Path;
|
|
76
|
+
start: {
|
|
77
|
+
row: number;
|
|
78
|
+
column: number;
|
|
79
|
+
};
|
|
80
|
+
end: {
|
|
81
|
+
row: number;
|
|
82
|
+
column: number;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export declare const mergeTableCells: SmartCommand<MergeTableCellsInput>;
|
|
86
|
+
export interface SplitTableCellInput {
|
|
87
|
+
tablePath: Path;
|
|
88
|
+
row: number;
|
|
89
|
+
column: number;
|
|
90
|
+
}
|
|
91
|
+
export declare const splitTableCell: SmartCommand<SplitTableCellInput>;
|