@stll/folio-core 0.55.0 → 0.56.0
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/dist/ai-edits/apply.js +169 -38
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +476 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComposition.d.ts +20 -3
- package/dist/controller/canonicalComposition.js +166 -38
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +52 -13
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalSession.d.ts +24 -6
- package/dist/controller/canonicalSession.js +259 -111
- package/dist/controller/canonicalStoryEditor.d.ts +5 -3
- package/dist/controller/canonicalStoryEditor.js +7 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +5 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +8 -7
- package/dist/controller/hiddenEditorApi.d.ts +12 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +216 -34
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +8 -7
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphPropertySource.js +2 -1
- package/dist/docx/parser.js +2 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +745 -229
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +32 -3
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +32 -13
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +5 -4
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +39 -30
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/markUtils.js +3 -1
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +7 -5
- package/dist/types/canonicalCapabilities.d.ts +215 -0
- package/dist/types/canonicalCapabilities.js +212 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/package.json +4 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CanonicalGap } from "../types/canonicalCapabilities.js";
|
|
1
2
|
import { HiddenEditorApi } from "./hiddenEditorApi.js";
|
|
2
3
|
import { Transaction } from "prosemirror-state";
|
|
3
4
|
import { EditorView } from "prosemirror-view";
|
|
@@ -9,7 +10,7 @@ type CanonicalStoryEditorOptions = {
|
|
|
9
10
|
getApi: () => HiddenEditorApi | null;
|
|
10
11
|
enabled: () => boolean;
|
|
11
12
|
onSelectionChange: () => void;
|
|
12
|
-
onRefusal: ((reason: string) => void) | undefined;
|
|
13
|
+
onRefusal: ((reason: string, gap: CanonicalGap) => void) | undefined;
|
|
13
14
|
};
|
|
14
15
|
/** Secondary views compile classified native input into the shared Document journal. */
|
|
15
16
|
declare const createCanonicalStoryEditor: ({ story, getView, getApi, enabled, onRefusal, onSelectionChange }: CanonicalStoryEditorOptions) => {
|
|
@@ -18,14 +19,15 @@ declare const createCanonicalStoryEditor: ({ story, getView, getApi, enabled, on
|
|
|
18
19
|
handleKeyDown: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
19
20
|
handleTextInput: (view: EditorView, from: number, to: number, text: string) => boolean;
|
|
20
21
|
handleDOMEvents: {
|
|
22
|
+
keydown: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
21
23
|
beforeinput: (view: EditorView, event: InputEvent) => boolean;
|
|
22
24
|
mousedown: (view: EditorView) => boolean;
|
|
23
25
|
compositionstart: (view: EditorView) => boolean;
|
|
24
26
|
compositionend: (view: EditorView) => boolean;
|
|
25
27
|
input: (view: EditorView) => boolean;
|
|
26
28
|
blur: (view: EditorView) => boolean;
|
|
27
|
-
paste: (view: EditorView, event:
|
|
28
|
-
cut: (view: EditorView, event:
|
|
29
|
+
paste: (view: EditorView, event: ClipboardEvent) => boolean;
|
|
30
|
+
cut: (view: EditorView, event: ClipboardEvent) => boolean;
|
|
29
31
|
drop: (view: EditorView, event: Event) => boolean;
|
|
30
32
|
};
|
|
31
33
|
};
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
1
2
|
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
2
3
|
import { CanonicalSessionError } from "./canonicalSession.js";
|
|
3
4
|
//#region src/controller/canonicalStoryEditor.ts
|
|
4
5
|
/** Secondary views compile classified native input into the shared Document journal. */
|
|
5
6
|
const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal, onSelectionChange }) => {
|
|
6
|
-
const refuse = (
|
|
7
|
-
|
|
7
|
+
const refuse = (reason) => {
|
|
8
|
+
const gap = CANONICAL_GAP.dispatch;
|
|
9
|
+
const message = reason;
|
|
10
|
+
if (onRefusal) onRefusal(message, gap);
|
|
8
11
|
else throw new CanonicalSessionError({
|
|
12
|
+
gap,
|
|
9
13
|
message,
|
|
10
14
|
reason: "refused"
|
|
11
15
|
});
|
|
@@ -65,6 +69,7 @@ const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal
|
|
|
65
69
|
handleKeyDown: (view, event) => enabled() && boundary.handleKeyDown(view, event),
|
|
66
70
|
handleTextInput: (view, from, to, text) => enabled() && boundary.handleTextInput(view, from, to, text),
|
|
67
71
|
handleDOMEvents: {
|
|
72
|
+
keydown: (view, event) => enabled() && boundary.handleDOMEvents.keydown(view, event),
|
|
68
73
|
beforeinput: (view, event) => enabled() && boundary.handleDOMEvents.beforeinput(view, event),
|
|
69
74
|
mousedown: (view) => enabled() && boundary.handleDOMEvents.mousedown(view),
|
|
70
75
|
compositionstart: (view) => enabled() && boundary.handleDOMEvents.compositionstart(view),
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
import { BUILT_IN_STYLE_NAME, createBuiltInStyleIndex } from "../docx/builtInStyles.js";
|
|
1
2
|
import { getCachedNumberingMap, numberingLevelUsesBulletMarker } from "../docx/numberingParser.js";
|
|
2
3
|
import { listRequestsForMarker } from "../prosemirror/listAutoformatMarkers.js";
|
|
4
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
5
|
+
import { collectHeadings } from "../utils/headingCollector.js";
|
|
3
6
|
import { CanonicalSessionError } from "./canonicalSession.js";
|
|
4
7
|
import { Result } from "better-result";
|
|
5
|
-
import { paragraphNumberingReference } from "@stll/docx-core/model";
|
|
8
|
+
import { headingOutlineLevel, paragraphNumberingReference } from "@stll/docx-core/model";
|
|
6
9
|
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
7
10
|
//#region src/controller/canonicalStructure.ts
|
|
11
|
+
const DEFAULT_TOC_PAGE_WIDTH_TWIPS = 12240;
|
|
12
|
+
const DEFAULT_TOC_MARGIN_TWIPS = 1440;
|
|
8
13
|
const refuse = (message) => Result.err(new CanonicalSessionError({
|
|
14
|
+
gap: CANONICAL_GAP.commands,
|
|
9
15
|
message,
|
|
10
16
|
reason: "refused"
|
|
11
17
|
}));
|
|
@@ -84,6 +90,53 @@ const prepareCanonicalCommands = (session, state, commands) => {
|
|
|
84
90
|
const intents = [];
|
|
85
91
|
const paragraphs = selectedParagraphs(session, state);
|
|
86
92
|
for (const command of commands) switch (command.type) {
|
|
93
|
+
case "generateTOC": {
|
|
94
|
+
const at = session.projection.addressAt(command.at);
|
|
95
|
+
if (at.isErr()) return at;
|
|
96
|
+
const definitions = session.document.package.styles;
|
|
97
|
+
const styles = createBuiltInStyleIndex(definitions?.styles ?? [], definitions?.docDefaults);
|
|
98
|
+
const headings = [];
|
|
99
|
+
for (const heading of collectHeadings(session.projection.doc, styles)) {
|
|
100
|
+
const address = session.projection.addressAt(heading.pmPos + 1);
|
|
101
|
+
if (address.isErr()) return address;
|
|
102
|
+
const outline = headingOutlineLevel(heading.level);
|
|
103
|
+
if (outline?.kind !== "heading") return refuse("A TOC heading has an invalid outline level.");
|
|
104
|
+
const styleId = styles.styleIdForTableOfContentsLevel(outline.level + 1);
|
|
105
|
+
headings.push({
|
|
106
|
+
blockId: address.value.blockId,
|
|
107
|
+
text: heading.text,
|
|
108
|
+
level: outline.level,
|
|
109
|
+
...styleId === void 0 ? {} : { styleId }
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (headings.length === 0) break;
|
|
113
|
+
const titleStyleId = styles.styleIdForBuiltInName(BUILT_IN_STYLE_NAME.tocHeading);
|
|
114
|
+
const section = session.document.package.document.content.find((item) => item.type === "paragraph" && (item.sectionProperties?.pageWidth ?? 0) > 0);
|
|
115
|
+
const properties = section?.type === "paragraph" ? section.sectionProperties : void 0;
|
|
116
|
+
intents.push({
|
|
117
|
+
type: "generateTOC",
|
|
118
|
+
at: at.value,
|
|
119
|
+
title: command.title,
|
|
120
|
+
headings,
|
|
121
|
+
tabPosition: (properties?.pageWidth ?? DEFAULT_TOC_PAGE_WIDTH_TWIPS) - (properties?.marginLeft ?? DEFAULT_TOC_MARGIN_TWIPS) - (properties?.marginRight ?? DEFAULT_TOC_MARGIN_TWIPS),
|
|
122
|
+
...titleStyleId === void 0 ? {} : { titleStyleId }
|
|
123
|
+
});
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case "setHyperlink":
|
|
127
|
+
case "removeHyperlink":
|
|
128
|
+
case "insertHyperlink": {
|
|
129
|
+
const from = session.projection.addressAt(command.from);
|
|
130
|
+
if (from.isErr()) return from;
|
|
131
|
+
const to = session.projection.addressAt(command.to);
|
|
132
|
+
if (to.isErr()) return to;
|
|
133
|
+
intents.push({
|
|
134
|
+
...command,
|
|
135
|
+
from: from.value,
|
|
136
|
+
to: to.value
|
|
137
|
+
});
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
87
140
|
case "insertBreak": {
|
|
88
141
|
const from = session.projection.addressAt(command.from);
|
|
89
142
|
if (from.isErr()) return from;
|
|
@@ -233,7 +286,7 @@ const prepareCanonicalCommands = (session, state, commands) => {
|
|
|
233
286
|
}
|
|
234
287
|
default: return command;
|
|
235
288
|
}
|
|
236
|
-
return session.prepareIntents(state, intents);
|
|
289
|
+
return session.prepareIntents(state, { intents });
|
|
237
290
|
};
|
|
238
291
|
/** Rules compile their replacement and paragraph change as one atomic edit. */
|
|
239
292
|
const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
|
|
@@ -254,7 +307,7 @@ const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
|
|
|
254
307
|
const request = requests?.at(0);
|
|
255
308
|
const styleId = `Heading${heading?.length ?? 1}`;
|
|
256
309
|
if (request === void 0 && !session.hasStyle(styleId)) return void 0;
|
|
257
|
-
return session.prepareIntents(state, [{
|
|
310
|
+
return session.prepareIntents(state, { intents: [{
|
|
258
311
|
type: "replaceText",
|
|
259
312
|
from: start,
|
|
260
313
|
to: at.value,
|
|
@@ -263,7 +316,7 @@ const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
|
|
|
263
316
|
type: "formatParagraph",
|
|
264
317
|
at: start,
|
|
265
318
|
patch: { styleId }
|
|
266
|
-
} : numberingIntent(session, [source], request)]);
|
|
319
|
+
} : numberingIntent(session, [source], request)] });
|
|
267
320
|
};
|
|
268
321
|
//#endregion
|
|
269
322
|
export { prepareCanonicalAutoformat, prepareCanonicalCommands };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DocumentOp, TextPosition } from "@stll/docx-core/ops";
|
|
2
|
+
//#region src/controller/canonicalTocSelection.d.ts
|
|
3
|
+
type TocSelectionMapping = {
|
|
4
|
+
at: TextPosition;
|
|
5
|
+
after: TextPosition;
|
|
6
|
+
ops: readonly DocumentOp[];
|
|
7
|
+
};
|
|
8
|
+
/** TOC insertion retains the selected text and maps its endpoints through the canonical split. */
|
|
9
|
+
declare const mapTocSelection: (point: TextPosition, { at, after, ops }: TocSelectionMapping) => TextPosition;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { mapTocSelection };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { panic } from "better-result";
|
|
2
|
+
import { DOCUMENT_OP_TYPES, SPLIT_HALVES, compareGaps, idKey, mapTocBookmarkPosition, sameStory } from "@stll/docx-core/ops";
|
|
3
|
+
//#region src/controller/canonicalTocSelection.ts
|
|
4
|
+
/** TOC insertion retains the selected text and maps its endpoints through the canonical split. */
|
|
5
|
+
const mapTocSelection = (point, { at, after, ops }) => {
|
|
6
|
+
if (!sameStory(point.story, at.story)) return point;
|
|
7
|
+
point = mapTocBookmarkPosition({
|
|
8
|
+
...point,
|
|
9
|
+
zeroWidthBefore: point.zeroWidthBefore ?? 0
|
|
10
|
+
}, ops);
|
|
11
|
+
at = mapTocBookmarkPosition({
|
|
12
|
+
...at,
|
|
13
|
+
zeroWidthBefore: at.zeroWidthBefore ?? 0
|
|
14
|
+
}, ops);
|
|
15
|
+
if (idKey(point.blockId) !== idKey(at.blockId)) return point;
|
|
16
|
+
const split = ops.find((op) => op.type === DOCUMENT_OP_TYPES.SPLIT_BLOCK);
|
|
17
|
+
if (split === void 0) return point;
|
|
18
|
+
if (point.offset === at.offset && (point.zeroWidthBefore ?? 0) === (at.zeroWidthBefore ?? 0)) return after;
|
|
19
|
+
if (split.type !== DOCUMENT_OP_TYPES.SPLIT_BLOCK || split.newHalf !== SPLIT_HALVES.FIRST) return panic("TOC insertion must retain its following paragraph identity.");
|
|
20
|
+
const pointGap = {
|
|
21
|
+
offset: point.offset,
|
|
22
|
+
zeroWidthBefore: point.zeroWidthBefore ?? 0
|
|
23
|
+
};
|
|
24
|
+
const splitGap = {
|
|
25
|
+
offset: split.at.offset,
|
|
26
|
+
zeroWidthBefore: split.at.zeroWidthBefore ?? 0
|
|
27
|
+
};
|
|
28
|
+
if (compareGaps(pointGap, splitGap) < 0) return {
|
|
29
|
+
...point,
|
|
30
|
+
blockId: split.newBlockId
|
|
31
|
+
};
|
|
32
|
+
if (point.offset === split.at.offset) return {
|
|
33
|
+
...point,
|
|
34
|
+
offset: 0,
|
|
35
|
+
zeroWidthBefore: pointGap.zeroWidthBefore - splitGap.zeroWidthBefore
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
...point,
|
|
39
|
+
offset: point.offset - split.at.offset
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { mapTocSelection };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { DocxInput } from "../utils/docxInput.js";
|
|
3
|
+
import { FOLIO_DOCX_SERIALIZATION_MODE, FolioDocxSerializationMode, FolioGetDocxOptions } from "../types/docxSerialization.js";
|
|
3
4
|
import { Layout } from "../layout-engine/types.js";
|
|
4
5
|
import { FolioEditorEmitter } from "./folioEditorEvents.js";
|
|
5
6
|
import { HiddenEditorApi } from "./hiddenEditorApi.js";
|
|
@@ -14,14 +15,6 @@ type FolioEditorDeps = {
|
|
|
14
15
|
getDocumentIO?: () => FolioEditorDocumentIO;
|
|
15
16
|
emitter: FolioEditorEmitter;
|
|
16
17
|
};
|
|
17
|
-
declare const FOLIO_DOCX_SERIALIZATION_MODE: Readonly<{
|
|
18
|
-
readonly full: "full";
|
|
19
|
-
readonly preferSelective: "prefer-selective";
|
|
20
|
-
}>;
|
|
21
|
-
type FolioDocxSerializationMode = (typeof FOLIO_DOCX_SERIALIZATION_MODE)[keyof typeof FOLIO_DOCX_SERIALIZATION_MODE];
|
|
22
|
-
type FolioGetDocxOptions = {
|
|
23
|
-
mode?: FolioDocxSerializationMode;
|
|
24
|
-
};
|
|
25
18
|
/**
|
|
26
19
|
* Document lifecycle operations supplied by a host integration.
|
|
27
20
|
*
|
|
@@ -45,4 +38,4 @@ type FolioEditor = HiddenEditorApi & {
|
|
|
45
38
|
};
|
|
46
39
|
declare const createFolioEditor: (deps: FolioEditorDeps) => FolioEditor;
|
|
47
40
|
//#endregion
|
|
48
|
-
export { FOLIO_DOCX_SERIALIZATION_MODE, FolioDocxSerializationMode, FolioEditor, FolioEditorDeps, FolioEditorDocumentIO, FolioGetDocxOptions, createFolioEditor };
|
|
41
|
+
export { FOLIO_DOCX_SERIALIZATION_MODE, type FolioDocxSerializationMode, FolioEditor, FolioEditorDeps, FolioEditorDocumentIO, type FolioGetDocxOptions, createFolioEditor };
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { FOLIO_DOCX_SERIALIZATION_MODE } from "../types/docxSerialization.js";
|
|
1
2
|
import { panic } from "better-result";
|
|
2
3
|
//#region src/controller/folioEditor.ts
|
|
3
|
-
const FOLIO_DOCX_SERIALIZATION_MODE = Object.freeze({
|
|
4
|
-
full: "full",
|
|
5
|
-
preferSelective: "prefer-selective"
|
|
6
|
-
});
|
|
7
4
|
const createFolioEditor = (deps) => {
|
|
8
5
|
const getDocumentIO = () => deps.getDocumentIO?.() ?? panic("FolioEditor document I/O requires a getDocumentIO dependency");
|
|
9
6
|
return {
|
|
@@ -21,6 +18,10 @@ const createFolioEditor = (deps) => {
|
|
|
21
18
|
getCanonicalStorySelection: (story) => deps.getEditorApi()?.getCanonicalStorySelection(story) ?? null,
|
|
22
19
|
getCanonicalStoryProjection: (story) => deps.getEditorApi()?.getCanonicalStoryProjection(story) ?? null,
|
|
23
20
|
replaceCanonicalStoryText: (options) => deps.getEditorApi()?.replaceCanonicalStoryText(options) ?? false,
|
|
21
|
+
isCanonicalSaveCurrent: (version) => deps.getEditorApi()?.isCanonicalSaveCurrent(version) ?? false,
|
|
22
|
+
captureCanonicalSave: () => deps.getEditorApi()?.captureCanonicalSave() ?? null,
|
|
23
|
+
applyCanonicalDocumentOperations: (options) => deps.getEditorApi()?.applyCanonicalDocumentOperations(options) ?? null,
|
|
24
|
+
undoCanonicalDocumentOperations: (handle) => deps.getEditorApi()?.undoCanonicalDocumentOperations(handle) ?? null,
|
|
24
25
|
getCanonicalDocument: () => deps.getEditorApi()?.getCanonicalDocument() ?? null,
|
|
25
26
|
setCanonicalMode: (mode) => deps.getEditorApi()?.setCanonicalMode(mode) ?? false,
|
|
26
27
|
resolveCanonicalRevisions: (revisionIds, resolution) => deps.getEditorApi()?.resolveCanonicalRevisions(revisionIds, resolution) ?? false,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { CanonicalGap } from "../types/canonicalCapabilities.js";
|
|
2
3
|
import { HiddenEditorApi } from "./hiddenEditorApi.js";
|
|
3
4
|
import { DirectEditorProps, EditorView } from "prosemirror-view";
|
|
4
5
|
//#region src/controller/headerFooterEditorManager.d.ts
|
|
@@ -19,7 +20,7 @@ type HeaderFooterEditorManagerDeps = {
|
|
|
19
20
|
getDocument: () => document_d_exports.Document | null;
|
|
20
21
|
getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
|
|
21
22
|
getExperimentalSession?: (() => "canonical" | undefined) | undefined;
|
|
22
|
-
onSessionRefusal?: ((reason: string) => void) | undefined;
|
|
23
|
+
onSessionRefusal?: ((reason: string, gap: CanonicalGap) => void) | undefined;
|
|
23
24
|
getHost: () => HTMLElement | null;
|
|
24
25
|
getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
|
|
25
26
|
getTheme: () => document_d_exports.Theme | null | undefined;
|
|
@@ -10,6 +10,7 @@ import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNu
|
|
|
10
10
|
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
11
11
|
import { schema } from "../prosemirror/schema/index.js";
|
|
12
12
|
import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
|
|
13
|
+
import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
|
|
13
14
|
import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
|
|
14
15
|
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
15
16
|
import { EditorState, TextSelection } from "prosemirror-state";
|
|
@@ -87,8 +88,8 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
87
88
|
const sync = () => {
|
|
88
89
|
const host = deps.getHost();
|
|
89
90
|
if (!host) return;
|
|
90
|
-
if (deps.getExperimentalSession?.()
|
|
91
|
-
const document = deps.getExperimentalSession?.()
|
|
91
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
|
|
92
|
+
const document = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? deps.getDocument() : deps.getDocument();
|
|
92
93
|
const styles = deps.getStyles();
|
|
93
94
|
const theme = deps.getTheme();
|
|
94
95
|
const numbering = document?.package.numbering;
|
|
@@ -104,7 +105,7 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
104
105
|
const existing = mounted.get(part.rId);
|
|
105
106
|
if (existing) {
|
|
106
107
|
if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
|
|
107
|
-
if (deps.getExperimentalSession?.()
|
|
108
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) {
|
|
108
109
|
const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
109
110
|
kind: part.kind,
|
|
110
111
|
rId: part.rId
|
|
@@ -154,7 +155,7 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
154
155
|
},
|
|
155
156
|
getView: () => view,
|
|
156
157
|
getApi: () => deps.getCanonicalApi?.() ?? null,
|
|
157
|
-
enabled: () => deps.getExperimentalSession?.()
|
|
158
|
+
enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories),
|
|
158
159
|
onRefusal: deps.onSessionRefusal,
|
|
159
160
|
onSelectionChange: () => deps.onTransaction?.({
|
|
160
161
|
kind: part.kind,
|
|
@@ -164,11 +165,11 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
164
165
|
selectionChanged: true
|
|
165
166
|
})
|
|
166
167
|
});
|
|
167
|
-
const canonicalProjection = deps.getExperimentalSession?.()
|
|
168
|
+
const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
168
169
|
kind: part.kind,
|
|
169
170
|
rId: part.rId
|
|
170
171
|
}) : null;
|
|
171
|
-
if (deps.getExperimentalSession?.()
|
|
172
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !canonicalProjection) {
|
|
172
173
|
manager.destroy();
|
|
173
174
|
mountNode.remove();
|
|
174
175
|
continue;
|
|
@@ -217,7 +218,7 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
217
218
|
rId
|
|
218
219
|
})),
|
|
219
220
|
snapshotDocument: (document) => {
|
|
220
|
-
if (deps.getExperimentalSession?.()
|
|
221
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
|
|
221
222
|
let headers = document.package.headers;
|
|
222
223
|
let footers = document.package.footers;
|
|
223
224
|
let headersChanged = false;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
-
import {
|
|
2
|
+
import { FolioDocumentOperationResult, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult } from "../document-operations.js";
|
|
3
|
+
import { CanonicalSaveSnapshot } from "../types/canonicalSave.js";
|
|
3
4
|
import { CanonicalSessionMode } from "./canonicalSession.js";
|
|
5
|
+
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
6
|
+
import { CanonicalPublicOperationOptions } from "./canonicalPublicOperations.js";
|
|
4
7
|
import { Node } from "prosemirror-model";
|
|
5
8
|
import { Command, EditorState, Transaction } from "prosemirror-state";
|
|
6
9
|
import { EditorView } from "prosemirror-view";
|
|
@@ -29,6 +32,9 @@ type HiddenEditorApi = {
|
|
|
29
32
|
getDocument: () => document_d_exports.Document | null;
|
|
30
33
|
/** Canonical snapshot, or null in the default session. */
|
|
31
34
|
getCanonicalDocument: () => document_d_exports.Document | null;
|
|
35
|
+
captureCanonicalSave: () => CanonicalSaveSnapshot | null;
|
|
36
|
+
/** A save cannot acknowledge newer edits or an unfinished composition. */
|
|
37
|
+
isCanonicalSaveCurrent: (version: number) => boolean;
|
|
32
38
|
/** Set the explicit mode for an active canonical session. */
|
|
33
39
|
setCanonicalMode: (mode: CanonicalSessionMode) => boolean;
|
|
34
40
|
/** Resolve canonical revisions as one batch and journal its exact inverse. */
|
|
@@ -42,6 +48,8 @@ type HiddenEditorApi = {
|
|
|
42
48
|
} | null;
|
|
43
49
|
getCanonicalStoryProjection: (story: OpStory) => Node | null;
|
|
44
50
|
replaceCanonicalStoryText: (options: CanonicalStoryTextOptions) => boolean;
|
|
51
|
+
applyCanonicalDocumentOperations: (options: CanonicalPublicOperationOptions) => FolioDocumentOperationResult | null;
|
|
52
|
+
undoCanonicalDocumentOperations: (handle: FolioDocumentOperationUndoHandle) => FolioDocumentOperationUndoResult | null;
|
|
45
53
|
/** Focus the hidden editor */
|
|
46
54
|
focus: () => void;
|
|
47
55
|
/** Blur the hidden editor */
|
|
@@ -73,11 +81,13 @@ type HiddenEditorApiDeps = {
|
|
|
73
81
|
getView: () => EditorView | null;
|
|
74
82
|
getDocumentContext: () => document_d_exports.Document | null;
|
|
75
83
|
getCanonicalDocument?: () => document_d_exports.Document | null;
|
|
84
|
+
captureCanonicalSave?: HiddenEditorApi["captureCanonicalSave"];
|
|
85
|
+
isCanonicalSaveCurrent?: HiddenEditorApi["isCanonicalSaveCurrent"];
|
|
76
86
|
setCanonicalMode?: HiddenEditorApi["setCanonicalMode"];
|
|
77
87
|
resolveCanonicalRevisions?: HiddenEditorApi["resolveCanonicalRevisions"];
|
|
78
88
|
executeCanonicalCommand?: (command: Command) => boolean | undefined;
|
|
79
89
|
getCanonicalHistory?: () => Pick<HiddenEditorApi, "undo" | "redo" | "canUndo" | "canRedo"> | null;
|
|
80
|
-
canonicalOperations?: Pick<HiddenEditorApi, "updateCanonicalInputLifecycle" | "applyCanonicalOperations" | "getCanonicalStoryProjection" | "replaceCanonicalStoryText" | "applyCanonicalStoryHistory" | "getCanonicalStorySelection">;
|
|
90
|
+
canonicalOperations?: Pick<HiddenEditorApi, "updateCanonicalInputLifecycle" | "applyCanonicalOperations" | "getCanonicalStoryProjection" | "replaceCanonicalStoryText" | "applyCanonicalStoryHistory" | "getCanonicalStorySelection" | "applyCanonicalDocumentOperations" | "undoCanonicalDocumentOperations">;
|
|
81
91
|
isDestroying: () => boolean;
|
|
82
92
|
ensureView: () => void;
|
|
83
93
|
isViewRequested: () => boolean;
|
|
@@ -34,6 +34,8 @@ const createHiddenEditorApi = (deps) => {
|
|
|
34
34
|
getView: () => deps.getView() ?? null,
|
|
35
35
|
setCanonicalMode: (mode) => !deps.isDestroying() && (deps.setCanonicalMode?.(mode) ?? false),
|
|
36
36
|
resolveCanonicalRevisions: (revisionIds, resolution) => !deps.isDestroying() && (deps.resolveCanonicalRevisions?.(revisionIds, resolution) ?? false),
|
|
37
|
+
captureCanonicalSave: () => deps.captureCanonicalSave?.() ?? null,
|
|
38
|
+
isCanonicalSaveCurrent: (version) => deps.isCanonicalSaveCurrent?.(version) ?? false,
|
|
37
39
|
getCanonicalDocument: () => {
|
|
38
40
|
const canonical = deps.getCanonicalDocument?.();
|
|
39
41
|
return canonical ? cloneDocumentWithParagraphPropertySources(canonical) : null;
|
|
@@ -51,6 +53,8 @@ const createHiddenEditorApi = (deps) => {
|
|
|
51
53
|
getCanonicalStorySelection: (story) => deps.canonicalOperations?.getCanonicalStorySelection(story) ?? null,
|
|
52
54
|
getCanonicalStoryProjection: (story) => deps.canonicalOperations?.getCanonicalStoryProjection(story) ?? null,
|
|
53
55
|
replaceCanonicalStoryText: (options) => deps.canonicalOperations?.replaceCanonicalStoryText(options) ?? false,
|
|
56
|
+
applyCanonicalDocumentOperations: (options) => deps.canonicalOperations?.applyCanonicalDocumentOperations(options) ?? null,
|
|
57
|
+
undoCanonicalDocumentOperations: (handle) => deps.canonicalOperations?.undoCanonicalDocumentOperations(handle) ?? null,
|
|
54
58
|
focus: () => {
|
|
55
59
|
const view = deps.getView();
|
|
56
60
|
if (!view || view.hasFocus()) return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { CanonicalGap } from "../types/canonicalCapabilities.js";
|
|
2
3
|
import { HiddenEditorApi } from "./hiddenEditorApi.js";
|
|
3
4
|
import { HiddenEditorStateReason } from "../layout-engine/layoutInstrumentation.js";
|
|
4
5
|
import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js";
|
|
@@ -12,6 +13,7 @@ import * as YProseMirror from "y-prosemirror";
|
|
|
12
13
|
//#region src/controller/hiddenEditorManager.d.ts
|
|
13
14
|
declare const CanonicalSessionRefusalError_base: import("better-result").TaggedErrorClass<"CanonicalSessionRefusalError">;
|
|
14
15
|
declare class CanonicalSessionRefusalError extends CanonicalSessionRefusalError_base<{
|
|
16
|
+
gap: CanonicalGap;
|
|
15
17
|
message: string;
|
|
16
18
|
}> {}
|
|
17
19
|
type YProseMirrorModule = typeof YProseMirror;
|
|
@@ -63,7 +65,7 @@ type HiddenEditorManagerDeps = {
|
|
|
63
65
|
getExperimentalSession?: () => "canonical" | undefined;
|
|
64
66
|
getEditingMode?: () => EditorMode;
|
|
65
67
|
getSuggestionAuthor?: () => string;
|
|
66
|
-
onSessionRefusal?: (reason: string) => void;
|
|
68
|
+
onSessionRefusal?: (reason: string, gap: CanonicalGap) => void;
|
|
67
69
|
/**
|
|
68
70
|
* Identity of the loaded document as tracked by the adapter's loader: the
|
|
69
71
|
* same value across internal edits (so typing does not trigger an external
|