smartrte-core 0.2.0 → 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 +16 -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 +45 -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,422 @@
|
|
|
1
|
+
import { cloneNode, isTextNode } from "../identity.js";
|
|
2
|
+
import { moveContiguousSiblings } from "../structural/move.js";
|
|
3
|
+
import { isFoundationSmartListPreset } from "./presets.js";
|
|
4
|
+
const attrsOf = (node) => ({ ...(node.attrs || {}) });
|
|
5
|
+
const withAttrs = (node, attrs) => {
|
|
6
|
+
const clean = Object.fromEntries(Object.entries(attrs).filter(([, value]) => value !== undefined));
|
|
7
|
+
const { attrs: _attrs, ...rest } = node;
|
|
8
|
+
return Object.keys(clean).length ? { ...rest, attrs: clean } : rest;
|
|
9
|
+
};
|
|
10
|
+
const withChildren = (node, children) => ({ ...node, children });
|
|
11
|
+
const locate = (document, id, ctx) => {
|
|
12
|
+
const resolved = ctx.positions.positionOf(id);
|
|
13
|
+
if (!resolved)
|
|
14
|
+
throw new Error(`Unknown node ID "${id}".`);
|
|
15
|
+
const node = resolved.parent.children?.[resolved.pos.offset];
|
|
16
|
+
if (!node || isTextNode(node) || node.id !== id)
|
|
17
|
+
throw new Error(`PositionLookup returned a stale boundary for "${id}".`);
|
|
18
|
+
return { node, pos: { path: [...resolved.pos.path], offset: resolved.pos.offset } };
|
|
19
|
+
};
|
|
20
|
+
const listScopes = (scope) => {
|
|
21
|
+
if (scope.kind === "list-selection")
|
|
22
|
+
return [scope];
|
|
23
|
+
if (scope.kind !== "mixed")
|
|
24
|
+
return [];
|
|
25
|
+
const collect = (mixed) => mixed.parts.flatMap((part) => part.kind === "list-selection" ? [part] : part.kind === "mixed" ? collect(part) : []);
|
|
26
|
+
return collect(scope);
|
|
27
|
+
};
|
|
28
|
+
const blockIds = (scope) => {
|
|
29
|
+
if (scope.kind === "block-range")
|
|
30
|
+
return [...scope.blockIds];
|
|
31
|
+
if (scope.kind !== "mixed")
|
|
32
|
+
return [];
|
|
33
|
+
return scope.parts.flatMap((part) => blockIds(part));
|
|
34
|
+
};
|
|
35
|
+
const directItemIndexes = (list, scope) => {
|
|
36
|
+
const wanted = new Set(scope.items.map((entry) => entry.itemId));
|
|
37
|
+
return (list.children || []).flatMap((node, index) => !isTextNode(node) && wanted.has(node.id) ? [index] : []);
|
|
38
|
+
};
|
|
39
|
+
const contiguousRuns = (values) => {
|
|
40
|
+
const sorted = [...new Set(values)].sort((a, b) => a - b);
|
|
41
|
+
const runs = [];
|
|
42
|
+
sorted.forEach((value) => {
|
|
43
|
+
const last = runs[runs.length - 1];
|
|
44
|
+
if (last && value === last.end + 1)
|
|
45
|
+
last.end = value;
|
|
46
|
+
else
|
|
47
|
+
runs.push({ start: value, end: value });
|
|
48
|
+
});
|
|
49
|
+
return runs;
|
|
50
|
+
};
|
|
51
|
+
const replacementSequence = (before, pos, after) => {
|
|
52
|
+
if (!after.length)
|
|
53
|
+
return [{ type: "removeNode", pos, node: before }];
|
|
54
|
+
const operations = [{ type: "replaceNode", pos, before, after: after[0] }];
|
|
55
|
+
after.slice(1).forEach((node, index) => operations.push({
|
|
56
|
+
type: "insertNode",
|
|
57
|
+
pos: { path: [...pos.path], offset: pos.offset + index + 1 },
|
|
58
|
+
node,
|
|
59
|
+
}));
|
|
60
|
+
return operations;
|
|
61
|
+
};
|
|
62
|
+
const checkIds = (ids, count, label) => {
|
|
63
|
+
if (!ids || ids.length < count)
|
|
64
|
+
throw new Error(`${label} requires ${count} caller-provided deterministic node ID(s).`);
|
|
65
|
+
return ids;
|
|
66
|
+
};
|
|
67
|
+
/** How many list ancestors sit above this list — 0 for a top-level list, 1 for
|
|
68
|
+
* a list nested one level inside a list_item, and so on. Used to stamp the
|
|
69
|
+
* original nesting depth onto content unwrapped out of a list, so a later
|
|
70
|
+
* list.create over that content (and other unwrapped content) can rebuild it. */
|
|
71
|
+
const listAncestorDepth = (list, ctx) => {
|
|
72
|
+
let depth = 0;
|
|
73
|
+
let current = list;
|
|
74
|
+
for (;;) {
|
|
75
|
+
const resolved = ctx.positions.positionOf(current.id);
|
|
76
|
+
if (!resolved || resolved.parent.type !== "list_item")
|
|
77
|
+
return depth;
|
|
78
|
+
const outer = ctx.positions.positionOf(resolved.parent.id)?.parent;
|
|
79
|
+
if (!outer || outer.type !== "list")
|
|
80
|
+
return depth;
|
|
81
|
+
depth += 1;
|
|
82
|
+
current = outer;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const withDepthStamp = (node, depth) => depth <= 0 || typeof node.attrs?.indentLevel === "number" ? node : withAttrs(node, { ...attrsOf(node), indentLevel: depth });
|
|
86
|
+
/** Explicit style is the current-level override; preset supplies other levels. */
|
|
87
|
+
export const effectiveListStyle = (list) => typeof list.attrs?.style === "string" ? list.attrs.style
|
|
88
|
+
: typeof list.attrs?.preset === "string" ? list.attrs.preset
|
|
89
|
+
: undefined;
|
|
90
|
+
const withoutIndentLevel = (node) => typeof node.attrs?.indentLevel === "number" ? withAttrs(node, { ...attrsOf(node), indentLevel: undefined }) : node;
|
|
91
|
+
/** Clamps each block's indentLevel to at most one deeper than the block
|
|
92
|
+
* immediately before it (mirroring indentList's "only nest under the
|
|
93
|
+
* immediately preceding sibling" rule), so a selection built from a mix of
|
|
94
|
+
* never-nested content and content previously unwrapped out of a list
|
|
95
|
+
* (see withDepthStamp) always yields a structurally valid outline. */
|
|
96
|
+
const clampedDepths = (nodes) => {
|
|
97
|
+
let previous = -1;
|
|
98
|
+
return nodes.map((node) => {
|
|
99
|
+
const raw = Math.max(0, Number(node.attrs?.indentLevel) || 0);
|
|
100
|
+
const depth = Math.min(raw, previous + 1);
|
|
101
|
+
previous = depth;
|
|
102
|
+
return depth;
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
/** Rebuilds a run of blocks at a common depth into list_items, recursing into
|
|
106
|
+
* a nested list for any run of consecutively deeper blocks that follows one
|
|
107
|
+
* of them — the reconstruction counterpart to withDepthStamp. */
|
|
108
|
+
const buildListItems = (entries, depths, base, nextItemId, nextListId, listAttrs) => {
|
|
109
|
+
const items = [];
|
|
110
|
+
let index = 0;
|
|
111
|
+
while (index < entries.length) {
|
|
112
|
+
const entry = entries[index];
|
|
113
|
+
// Consume this item's own ID before descending into any deeper run, so
|
|
114
|
+
// IDs are assigned in document order rather than the deepest/last entry
|
|
115
|
+
// grabbing an earlier ID than an entry that appears before it.
|
|
116
|
+
const itemId = nextItemId();
|
|
117
|
+
const content = withoutIndentLevel(cloneNode(entry.node));
|
|
118
|
+
index += 1;
|
|
119
|
+
const deepStart = index;
|
|
120
|
+
while (index < entries.length && depths[index] > base)
|
|
121
|
+
index += 1;
|
|
122
|
+
const children = [content];
|
|
123
|
+
if (index > deepStart)
|
|
124
|
+
children.push({
|
|
125
|
+
type: "list",
|
|
126
|
+
id: nextListId(),
|
|
127
|
+
attrs: listAttrs,
|
|
128
|
+
children: buildListItems(entries.slice(deepStart, index), depths.slice(deepStart, index), base + 1, nextItemId, nextListId, listAttrs),
|
|
129
|
+
});
|
|
130
|
+
items.push({
|
|
131
|
+
type: "list_item",
|
|
132
|
+
id: itemId,
|
|
133
|
+
...(typeof entry.node.attrs?.htmlStyle === "string" ? { attrs: { htmlStyle: entry.node.attrs.htmlStyle } } : {}),
|
|
134
|
+
children,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return items;
|
|
138
|
+
};
|
|
139
|
+
export const createList = (document, scope, params, ctx) => {
|
|
140
|
+
if (params.preset !== undefined && !isFoundationSmartListPreset(params.preset))
|
|
141
|
+
return [];
|
|
142
|
+
const ids = blockIds(scope);
|
|
143
|
+
if (!ids.length)
|
|
144
|
+
return [];
|
|
145
|
+
const located = ids.map((id) => ({ id, ...locate(document, id, ctx) }));
|
|
146
|
+
const byParent = new Map();
|
|
147
|
+
located.forEach((entry) => {
|
|
148
|
+
const key = JSON.stringify(entry.pos.path);
|
|
149
|
+
byParent.set(key, [...(byParent.get(key) || []), entry]);
|
|
150
|
+
});
|
|
151
|
+
const groups = [...byParent.values()].flatMap((entries) => {
|
|
152
|
+
const byOffset = new Map(entries.map((entry) => [entry.pos.offset, entry]));
|
|
153
|
+
return contiguousRuns(entries.map((entry) => entry.pos.offset)).map((run) => ({
|
|
154
|
+
path: entries[0].pos.path,
|
|
155
|
+
entries: Array.from({ length: run.end - run.start + 1 }, (_, index) => byOffset.get(run.start + index)),
|
|
156
|
+
}));
|
|
157
|
+
}).sort((left, right) => right.entries[0].pos.offset - left.entries[0].pos.offset);
|
|
158
|
+
const itemIds = checkIds(params.itemIds, located.length, "list.create");
|
|
159
|
+
let itemCursor = 0;
|
|
160
|
+
let listCursor = 0;
|
|
161
|
+
// A reconstructed group may need more than one list node (one per nesting
|
|
162
|
+
// transition), which isn't known until the content's depths are read. The
|
|
163
|
+
// caller over-provisions listIds; this consumes only what's needed and
|
|
164
|
+
// fails clearly, matching indentList's per-step checkIds pattern, if it
|
|
165
|
+
// genuinely runs out.
|
|
166
|
+
const nextListId = () => checkIds(params.listIds, listCursor + 1, "list.create")[listCursor++];
|
|
167
|
+
const listAttrs = {
|
|
168
|
+
...(params.preset !== undefined ? { preset: params.preset } : {}),
|
|
169
|
+
...(params.style !== undefined ? { style: params.style } : {}),
|
|
170
|
+
...(params.start !== undefined ? { start: params.start } : {}),
|
|
171
|
+
...(params.checkable !== undefined ? { checkable: params.checkable } : {}),
|
|
172
|
+
};
|
|
173
|
+
return groups.flatMap((group) => {
|
|
174
|
+
const depths = clampedDepths(group.entries.map((entry) => entry.node));
|
|
175
|
+
const list = {
|
|
176
|
+
type: "list",
|
|
177
|
+
id: nextListId(),
|
|
178
|
+
attrs: listAttrs,
|
|
179
|
+
children: buildListItems(group.entries, depths, 0, () => itemIds[itemCursor++], nextListId, listAttrs),
|
|
180
|
+
};
|
|
181
|
+
const first = group.entries[0];
|
|
182
|
+
const operations = [{ type: "replaceNode", pos: first.pos, before: first.node, after: list }];
|
|
183
|
+
group.entries.slice(1).forEach((entry) => operations.push({
|
|
184
|
+
type: "removeNode",
|
|
185
|
+
pos: { path: [...first.pos.path], offset: first.pos.offset + 1 },
|
|
186
|
+
node: entry.node,
|
|
187
|
+
}));
|
|
188
|
+
return operations;
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
const unwrapOne = (list, selectedIndexes, splitId, depth) => {
|
|
192
|
+
if (!selectedIndexes.length)
|
|
193
|
+
return [];
|
|
194
|
+
const selected = new Set(selectedIndexes);
|
|
195
|
+
const runs = contiguousRuns(selectedIndexes);
|
|
196
|
+
if (runs.length !== 1)
|
|
197
|
+
throw new Error("list.unwrap requires one contiguous item run per list.");
|
|
198
|
+
const { start, end } = runs[0];
|
|
199
|
+
const children = list.node.children || [];
|
|
200
|
+
const beforeItems = children.slice(0, start);
|
|
201
|
+
const afterItems = children.slice(end + 1);
|
|
202
|
+
const unwrapped = children.slice(start, end + 1).flatMap((node) => {
|
|
203
|
+
if (isTextNode(node))
|
|
204
|
+
throw new Error("List children must be list items.");
|
|
205
|
+
// Unwrapping removes the list-item wrapper, not its descendants. Nested
|
|
206
|
+
// lists become sibling block content at the new level; dropping them here
|
|
207
|
+
// loses user content and leaves a later mixed-scope selection with no list
|
|
208
|
+
// part to act on. The top-level unwrapped children are stamped with the
|
|
209
|
+
// list's nesting depth so a later list.create can rebuild it; a nested
|
|
210
|
+
// list carried along unchanged still encodes its own relative depth via
|
|
211
|
+
// its own item structure, so it is left alone.
|
|
212
|
+
return (node.children || []).map((child) => {
|
|
213
|
+
const cloned = cloneNode(child);
|
|
214
|
+
return isTextNode(cloned) || cloned.type === "list" ? cloned : withDepthStamp(cloned, depth);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
const sequence = [];
|
|
218
|
+
if (beforeItems.length)
|
|
219
|
+
sequence.push(withChildren(list.node, beforeItems));
|
|
220
|
+
sequence.push(...unwrapped);
|
|
221
|
+
if (afterItems.length) {
|
|
222
|
+
const afterId = beforeItems.length ? splitId : list.node.id;
|
|
223
|
+
if (!afterId)
|
|
224
|
+
throw new Error("list.unwrap middle split requires a caller-provided splitListId.");
|
|
225
|
+
// A middle unwrap splits an ordered list into two list nodes — without
|
|
226
|
+
// this, the trailing portion silently restarts its own numbering at 1
|
|
227
|
+
// instead of continuing from where the original list left off.
|
|
228
|
+
// Harmless to set on an unordered list; `start` is simply unused there.
|
|
229
|
+
const priorStart = typeof list.node.attrs?.start === "number" ? list.node.attrs.start : 1;
|
|
230
|
+
const continuedStart = priorStart + end + 1;
|
|
231
|
+
sequence.push(withAttrs({ ...list.node, id: afterId, children: afterItems }, { ...attrsOf(list.node), start: continuedStart }));
|
|
232
|
+
}
|
|
233
|
+
if (selected.size !== end - start + 1)
|
|
234
|
+
throw new Error("Invalid selected list item indexes.");
|
|
235
|
+
return replacementSequence(list.node, list.pos, sequence);
|
|
236
|
+
};
|
|
237
|
+
export const unwrapList = (document, scope, params, ctx) => {
|
|
238
|
+
const scopes = listScopes(scope);
|
|
239
|
+
let splitCursor = 0;
|
|
240
|
+
return scopes.map((entry) => ({ entry, list: locate(document, entry.listId, ctx) }))
|
|
241
|
+
.sort((a, b) => b.list.pos.offset - a.list.pos.offset)
|
|
242
|
+
.flatMap(({ entry, list }) => {
|
|
243
|
+
const indexes = directItemIndexes(list.node, entry);
|
|
244
|
+
const middle = indexes.length && indexes[0] > 0 && indexes[indexes.length - 1] < (list.node.children?.length || 0) - 1;
|
|
245
|
+
const splitId = middle ? params.splitListIds?.[splitCursor++] : undefined;
|
|
246
|
+
return unwrapOne(list, indexes, splitId, listAncestorDepth(list.node, ctx));
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
const nestedListChild = (item) => {
|
|
250
|
+
const children = item.children || [];
|
|
251
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
252
|
+
const child = children[index];
|
|
253
|
+
if (!isTextNode(child) && child.type === "list")
|
|
254
|
+
return { node: child, index };
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
};
|
|
258
|
+
const compatibleNestedList = (parent, candidate) => {
|
|
259
|
+
const parentOrdered = /^(?:decimal|lower-|upper-|ordered)/.test(String(parent.attrs?.style || parent.attrs?.preset || ""));
|
|
260
|
+
const candidateOrdered = /^(?:decimal|lower-|upper-|ordered)/.test(String(candidate.attrs?.style || candidate.attrs?.preset || ""));
|
|
261
|
+
return parentOrdered === candidateOrdered && parent.attrs?.checkable === candidate.attrs?.checkable;
|
|
262
|
+
};
|
|
263
|
+
/** Indent is a decision about the selected line(s), not their whole subtree.
|
|
264
|
+
* A moved item's own nested list is unwrapped one level rather than carried
|
|
265
|
+
* along — its direct children become siblings of the moved item at its new
|
|
266
|
+
* position, in the same order, instead of silently ending up one level
|
|
267
|
+
* deeper than before. Only the moved item's own nested list unwraps; each
|
|
268
|
+
* hoisted child keeps whatever nested structure it independently has. */
|
|
269
|
+
const flattenMovedItem = (node) => {
|
|
270
|
+
if (isTextNode(node))
|
|
271
|
+
throw new Error("List children must be list items.");
|
|
272
|
+
const item = node;
|
|
273
|
+
const nested = nestedListChild(item);
|
|
274
|
+
if (!nested)
|
|
275
|
+
return [item];
|
|
276
|
+
const withoutNested = withChildren(item, (item.children || []).filter((_, index) => index !== nested.index));
|
|
277
|
+
const hoisted = (nested.node.children || []).filter((child) => !isTextNode(child));
|
|
278
|
+
return [withoutNested, ...hoisted];
|
|
279
|
+
};
|
|
280
|
+
export const indentList = (document, scope, params, ctx) => {
|
|
281
|
+
let idCursor = 0;
|
|
282
|
+
return listScopes(scope).flatMap((entry) => {
|
|
283
|
+
const located = locate(document, entry.listId, ctx);
|
|
284
|
+
const indexes = directItemIndexes(located.node, entry);
|
|
285
|
+
const runs = contiguousRuns(indexes);
|
|
286
|
+
if (runs.length !== 1 || runs[0].start === 0)
|
|
287
|
+
return [];
|
|
288
|
+
const { start, end } = runs[0];
|
|
289
|
+
const children = [...(located.node.children || [])];
|
|
290
|
+
const previous = children[start - 1];
|
|
291
|
+
if (!previous || isTextNode(previous))
|
|
292
|
+
throw new Error("List item predecessor is invalid.");
|
|
293
|
+
const moved = children.slice(start, end + 1).flatMap(flattenMovedItem);
|
|
294
|
+
const candidate = nestedListChild(previous);
|
|
295
|
+
const nested = candidate && compatibleNestedList(located.node, candidate.node) ? candidate : null;
|
|
296
|
+
let nextPrevious;
|
|
297
|
+
if (nested) {
|
|
298
|
+
const nextNested = withChildren(nested.node, [...(nested.node.children || []), ...moved]);
|
|
299
|
+
nextPrevious = withChildren(previous, (previous.children || []).map((child, index) => index === nested.index ? nextNested : child));
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
const nestedId = checkIds(params.nestedListIds, idCursor + 1, "list.indent")[idCursor++];
|
|
303
|
+
const nestedNode = { ...located.node, id: nestedId, children: moved };
|
|
304
|
+
nextPrevious = withChildren(previous, [...(previous.children || []), nestedNode]);
|
|
305
|
+
}
|
|
306
|
+
const nextChildren = [...children.slice(0, start - 1), nextPrevious, ...children.slice(end + 1)];
|
|
307
|
+
return [{ type: "replaceNode", pos: located.pos, before: located.node, after: withChildren(located.node, nextChildren) }];
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
export const outdentList = (document, scope, params, ctx) => {
|
|
311
|
+
let splitCursor = 0;
|
|
312
|
+
return listScopes(scope).flatMap((entry) => {
|
|
313
|
+
const nested = locate(document, entry.listId, ctx);
|
|
314
|
+
const indexes = directItemIndexes(nested.node, entry);
|
|
315
|
+
if (!indexes.length)
|
|
316
|
+
return [];
|
|
317
|
+
const parentItemResolved = ctx.positions.positionOf(nested.node.id)?.parent;
|
|
318
|
+
if (!parentItemResolved || parentItemResolved.type !== "list_item") {
|
|
319
|
+
const middle = indexes[0] > 0 && indexes[indexes.length - 1] < (nested.node.children?.length || 0) - 1;
|
|
320
|
+
return unwrapOne(nested, indexes, middle ? params.splitListIds?.[splitCursor++] : undefined, listAncestorDepth(nested.node, ctx));
|
|
321
|
+
}
|
|
322
|
+
const parentItem = parentItemResolved;
|
|
323
|
+
const parentListResolved = ctx.positions.positionOf(parentItem.id)?.parent;
|
|
324
|
+
if (!parentListResolved || parentListResolved.type !== "list")
|
|
325
|
+
throw new Error("Nested list does not belong to a parent list item.");
|
|
326
|
+
const parentList = locate(document, parentListResolved.id, ctx);
|
|
327
|
+
const parentItemIndex = (parentList.node.children || []).findIndex((child) => !isTextNode(child) && child.id === parentItem.id);
|
|
328
|
+
const selected = new Set(indexes);
|
|
329
|
+
const moved = (nested.node.children || []).filter((_, index) => selected.has(index));
|
|
330
|
+
const remaining = (nested.node.children || []).filter((_, index) => !selected.has(index));
|
|
331
|
+
const updatedParentItem = withChildren(parentItem, (parentItem.children || []).flatMap((child) => {
|
|
332
|
+
if (isTextNode(child) || child.id !== nested.node.id)
|
|
333
|
+
return [child];
|
|
334
|
+
return remaining.length ? [withChildren(nested.node, remaining)] : [];
|
|
335
|
+
}));
|
|
336
|
+
const nextParentChildren = [...(parentList.node.children || [])];
|
|
337
|
+
nextParentChildren[parentItemIndex] = updatedParentItem;
|
|
338
|
+
nextParentChildren.splice(parentItemIndex + 1, 0, ...moved);
|
|
339
|
+
return [{ type: "replaceNode", pos: parentList.pos, before: parentList.node, after: withChildren(parentList.node, nextParentChildren) }];
|
|
340
|
+
});
|
|
341
|
+
};
|
|
342
|
+
const replaceLists = (document, scope, ctx, change) => listScopes(scope).map((entry) => ({ entry, list: locate(document, entry.listId, ctx) }))
|
|
343
|
+
.map(({ entry, list }) => ({ type: "replaceNode", pos: list.pos, before: list.node, after: change(list.node, entry) }));
|
|
344
|
+
// Marker CSS is keyed on `[data-srte-list-preset][data-srte-list-depth]` on
|
|
345
|
+
// each list element individually — depth alone does not select a marker
|
|
346
|
+
// without a matching preset on that same nested list. A style/preset change
|
|
347
|
+
// must therefore cascade into every nested list, not just the selected one,
|
|
348
|
+
// or descendant items keep rendering their old marker family.
|
|
349
|
+
const withNestedListsRestyled = (list, restyle) => withChildren(restyle(list), (list.children || []).map((item) => {
|
|
350
|
+
if (isTextNode(item) || item.type !== "list_item")
|
|
351
|
+
return item;
|
|
352
|
+
return withChildren(item, (item.children || []).map((child) => !isTextNode(child) && child.type === "list" ? withNestedListsRestyled(child, restyle) : child));
|
|
353
|
+
}));
|
|
354
|
+
export const setListPreset = (document, scope, params, ctx) => (params.preset !== undefined && !isFoundationSmartListPreset(params.preset)
|
|
355
|
+
? []
|
|
356
|
+
: replaceLists(document, scope, ctx, (list) => withNestedListsRestyled(list, (nested) => withAttrs(nested, { ...attrsOf(nested), preset: params.preset, style: undefined }))));
|
|
357
|
+
export const setListStyle = (document, scope, params, ctx) => replaceLists(document, scope, ctx, (list) => {
|
|
358
|
+
// A concrete style is a state transition, not an additional marker. A
|
|
359
|
+
// stale preset makes serializers and CSS consumers see two competing list
|
|
360
|
+
// definitions after numbered → bulleted/checklist changes. Style/preset
|
|
361
|
+
// cascade to nested lists (see withNestedListsRestyled); `checkable` does
|
|
362
|
+
// not — converting an outer list to a checklist should not silently make
|
|
363
|
+
// every nested sublist checkable too.
|
|
364
|
+
const restyled = withNestedListsRestyled(list, (nested) => withAttrs(nested, { ...attrsOf(nested), preset: undefined, style: params.style }));
|
|
365
|
+
return params.checkable !== undefined ? withAttrs(restyled, { ...attrsOf(restyled), checkable: params.checkable }) : restyled;
|
|
366
|
+
});
|
|
367
|
+
export const setListChecked = (document, scope, params, ctx) => replaceLists(document, scope, ctx, (list, entry) => {
|
|
368
|
+
if (list.attrs?.checkable !== true)
|
|
369
|
+
return list;
|
|
370
|
+
const selected = new Set(entry.items.map((item) => item.itemId));
|
|
371
|
+
return withChildren(list, (list.children || []).map((item) => {
|
|
372
|
+
if (isTextNode(item) || !selected.has(item.id))
|
|
373
|
+
return item;
|
|
374
|
+
return withAttrs(item, { ...attrsOf(item), checked: params.checked });
|
|
375
|
+
}));
|
|
376
|
+
});
|
|
377
|
+
/** Moves one contiguous item run by one sibling while preserving every item subtree and ID. */
|
|
378
|
+
export const moveListItems = (_document, scope, params, ctx) => listScopes(scope).flatMap((entry) => moveContiguousSiblings(entry.items.map((item) => item.itemId), params.direction, ctx));
|
|
379
|
+
export const restartListNumbering = (document, scope, params, ctx) => {
|
|
380
|
+
if (!Number.isInteger(params.start) || params.start < 1)
|
|
381
|
+
throw new Error("list.restartNumbering requires a positive integer.");
|
|
382
|
+
return replaceLists(document, scope, ctx, (list) => withAttrs(list, { ...attrsOf(list), start: params.start }));
|
|
383
|
+
};
|
|
384
|
+
export const continueListNumbering = (document, scope, _params, ctx) => replaceLists(document, scope, ctx, (list) => withAttrs(list, { ...attrsOf(list), start: undefined }));
|
|
385
|
+
export const insertListFragment = (document, scope, params, ctx) => {
|
|
386
|
+
const targetScope = listScopes(scope)[0];
|
|
387
|
+
if (!targetScope)
|
|
388
|
+
return [];
|
|
389
|
+
const located = locate(document, targetScope.listId, ctx);
|
|
390
|
+
const direct = directItemIndexes(located.node, targetScope);
|
|
391
|
+
if (!direct.length && params.position !== "start" && params.position !== "end")
|
|
392
|
+
return [];
|
|
393
|
+
const fragmentNodes = params.fragment.children.flatMap((node) => {
|
|
394
|
+
if (!isTextNode(node) && node.type === "list")
|
|
395
|
+
return (node.children || []).map(cloneNode);
|
|
396
|
+
return [cloneNode(node)];
|
|
397
|
+
});
|
|
398
|
+
const plainCount = fragmentNodes.filter((node) => isTextNode(node) || node.type !== "list_item").length;
|
|
399
|
+
const itemIds = plainCount ? checkIds(params.itemIds, plainCount, "list fragment insertion") : [];
|
|
400
|
+
let itemCursor = 0;
|
|
401
|
+
const items = fragmentNodes.map((node) => !isTextNode(node) && node.type === "list_item" ? node : ({
|
|
402
|
+
type: "list_item", id: itemIds[itemCursor++], children: [node],
|
|
403
|
+
}));
|
|
404
|
+
const insertionIndex = params.position === "start" ? 0
|
|
405
|
+
: params.position === "end" ? (located.node.children?.length || 0)
|
|
406
|
+
: params.position === "before" ? direct[0] : direct[direct.length - 1] + 1;
|
|
407
|
+
const children = [...(located.node.children || [])];
|
|
408
|
+
children.splice(insertionIndex, 0, ...items);
|
|
409
|
+
return [{ type: "replaceNode", pos: located.pos, before: located.node, after: withChildren(located.node, children) }];
|
|
410
|
+
};
|
|
411
|
+
export const listCommands = {
|
|
412
|
+
"list.create": createList,
|
|
413
|
+
"list.unwrap": unwrapList,
|
|
414
|
+
"list.indent": indentList,
|
|
415
|
+
"list.outdent": outdentList,
|
|
416
|
+
"list.setPreset": setListPreset,
|
|
417
|
+
"list.setStyle": setListStyle,
|
|
418
|
+
"list.setChecked": setListChecked,
|
|
419
|
+
"list.move": moveListItems,
|
|
420
|
+
"list.restartNumbering": restartListNumbering,
|
|
421
|
+
"list.continueNumbering": continueListNumbering,
|
|
422
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SmartDocument } from "../types.js";
|
|
2
|
+
export declare const serializeCanonicalListHtml: (document: SmartDocument, options?: {
|
|
3
|
+
clean?: boolean;
|
|
4
|
+
fragment?: boolean;
|
|
5
|
+
}) => string;
|
|
6
|
+
export declare const parseCanonicalListHtml: (html: string) => SmartDocument;
|
|
7
|
+
/** Alignment and indent are unsupported in Markdown; block content survives semantically. */
|
|
8
|
+
export declare const serializeCanonicalListMarkdown: (document: SmartDocument) => string;
|
|
9
|
+
export declare const parseCanonicalListMarkdown: (markdown: string) => SmartDocument;
|
|
10
|
+
export interface CanonicalDocxNumberingEntry {
|
|
11
|
+
readonly itemId: string;
|
|
12
|
+
readonly numId: number;
|
|
13
|
+
readonly ilvl: number;
|
|
14
|
+
readonly marker: "bullet" | "decimal";
|
|
15
|
+
readonly text: string;
|
|
16
|
+
readonly checked?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** DOCX has numId/ilvl but no Smart preset identity; presets fall back semantically. */
|
|
19
|
+
export declare const canonicalListToDocxNumbering: (document: SmartDocument) => CanonicalDocxNumberingEntry[];
|
|
20
|
+
export declare const canonicalListPdfText: (document: SmartDocument) => string;
|