@stll/folio-core 0.56.0 → 0.57.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 +45 -14
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.js +7 -1
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +4 -0
- package/dist/controller/canonicalComposition.js +43 -11
- package/dist/controller/canonicalInlineProjection.d.ts +6 -1
- package/dist/controller/canonicalInlineProjection.js +86 -3
- package/dist/controller/canonicalInput.js +10 -1
- package/dist/controller/canonicalInputTimer.d.ts +10 -1
- package/dist/controller/canonicalInputTimer.js +24 -1
- package/dist/controller/canonicalPublicOperations.d.ts +2 -2
- package/dist/controller/canonicalPublicOperations.js +107 -15
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +32 -0
- package/dist/controller/canonicalSession.d.ts +3 -0
- package/dist/controller/canonicalSession.js +58 -24
- package/dist/controller/canonicalStoryEditor.d.ts +2 -0
- package/dist/controller/canonicalStoryEditor.js +20 -0
- package/dist/controller/folioEditor.js +13 -0
- package/dist/controller/headerFooterEditorManager.d.ts +1 -1
- package/dist/controller/headerFooterEditorManager.js +25 -11
- package/dist/controller/hiddenEditorApi.d.ts +13 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +166 -13
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/controller/noteEditorManager.js +28 -13
- package/dist/docx/builtInStyles.js +13 -6
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/fieldParser.js +14 -2
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- package/dist/docx/inlineWrapperContent.d.ts +4 -4
- package/dist/docx/inlineWrapperContent.js +4 -4
- package/dist/docx/linkedSdtPreservation.d.ts +10 -0
- package/dist/docx/linkedSdtPreservation.js +37 -0
- package/dist/docx/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +107 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/rezip.js +9 -6
- package/dist/docx/selectiveSave.js +10 -8
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/materializeYjsDocx.js +14 -6
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- package/dist/i18n/messages/ar.gen.js +4 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
- package/dist/i18n/messages/catalogs.gen.js +68 -0
- package/dist/i18n/messages/cs.gen.js +4 -0
- package/dist/i18n/messages/de.gen.js +4 -0
- package/dist/i18n/messages/en.gen.js +4 -0
- package/dist/i18n/messages/es.gen.js +4 -0
- package/dist/i18n/messages/et.gen.js +4 -0
- package/dist/i18n/messages/fr.gen.js +4 -0
- package/dist/i18n/messages/he.gen.js +4 -0
- package/dist/i18n/messages/hi.gen.js +4 -0
- package/dist/i18n/messages/hu.gen.js +4 -0
- package/dist/i18n/messages/lt.gen.js +4 -0
- package/dist/i18n/messages/lv.gen.js +4 -0
- package/dist/i18n/messages/messages.gen.d.ts +4 -0
- package/dist/i18n/messages/pl.gen.js +4 -0
- package/dist/i18n/messages/pt-BR.gen.js +4 -0
- package/dist/i18n/messages/sk.gen.js +4 -0
- package/dist/i18n/messages/tr.gen.js +4 -0
- package/dist/i18n/messages/zh-CN.gen.js +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/revisionResolutionInline.js +25 -3
- package/dist/markdown/renderRuns.js +1 -11
- package/dist/panel-layout.d.ts +11 -9
- package/dist/panel-layout.js +13 -9
- package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
- package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
- package/dist/prosemirror/attrs/index.js +5 -0
- package/dist/prosemirror/commands/comments.js +60 -35
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
- package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
- package/dist/prosemirror/commentOps.js +15 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
- package/dist/prosemirror/conversion/toProseDoc.js +119 -18
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +22 -5
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +22 -14
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -7
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
- package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
- package/dist/prosemirror/fieldRepresentation.js +18 -0
- package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
- package/dist/prosemirror/hyperlinkRemoval.js +28 -9
- package/dist/prosemirror/listNumbering.js +11 -5
- package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
- package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
- package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
- package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
- package/dist/prosemirror/noteReferenceReview.js +14 -1
- package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +47 -49
- package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
- package/dist/prosemirror/preservedXmlReview.js +35 -0
- package/dist/prosemirror/runFormattingFromMarks.js +2 -2
- package/dist/prosemirror/runFormattingReconciliation.js +5 -4
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
- package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
- package/dist/prosemirror/runStyleFormatting.js +3 -1
- package/dist/prosemirror/schema/marks.d.ts +1 -0
- package/dist/prosemirror/schema/nodes.d.ts +2 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
- package/dist/prosemirror/textInput.d.ts +5 -1
- package/dist/prosemirror/textInput.js +3 -3
- package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +39 -1
- package/dist/prosemirror/validation.js +3 -5
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
- package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
- package/dist/types/canonicalCapabilities.d.ts +6 -20
- package/dist/types/canonicalCapabilities.js +6 -20
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -0
- package/dist/utils/headingCollector.js +45 -4
- package/dist/utils/outlineDepth.d.ts +9 -0
- package/dist/utils/outlineDepth.js +9 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { splitsGraphemeCluster, splitsSurrogatePair } from "../ai-edits/character-boundaries.js";
|
|
2
|
+
import { rangedCommentIds, visitCommentMarkers } from "../docx/commentAnchorIndex.js";
|
|
2
3
|
import { cloneDocumentWithParagraphPropertySources, copyDocumentParagraphPropertySourceContract, copyParagraphPropertySource } from "../docx/paragraphPropertySource.js";
|
|
3
4
|
import { canonicalSelectionRange } from "../prosemirror/canonicalSelectionRange.js";
|
|
4
5
|
import { collectPairedBookmarkIds, footnoteToProseDoc, headerFooterToProseDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
@@ -6,11 +7,12 @@ import { markPackageChange } from "../prosemirror/extensions/features/ParagraphC
|
|
|
6
7
|
import { runFormattingPatchFromMarks } from "../prosemirror/runFormattingFromMarks.js";
|
|
7
8
|
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
8
9
|
import { canonicalInlineSourceIssue, canonicalNativeCells, projectCanonicalInline } from "./canonicalInlineProjection.js";
|
|
10
|
+
import { restoreCanonicalSelection } from "./canonicalSelection.js";
|
|
9
11
|
import { mapTocSelection } from "./canonicalTocSelection.js";
|
|
10
12
|
import { Result, TaggedError, panic } from "better-result";
|
|
11
13
|
import { hasIllegalXmlCharacters } from "@stll/docx-core";
|
|
12
14
|
import { Fragment } from "prosemirror-model";
|
|
13
|
-
import { DOCUMENT_OP_TYPES, OP_STORIES, applyDocumentOps, combineEdits, compileEditorIntent, createEditorIntentIdAllocator, documentStories, editorParagraphGroups, findStoryBody, normalizeForOps, packageParagraphIds, sameStory, validateOpsDocument } from "@stll/docx-core/ops";
|
|
15
|
+
import { DOCUMENT_OP_TYPES, OP_STORIES, applyDocumentOps, combineEdits, commentDocumentIssue, compileEditorIntent, createEditorIntentIdAllocator, documentStories, editorParagraphGroups, findStoryBody, normalizeForOps, packageParagraphIds, sameStory, validateOpsDocument } from "@stll/docx-core/ops";
|
|
14
16
|
import { AllSelection, TextSelection } from "prosemirror-state";
|
|
15
17
|
//#region src/controller/canonicalSession.ts
|
|
16
18
|
var CanonicalSessionError = class extends TaggedError("CanonicalSessionError") {};
|
|
@@ -24,8 +26,20 @@ const noChange = (message) => Result.err(new CanonicalSessionError({
|
|
|
24
26
|
message,
|
|
25
27
|
reason: "noChange"
|
|
26
28
|
}));
|
|
29
|
+
const COMMENT_OPERATION_TYPES = /* @__PURE__ */ new Set([
|
|
30
|
+
DOCUMENT_OP_TYPES.CREATE_COMMENT,
|
|
31
|
+
DOCUMENT_OP_TYPES.UPDATE_COMMENT_CONTENT,
|
|
32
|
+
DOCUMENT_OP_TYPES.SET_COMMENT_RESOLUTION,
|
|
33
|
+
DOCUMENT_OP_TYPES.DELETE_COMMENT,
|
|
34
|
+
DOCUMENT_OP_TYPES.RESTORE_COMMENT_STATE
|
|
35
|
+
]);
|
|
27
36
|
const operationChangesPackage = (op) => {
|
|
28
37
|
switch (op.type) {
|
|
38
|
+
case DOCUMENT_OP_TYPES.CREATE_COMMENT:
|
|
39
|
+
case DOCUMENT_OP_TYPES.UPDATE_COMMENT_CONTENT:
|
|
40
|
+
case DOCUMENT_OP_TYPES.SET_COMMENT_RESOLUTION:
|
|
41
|
+
case DOCUMENT_OP_TYPES.DELETE_COMMENT:
|
|
42
|
+
case DOCUMENT_OP_TYPES.RESTORE_COMMENT_STATE:
|
|
29
43
|
case DOCUMENT_OP_TYPES.CREATE_HEADER_FOOTER:
|
|
30
44
|
case DOCUMENT_OP_TYPES.REMOVE_HEADER_FOOTER:
|
|
31
45
|
case DOCUMENT_OP_TYPES.ADD_NOTE:
|
|
@@ -71,7 +85,7 @@ const operationChangesStructure = (op) => {
|
|
|
71
85
|
case DOCUMENT_OP_TYPES.SET_PACKAGE_RESOURCES:
|
|
72
86
|
case DOCUMENT_OP_TYPES.CREATE_NUMBERING_INSTANCE:
|
|
73
87
|
case DOCUMENT_OP_TYPES.DELETE_NUMBERING_INSTANCE:
|
|
74
|
-
case DOCUMENT_OP_TYPES.SET_SECTION_ENDPOINT:
|
|
88
|
+
case DOCUMENT_OP_TYPES.SET_SECTION_ENDPOINT: return true;
|
|
75
89
|
case DOCUMENT_OP_TYPES.INSERT_TEXT:
|
|
76
90
|
case DOCUMENT_OP_TYPES.INSERT_CONTENT:
|
|
77
91
|
case DOCUMENT_OP_TYPES.DELETE_RANGE:
|
|
@@ -84,12 +98,22 @@ const operationChangesStructure = (op) => {
|
|
|
84
98
|
case DOCUMENT_OP_TYPES.SET_TABLE_GRID:
|
|
85
99
|
case DOCUMENT_OP_TYPES.SET_CELL_PROPS:
|
|
86
100
|
case DOCUMENT_OP_TYPES.SET_ROW_PROPS:
|
|
87
|
-
case DOCUMENT_OP_TYPES.SET_TABLE_PROPS:
|
|
101
|
+
case DOCUMENT_OP_TYPES.SET_TABLE_PROPS:
|
|
102
|
+
case DOCUMENT_OP_TYPES.CREATE_COMMENT:
|
|
103
|
+
case DOCUMENT_OP_TYPES.UPDATE_COMMENT_CONTENT:
|
|
104
|
+
case DOCUMENT_OP_TYPES.SET_COMMENT_RESOLUTION:
|
|
105
|
+
case DOCUMENT_OP_TYPES.DELETE_COMMENT:
|
|
106
|
+
case DOCUMENT_OP_TYPES.RESTORE_COMMENT_STATE: return false;
|
|
88
107
|
default: return op;
|
|
89
108
|
}
|
|
90
109
|
};
|
|
91
110
|
const operationChangesBodyProjection = (op) => {
|
|
92
111
|
switch (op.type) {
|
|
112
|
+
case DOCUMENT_OP_TYPES.CREATE_COMMENT:
|
|
113
|
+
case DOCUMENT_OP_TYPES.UPDATE_COMMENT_CONTENT:
|
|
114
|
+
case DOCUMENT_OP_TYPES.SET_COMMENT_RESOLUTION:
|
|
115
|
+
case DOCUMENT_OP_TYPES.DELETE_COMMENT:
|
|
116
|
+
case DOCUMENT_OP_TYPES.RESTORE_COMMENT_STATE:
|
|
93
117
|
case DOCUMENT_OP_TYPES.CREATE_HEADER_FOOTER:
|
|
94
118
|
case DOCUMENT_OP_TYPES.REMOVE_HEADER_FOOTER:
|
|
95
119
|
case DOCUMENT_OP_TYPES.ADD_NOTE:
|
|
@@ -219,6 +243,8 @@ const preservePropertySources = ({ target, source, stories = documentStories(sou
|
|
|
219
243
|
copyDocumentParagraphPropertySourceContract(target, source);
|
|
220
244
|
};
|
|
221
245
|
const unsupportedSeedReason = (document, stories = documentStories(document)) => {
|
|
246
|
+
const commentIssue = commentDocumentIssue(document, "all");
|
|
247
|
+
if (commentIssue !== void 0) return commentIssue;
|
|
222
248
|
for (const story of stories) {
|
|
223
249
|
const body = findStoryBody(document, story);
|
|
224
250
|
if (story !== OP_STORIES.MAIN && (story.kind === "footnote" || story.kind === "endnote")) {
|
|
@@ -257,6 +283,14 @@ const project = ({ document, styles, story = OP_STORIES.MAIN }) => {
|
|
|
257
283
|
});
|
|
258
284
|
if (converted.isErr()) return converted;
|
|
259
285
|
const pairedBookmarkIds = collectPairedBookmarkIds(body.content);
|
|
286
|
+
const commentContext = {
|
|
287
|
+
rangedIds: rangedCommentIds(body.content),
|
|
288
|
+
pointIds: /* @__PURE__ */ new Set(),
|
|
289
|
+
openIds: /* @__PURE__ */ new Set()
|
|
290
|
+
};
|
|
291
|
+
visitCommentMarkers(body.content, ({ item }) => {
|
|
292
|
+
if (item.type === "commentReference" && !commentContext.rangedIds.has(item.id)) commentContext.pointIds.add(item.id);
|
|
293
|
+
});
|
|
260
294
|
const paragraphs = [];
|
|
261
295
|
let failure;
|
|
262
296
|
converted.value.forEach((node, offset, index) => {
|
|
@@ -280,7 +314,8 @@ const project = ({ document, styles, story = OP_STORIES.MAIN }) => {
|
|
|
280
314
|
const inline = projectCanonicalInline({
|
|
281
315
|
source,
|
|
282
316
|
paragraph: node,
|
|
283
|
-
pairedBookmarkIds
|
|
317
|
+
pairedBookmarkIds,
|
|
318
|
+
commentContext
|
|
284
319
|
});
|
|
285
320
|
if (inline.isErr()) {
|
|
286
321
|
failure = new CanonicalSessionError({
|
|
@@ -297,6 +332,10 @@ const project = ({ document, styles, story = OP_STORIES.MAIN }) => {
|
|
|
297
332
|
node,
|
|
298
333
|
source
|
|
299
334
|
});
|
|
335
|
+
visitCommentMarkers([source], ({ item }) => {
|
|
336
|
+
if (item.type === "commentRangeStart") commentContext.openIds.add(item.id);
|
|
337
|
+
if (item.type === "commentRangeEnd") commentContext.openIds.delete(item.id);
|
|
338
|
+
});
|
|
300
339
|
});
|
|
301
340
|
if (failure !== void 0) return Result.err(failure);
|
|
302
341
|
if (paragraphs.length !== body.content.length) return refuse("The projection changed paragraph structure.");
|
|
@@ -405,6 +444,10 @@ var CanonicalSession = class {
|
|
|
405
444
|
this.styles = styles == null ? styles : structuredClone(styles);
|
|
406
445
|
this.rememberSources(document);
|
|
407
446
|
}
|
|
447
|
+
/** Render only the committed comment projection while provisional IME blocks document snapshots. */
|
|
448
|
+
getCommittedComments() {
|
|
449
|
+
return structuredClone(this.currentDocument.package.document.comments ?? []);
|
|
450
|
+
}
|
|
408
451
|
setMode(mode) {
|
|
409
452
|
if (this.mode.type !== mode.type || this.mode.type === "suggesting" && mode.type === "suggesting" && this.mode.author !== mode.author) this.breakUndoGroup();
|
|
410
453
|
this.mode = mode.type === "editing" ? { type: "editing" } : {
|
|
@@ -994,26 +1037,15 @@ var CanonicalSession = class {
|
|
|
994
1037
|
transaction.replaceWith(from, to, Fragment.fromArray(replacement));
|
|
995
1038
|
}
|
|
996
1039
|
if (!transaction.doc.eq(projected.value.doc)) transaction.replaceWith(0, transaction.doc.content.size, projected.value.doc.content);
|
|
997
|
-
if (sameStory(selection.anchor.story,
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
case "text":
|
|
1005
|
-
if (anchor.isOk() && head.isOk()) {
|
|
1006
|
-
transaction.setSelection(TextSelection.create(transaction.doc, anchor.value, head.value));
|
|
1007
|
-
break;
|
|
1008
|
-
}
|
|
1009
|
-
transaction.setSelection(TextSelection.near(transaction.doc.resolve(Math.min(state.selection.anchor, transaction.doc.content.size))));
|
|
1010
|
-
break;
|
|
1011
|
-
default: {
|
|
1012
|
-
const exhaustive = selection.type;
|
|
1013
|
-
return panic(`Unknown canonical selection type: ${exhaustive}`);
|
|
1014
|
-
}
|
|
1040
|
+
if (sameStory(selection.anchor.story, projectedStory) && sameStory(selection.head.story, projectedStory)) restoreCanonicalSelection({
|
|
1041
|
+
transaction,
|
|
1042
|
+
projection: projected.value,
|
|
1043
|
+
selection,
|
|
1044
|
+
unavailable: {
|
|
1045
|
+
type: "near",
|
|
1046
|
+
anchor: state.selection.anchor
|
|
1015
1047
|
}
|
|
1016
|
-
}
|
|
1048
|
+
});
|
|
1017
1049
|
transaction.setMeta(CANONICAL_PROJECTION_META, {
|
|
1018
1050
|
type: "canonical",
|
|
1019
1051
|
origin,
|
|
@@ -1033,6 +1065,7 @@ var CanonicalSession = class {
|
|
|
1033
1065
|
document: applied.value.document,
|
|
1034
1066
|
projection: projected.value,
|
|
1035
1067
|
bodyProjection: bodyProjection.value,
|
|
1068
|
+
selection,
|
|
1036
1069
|
touched: applied.value.touched,
|
|
1037
1070
|
version: baseVersion + 1,
|
|
1038
1071
|
origin,
|
|
@@ -1061,7 +1094,8 @@ var CanonicalSession = class {
|
|
|
1061
1094
|
applied.value.touched.inserted,
|
|
1062
1095
|
applied.value.touched.removed
|
|
1063
1096
|
]) for (const id of ids) this.saveTouched.add(id);
|
|
1064
|
-
|
|
1097
|
+
const bodyOps = ops.filter((op) => !COMMENT_OPERATION_TYPES.has(op.type));
|
|
1098
|
+
if (bodyOps.some(operationChangesStructure) || bodyOps.some(operationChangesPackage) || bodyOps.length > 0 && (applied.value.touched.inserted.length > 0 || applied.value.touched.removed.length > 0)) this.saveStructure = "changed";
|
|
1065
1099
|
this.currentVersion = baseVersion + 1;
|
|
1066
1100
|
onPublish(applied.value.inverse, this.currentVersion);
|
|
1067
1101
|
return Result.ok(void 0);
|
|
@@ -20,6 +20,8 @@ declare const createCanonicalStoryEditor: ({ story, getView, getApi, enabled, on
|
|
|
20
20
|
handleTextInput: (view: EditorView, from: number, to: number, text: string) => boolean;
|
|
21
21
|
handleDOMEvents: {
|
|
22
22
|
keydown: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
23
|
+
keyup: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
24
|
+
mouseup: (view: EditorView) => boolean;
|
|
23
25
|
beforeinput: (view: EditorView, event: InputEvent) => boolean;
|
|
24
26
|
mousedown: (view: EditorView) => boolean;
|
|
25
27
|
compositionstart: (view: EditorView) => boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
2
2
|
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
3
3
|
import { CanonicalSessionError } from "./canonicalSession.js";
|
|
4
|
+
import { AllSelection, TextSelection } from "prosemirror-state";
|
|
4
5
|
//#region src/controller/canonicalStoryEditor.ts
|
|
5
6
|
/** Secondary views compile classified native input into the shared Document journal. */
|
|
6
7
|
const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal, onSelectionChange }) => {
|
|
@@ -24,6 +25,17 @@ const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal
|
|
|
24
25
|
if (accepted && !view.isDestroyed) onSelectionChange();
|
|
25
26
|
return accepted;
|
|
26
27
|
};
|
|
28
|
+
const syncNativeSelection = (view) => {
|
|
29
|
+
if (boundary.isComposing || view.composing) return;
|
|
30
|
+
const selection = view.dom.ownerDocument.getSelection();
|
|
31
|
+
if (!selection?.anchorNode || !selection.focusNode || !view.dom.contains(selection.anchorNode) || !view.dom.contains(selection.focusNode)) return;
|
|
32
|
+
const anchor = view.posAtDOM(selection.anchorNode, selection.anchorOffset);
|
|
33
|
+
const head = view.posAtDOM(selection.focusNode, selection.focusOffset);
|
|
34
|
+
if (view.state.selection instanceof AllSelection && Math.min(anchor, head) === 0 && Math.max(anchor, head) === view.state.doc.content.size) return;
|
|
35
|
+
if (anchor === view.state.selection.anchor && head === view.state.selection.head) return;
|
|
36
|
+
if (!view.state.doc.resolve(anchor).parent.inlineContent || !view.state.doc.resolve(head).parent.inlineContent) return;
|
|
37
|
+
view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, anchor, head)));
|
|
38
|
+
};
|
|
27
39
|
const boundary = createCanonicalInputBoundary({
|
|
28
40
|
breakUndoGroup: () => {
|
|
29
41
|
getApi()?.updateCanonicalInputLifecycle("breakUndoGroup");
|
|
@@ -70,6 +82,14 @@ const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal
|
|
|
70
82
|
handleTextInput: (view, from, to, text) => enabled() && boundary.handleTextInput(view, from, to, text),
|
|
71
83
|
handleDOMEvents: {
|
|
72
84
|
keydown: (view, event) => enabled() && boundary.handleDOMEvents.keydown(view, event),
|
|
85
|
+
keyup: (view, event) => {
|
|
86
|
+
if (enabled() && /^(?:Arrow|Home$|End$|Page)/u.test(event.key)) syncNativeSelection(view);
|
|
87
|
+
return false;
|
|
88
|
+
},
|
|
89
|
+
mouseup: (view) => {
|
|
90
|
+
if (enabled()) syncNativeSelection(view);
|
|
91
|
+
return false;
|
|
92
|
+
},
|
|
73
93
|
beforeinput: (view, event) => enabled() && boundary.handleDOMEvents.beforeinput(view, event),
|
|
74
94
|
mousedown: (view) => enabled() && boundary.handleDOMEvents.mousedown(view),
|
|
75
95
|
compositionstart: (view) => enabled() && boundary.handleDOMEvents.compositionstart(view),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
1
2
|
import { FOLIO_DOCX_SERIALIZATION_MODE } from "../types/docxSerialization.js";
|
|
2
3
|
import { panic } from "better-result";
|
|
3
4
|
//#region src/controller/folioEditor.ts
|
|
@@ -14,6 +15,16 @@ const createFolioEditor = (deps) => {
|
|
|
14
15
|
getDocument: () => deps.getEditorApi()?.getDocument() ?? null,
|
|
15
16
|
updateCanonicalInputLifecycle: (action) => deps.getEditorApi()?.updateCanonicalInputLifecycle(action) ?? false,
|
|
16
17
|
applyCanonicalStoryHistory: (options) => deps.getEditorApi()?.applyCanonicalStoryHistory(options) ?? false,
|
|
18
|
+
applyCanonicalComment: (request) => deps.getEditorApi()?.applyCanonicalComment(request) ?? null,
|
|
19
|
+
applyCanonicalSectionProperties: (patch) => {
|
|
20
|
+
const api = deps.getEditorApi();
|
|
21
|
+
if (!api) return {
|
|
22
|
+
status: "refused",
|
|
23
|
+
gap: CANONICAL_GAP.sectionProperties,
|
|
24
|
+
message: "The editor is not ready for section changes."
|
|
25
|
+
};
|
|
26
|
+
return api.applyCanonicalSectionProperties(patch);
|
|
27
|
+
},
|
|
17
28
|
applyCanonicalOperations: (ops) => deps.getEditorApi()?.applyCanonicalOperations(ops) ?? false,
|
|
18
29
|
getCanonicalStorySelection: (story) => deps.getEditorApi()?.getCanonicalStorySelection(story) ?? null,
|
|
19
30
|
getCanonicalStoryProjection: (story) => deps.getEditorApi()?.getCanonicalStoryProjection(story) ?? null,
|
|
@@ -22,6 +33,8 @@ const createFolioEditor = (deps) => {
|
|
|
22
33
|
captureCanonicalSave: () => deps.getEditorApi()?.captureCanonicalSave() ?? null,
|
|
23
34
|
applyCanonicalDocumentOperations: (options) => deps.getEditorApi()?.applyCanonicalDocumentOperations(options) ?? null,
|
|
24
35
|
undoCanonicalDocumentOperations: (handle) => deps.getEditorApi()?.undoCanonicalDocumentOperations(handle) ?? null,
|
|
36
|
+
getCanonicalComments: () => deps.getEditorApi()?.getCanonicalComments() ?? null,
|
|
37
|
+
getCanonicalCommittedVersion: () => deps.getEditorApi()?.getCanonicalCommittedVersion() ?? null,
|
|
25
38
|
getCanonicalDocument: () => deps.getEditorApi()?.getCanonicalDocument() ?? null,
|
|
26
39
|
setCanonicalMode: (mode) => deps.getEditorApi()?.setCanonicalMode(mode) ?? false,
|
|
27
40
|
resolveCanonicalRevisions: (revisionIds, resolution) => deps.getEditorApi()?.resolveCanonicalRevisions(revisionIds, resolution) ?? false,
|
|
@@ -20,7 +20,7 @@ type HeaderFooterEditorManagerDeps = {
|
|
|
20
20
|
getDocument: () => document_d_exports.Document | null;
|
|
21
21
|
getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
|
|
22
22
|
getExperimentalSession?: (() => "canonical" | undefined) | undefined;
|
|
23
|
-
onSessionRefusal?: ((reason: string, gap: CanonicalGap) => void) | undefined;
|
|
23
|
+
onSessionRefusal?: ((reason: string, gap: CanonicalGap, error?: Error) => void) | undefined;
|
|
24
24
|
getHost: () => HTMLElement | null;
|
|
25
25
|
getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
|
|
26
26
|
getTheme: () => document_d_exports.Theme | null | undefined;
|
|
@@ -6,11 +6,13 @@ import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js"
|
|
|
6
6
|
import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
|
|
7
7
|
import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
|
|
8
8
|
import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
|
|
9
|
+
import { noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
|
|
9
10
|
import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
|
|
10
|
-
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
11
|
+
import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
11
12
|
import { schema } from "../prosemirror/schema/index.js";
|
|
12
13
|
import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
|
|
13
14
|
import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
|
|
15
|
+
import { CanonicalSessionError } from "./canonicalSession.js";
|
|
14
16
|
import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
|
|
15
17
|
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
16
18
|
import { EditorState, TextSelection } from "prosemirror-state";
|
|
@@ -85,11 +87,12 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
85
87
|
for (const part of mounted.values()) destroyMounted(part);
|
|
86
88
|
mounted.clear();
|
|
87
89
|
};
|
|
90
|
+
const getOwnedDocument = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? null : deps.getDocument();
|
|
88
91
|
const sync = () => {
|
|
89
92
|
const host = deps.getHost();
|
|
90
93
|
if (!host) return;
|
|
91
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
92
|
-
const document =
|
|
94
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
|
|
95
|
+
const document = getOwnedDocument();
|
|
93
96
|
const styles = deps.getStyles();
|
|
94
97
|
const theme = deps.getTheme();
|
|
95
98
|
const numbering = document?.package.numbering;
|
|
@@ -105,7 +108,7 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
105
108
|
const existing = mounted.get(part.rId);
|
|
106
109
|
if (existing) {
|
|
107
110
|
if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
|
|
108
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
111
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
|
|
109
112
|
const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
110
113
|
kind: part.kind,
|
|
111
114
|
rId: part.rId
|
|
@@ -155,7 +158,7 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
155
158
|
},
|
|
156
159
|
getView: () => view,
|
|
157
160
|
getApi: () => deps.getCanonicalApi?.() ?? null,
|
|
158
|
-
enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
161
|
+
enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting),
|
|
159
162
|
onRefusal: deps.onSessionRefusal,
|
|
160
163
|
onSelectionChange: () => deps.onTransaction?.({
|
|
161
164
|
kind: part.kind,
|
|
@@ -165,11 +168,11 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
165
168
|
selectionChanged: true
|
|
166
169
|
})
|
|
167
170
|
});
|
|
168
|
-
const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
171
|
+
const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
169
172
|
kind: part.kind,
|
|
170
173
|
rId: part.rId
|
|
171
174
|
}) : null;
|
|
172
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
175
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !canonicalProjection) {
|
|
173
176
|
manager.destroy();
|
|
174
177
|
mountNode.remove();
|
|
175
178
|
continue;
|
|
@@ -178,16 +181,19 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
178
181
|
...canonical.props,
|
|
179
182
|
state: canonicalProjection ? EditorState.create({
|
|
180
183
|
doc: canonicalProjection,
|
|
181
|
-
plugins: [
|
|
184
|
+
plugins: [createDocumentStyleContextPlugin(styles), createDocumentNumberingPlugin(numbering)]
|
|
182
185
|
}) : buildInitialState(headerFooter, styles, theme, numbering, manager),
|
|
183
186
|
dispatchTransaction(transaction) {
|
|
184
187
|
if (canonical.dispatch(transaction)) return;
|
|
185
188
|
const nextState = view.state.apply(transaction);
|
|
189
|
+
const docChanged = !nextState.doc.eq(view.state.doc);
|
|
190
|
+
const noteIssue = noteReferenceTransactionIssue(transaction);
|
|
191
|
+
if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
|
|
186
192
|
view.updateState(nextState);
|
|
187
193
|
const mountedPart = mounted.get(part.rId);
|
|
188
|
-
if (mountedPart &&
|
|
194
|
+
if (mountedPart && docChanged) mountedPart.dirty = true;
|
|
189
195
|
deps.onTransaction?.({
|
|
190
|
-
docChanged
|
|
196
|
+
docChanged,
|
|
191
197
|
kind: part.kind,
|
|
192
198
|
rId: part.rId,
|
|
193
199
|
selectionChanged: transaction.selectionSet,
|
|
@@ -218,7 +224,15 @@ const createHeaderFooterEditorManager = (deps) => {
|
|
|
218
224
|
rId
|
|
219
225
|
})),
|
|
220
226
|
snapshotDocument: (document) => {
|
|
221
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
227
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
|
|
228
|
+
const canonical = deps.getCanonicalApi?.()?.getCanonicalDocument();
|
|
229
|
+
if (canonical) return canonical;
|
|
230
|
+
throw new CanonicalSessionError({
|
|
231
|
+
gap: CANONICAL_GAP.authorityRouting,
|
|
232
|
+
reason: "refused",
|
|
233
|
+
message: "Canonical story snapshot is unavailable."
|
|
234
|
+
});
|
|
235
|
+
}
|
|
222
236
|
let headers = document.package.headers;
|
|
223
237
|
let footers = document.package.footers;
|
|
224
238
|
let headersChanged = false;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { FolioDocumentOperationResult, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult } from "../document-operations.js";
|
|
3
|
+
import { Comment } from "../types/content.js";
|
|
3
4
|
import { CanonicalSaveSnapshot } from "../types/canonicalSave.js";
|
|
4
5
|
import { CanonicalSessionMode } from "./canonicalSession.js";
|
|
5
6
|
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
6
7
|
import { CanonicalPublicOperationOptions } from "./canonicalPublicOperations.js";
|
|
8
|
+
import { CanonicalSectionPropertiesResult } from "../types/canonicalSections.js";
|
|
9
|
+
import { CanonicalCommentRequest, CanonicalCommentResult } from "../types/canonicalComments.js";
|
|
7
10
|
import { Node } from "prosemirror-model";
|
|
8
11
|
import { Command, EditorState, Transaction } from "prosemirror-state";
|
|
9
12
|
import { EditorView } from "prosemirror-view";
|
|
10
|
-
import { DocumentOp, OpStory } from "@stll/docx-core/ops";
|
|
13
|
+
import { DocumentOp, FormattingPatch, OpStory } from "@stll/docx-core/ops";
|
|
11
14
|
//#region src/controller/hiddenEditorApi.d.ts
|
|
12
15
|
type CanonicalStoryHistoryOptions = {
|
|
13
16
|
view: EditorView;
|
|
@@ -31,6 +34,9 @@ type HiddenEditorApi = {
|
|
|
31
34
|
/** Get the current Document from PM state */
|
|
32
35
|
getDocument: () => document_d_exports.Document | null;
|
|
33
36
|
/** Canonical snapshot, or null in the default session. */
|
|
37
|
+
getCanonicalComments: () => Comment[] | null;
|
|
38
|
+
/** Committed session/version identity; safe during provisional composition. */
|
|
39
|
+
getCanonicalCommittedVersion: () => string | null;
|
|
34
40
|
getCanonicalDocument: () => document_d_exports.Document | null;
|
|
35
41
|
captureCanonicalSave: () => CanonicalSaveSnapshot | null;
|
|
36
42
|
/** A save cannot acknowledge newer edits or an unfinished composition. */
|
|
@@ -42,6 +48,9 @@ type HiddenEditorApi = {
|
|
|
42
48
|
updateCanonicalInputLifecycle: (action: "beginComposition" | "endComposition" | "breakUndoGroup") => boolean;
|
|
43
49
|
applyCanonicalStoryHistory: (options: CanonicalStoryHistoryOptions) => boolean;
|
|
44
50
|
applyCanonicalOperations: (ops: readonly DocumentOp[]) => boolean;
|
|
51
|
+
applyCanonicalComment: (request: CanonicalCommentRequest) => CanonicalCommentResult | null;
|
|
52
|
+
/** Apply a final-section patch; null is reserved for default sessions. */
|
|
53
|
+
applyCanonicalSectionProperties: (patch: FormattingPatch<document_d_exports.SectionProperties>) => CanonicalSectionPropertiesResult | null;
|
|
45
54
|
getCanonicalStorySelection: (story: OpStory) => {
|
|
46
55
|
anchor: number;
|
|
47
56
|
head: number;
|
|
@@ -80,6 +89,8 @@ type HiddenEditorApi = {
|
|
|
80
89
|
type HiddenEditorApiDeps = {
|
|
81
90
|
getView: () => EditorView | null;
|
|
82
91
|
getDocumentContext: () => document_d_exports.Document | null;
|
|
92
|
+
getCanonicalComments?: () => Comment[] | null;
|
|
93
|
+
getCanonicalCommittedVersion?: HiddenEditorApi["getCanonicalCommittedVersion"];
|
|
83
94
|
getCanonicalDocument?: () => document_d_exports.Document | null;
|
|
84
95
|
captureCanonicalSave?: HiddenEditorApi["captureCanonicalSave"];
|
|
85
96
|
isCanonicalSaveCurrent?: HiddenEditorApi["isCanonicalSaveCurrent"];
|
|
@@ -87,7 +98,7 @@ type HiddenEditorApiDeps = {
|
|
|
87
98
|
resolveCanonicalRevisions?: HiddenEditorApi["resolveCanonicalRevisions"];
|
|
88
99
|
executeCanonicalCommand?: (command: Command) => boolean | undefined;
|
|
89
100
|
getCanonicalHistory?: () => Pick<HiddenEditorApi, "undo" | "redo" | "canUndo" | "canRedo"> | null;
|
|
90
|
-
canonicalOperations?: Pick<HiddenEditorApi, "updateCanonicalInputLifecycle" | "applyCanonicalOperations" | "getCanonicalStoryProjection" | "replaceCanonicalStoryText" | "applyCanonicalStoryHistory" | "getCanonicalStorySelection" | "applyCanonicalDocumentOperations" | "undoCanonicalDocumentOperations">;
|
|
101
|
+
canonicalOperations?: Pick<HiddenEditorApi, "updateCanonicalInputLifecycle" | "applyCanonicalOperations" | "applyCanonicalComment" | "applyCanonicalSectionProperties" | "getCanonicalStoryProjection" | "replaceCanonicalStoryText" | "applyCanonicalStoryHistory" | "getCanonicalStorySelection" | "applyCanonicalDocumentOperations" | "undoCanonicalDocumentOperations">;
|
|
91
102
|
isDestroying: () => boolean;
|
|
92
103
|
ensureView: () => void;
|
|
93
104
|
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
|
+
getCanonicalComments: () => deps.getCanonicalComments?.() ?? null,
|
|
38
|
+
getCanonicalCommittedVersion: () => deps.getCanonicalCommittedVersion?.() ?? null,
|
|
37
39
|
captureCanonicalSave: () => deps.captureCanonicalSave?.() ?? null,
|
|
38
40
|
isCanonicalSaveCurrent: (version) => deps.isCanonicalSaveCurrent?.(version) ?? false,
|
|
39
41
|
getCanonicalDocument: () => {
|
|
@@ -49,6 +51,8 @@ const createHiddenEditorApi = (deps) => {
|
|
|
49
51
|
},
|
|
50
52
|
updateCanonicalInputLifecycle: (action) => deps.canonicalOperations?.updateCanonicalInputLifecycle(action) ?? false,
|
|
51
53
|
applyCanonicalStoryHistory: (options) => deps.canonicalOperations?.applyCanonicalStoryHistory(options) ?? false,
|
|
54
|
+
applyCanonicalComment: (request) => deps.canonicalOperations?.applyCanonicalComment(request) ?? null,
|
|
55
|
+
applyCanonicalSectionProperties: (patch) => deps.canonicalOperations?.applyCanonicalSectionProperties(patch) ?? null,
|
|
52
56
|
applyCanonicalOperations: (ops) => deps.canonicalOperations?.applyCanonicalOperations(ops) ?? false,
|
|
53
57
|
getCanonicalStorySelection: (story) => deps.canonicalOperations?.getCanonicalStorySelection(story) ?? null,
|
|
54
58
|
getCanonicalStoryProjection: (story) => deps.canonicalOperations?.getCanonicalStoryProjection(story) ?? null,
|
|
@@ -65,7 +65,7 @@ type HiddenEditorManagerDeps = {
|
|
|
65
65
|
getExperimentalSession?: () => "canonical" | undefined;
|
|
66
66
|
getEditingMode?: () => EditorMode;
|
|
67
67
|
getSuggestionAuthor?: () => string;
|
|
68
|
-
onSessionRefusal?: (reason: string, gap: CanonicalGap) => void;
|
|
68
|
+
onSessionRefusal?: (reason: string, gap: CanonicalGap, error?: Error) => void;
|
|
69
69
|
/**
|
|
70
70
|
* Identity of the loaded document as tracked by the adapter's loader: the
|
|
71
71
|
* same value across internal edits (so typing does not trigger an external
|
|
@@ -99,6 +99,8 @@ declare const createHiddenEditorClipboardHandlers: (deps: Pick<HiddenEditorManag
|
|
|
99
99
|
paste: (_view: unknown, event: PreventableDomEvent) => boolean;
|
|
100
100
|
};
|
|
101
101
|
type HiddenEditorManager = {
|
|
102
|
+
/** Whether the canonical owner still holds a provisional composition. */
|
|
103
|
+
isCanonicalComposing: () => boolean;
|
|
102
104
|
/** Request the view (sets the requested flag, then attempts creation). */
|
|
103
105
|
ensureView: () => void;
|
|
104
106
|
/** Re-attempt a previously-requested-but-deferred creation (no-op otherwise). */
|