@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.
Files changed (142) hide show
  1. package/dist/ai-edits/apply.js +45 -14
  2. package/dist/ai-edits/batch-claims.d.ts +3 -1
  3. package/dist/ai-edits/batch-claims.js +25 -1
  4. package/dist/ai-edits/table-row-column-mutations.js +17 -3
  5. package/dist/ai-suggestions/apply.js +20 -1
  6. package/dist/compare/inline-atoms.js +40 -16
  7. package/dist/compare/inline-provenance.js +12 -5
  8. package/dist/compat/eigenpal.d.ts +2 -1
  9. package/dist/compat/eigenpal.js +2 -1
  10. package/dist/controller/canonicalClipboard.js +7 -1
  11. package/dist/controller/canonicalComments.d.ts +41 -0
  12. package/dist/controller/canonicalComments.js +152 -0
  13. package/dist/controller/canonicalComposition.d.ts +4 -0
  14. package/dist/controller/canonicalComposition.js +43 -11
  15. package/dist/controller/canonicalInlineProjection.d.ts +6 -1
  16. package/dist/controller/canonicalInlineProjection.js +86 -3
  17. package/dist/controller/canonicalInput.js +10 -1
  18. package/dist/controller/canonicalInputTimer.d.ts +10 -1
  19. package/dist/controller/canonicalInputTimer.js +24 -1
  20. package/dist/controller/canonicalPublicOperations.d.ts +2 -2
  21. package/dist/controller/canonicalPublicOperations.js +107 -15
  22. package/dist/controller/canonicalSelection.d.ts +18 -0
  23. package/dist/controller/canonicalSelection.js +32 -0
  24. package/dist/controller/canonicalSession.d.ts +3 -0
  25. package/dist/controller/canonicalSession.js +58 -24
  26. package/dist/controller/canonicalStoryEditor.d.ts +2 -0
  27. package/dist/controller/canonicalStoryEditor.js +20 -0
  28. package/dist/controller/folioEditor.js +13 -0
  29. package/dist/controller/headerFooterEditorManager.d.ts +1 -1
  30. package/dist/controller/headerFooterEditorManager.js +25 -11
  31. package/dist/controller/hiddenEditorApi.d.ts +13 -2
  32. package/dist/controller/hiddenEditorApi.js +4 -0
  33. package/dist/controller/hiddenEditorManager.d.ts +3 -1
  34. package/dist/controller/hiddenEditorManager.js +166 -13
  35. package/dist/controller/noteEditorManager.d.ts +1 -1
  36. package/dist/controller/noteEditorManager.js +28 -13
  37. package/dist/docx/builtInStyles.js +13 -6
  38. package/dist/docx/containerChildren.gen.d.ts +3 -1
  39. package/dist/docx/containerChildren.gen.js +33 -1
  40. package/dist/docx/fieldParser.js +14 -2
  41. package/dist/docx/hyperlinkParser.d.ts +1 -1
  42. package/dist/docx/hyperlinkParser.js +20 -1
  43. package/dist/docx/inlineWrapperContent.d.ts +4 -4
  44. package/dist/docx/inlineWrapperContent.js +4 -4
  45. package/dist/docx/linkedSdtPreservation.d.ts +10 -0
  46. package/dist/docx/linkedSdtPreservation.js +37 -0
  47. package/dist/docx/paragraphParser.js +88 -67
  48. package/dist/docx/paragraphPropertySource.d.ts +22 -1
  49. package/dist/docx/paragraphPropertySource.js +107 -1
  50. package/dist/docx/preservedRunContent.js +2 -1
  51. package/dist/docx/relsParser.js +26 -2
  52. package/dist/docx/rezip.js +9 -6
  53. package/dist/docx/selectiveSave.js +10 -8
  54. package/dist/docx/serializer/commentSerializer.d.ts +4 -1
  55. package/dist/docx/serializer/commentSerializer.js +7 -3
  56. package/dist/docx/serializer/paragraphSerializer.js +207 -94
  57. package/dist/docx/server/materializeYjsDocx.js +14 -6
  58. package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
  59. package/dist/i18n/messages/ar.gen.js +4 -0
  60. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  61. package/dist/i18n/messages/catalogs.gen.js +68 -0
  62. package/dist/i18n/messages/cs.gen.js +4 -0
  63. package/dist/i18n/messages/de.gen.js +4 -0
  64. package/dist/i18n/messages/en.gen.js +4 -0
  65. package/dist/i18n/messages/es.gen.js +4 -0
  66. package/dist/i18n/messages/et.gen.js +4 -0
  67. package/dist/i18n/messages/fr.gen.js +4 -0
  68. package/dist/i18n/messages/he.gen.js +4 -0
  69. package/dist/i18n/messages/hi.gen.js +4 -0
  70. package/dist/i18n/messages/hu.gen.js +4 -0
  71. package/dist/i18n/messages/lt.gen.js +4 -0
  72. package/dist/i18n/messages/lv.gen.js +4 -0
  73. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  74. package/dist/i18n/messages/pl.gen.js +4 -0
  75. package/dist/i18n/messages/pt-BR.gen.js +4 -0
  76. package/dist/i18n/messages/sk.gen.js +4 -0
  77. package/dist/i18n/messages/tr.gen.js +4 -0
  78. package/dist/i18n/messages/zh-CN.gen.js +4 -0
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +2 -1
  81. package/dist/internal/revisionResolutionInline.js +25 -3
  82. package/dist/markdown/renderRuns.js +1 -11
  83. package/dist/panel-layout.d.ts +11 -9
  84. package/dist/panel-layout.js +13 -9
  85. package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
  86. package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
  87. package/dist/prosemirror/attrs/index.js +5 -0
  88. package/dist/prosemirror/commands/comments.js +60 -35
  89. package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
  90. package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
  91. package/dist/prosemirror/commentOps.js +15 -1
  92. package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
  93. package/dist/prosemirror/conversion/toProseDoc.js +119 -18
  94. package/dist/prosemirror/extensions/core/ParagraphExtension.js +22 -5
  95. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
  96. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
  97. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +22 -14
  98. package/dist/prosemirror/extensions/marks/markUtils.js +8 -7
  99. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
  100. package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
  101. package/dist/prosemirror/fieldRepresentation.js +18 -0
  102. package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
  103. package/dist/prosemirror/hyperlinkRemoval.js +28 -9
  104. package/dist/prosemirror/listNumbering.js +11 -5
  105. package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
  106. package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
  107. package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
  108. package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
  109. package/dist/prosemirror/noteReferenceReview.js +14 -1
  110. package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
  111. package/dist/prosemirror/plugins/documentStyles.js +17 -10
  112. package/dist/prosemirror/plugins/suggestionMode.js +47 -49
  113. package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
  114. package/dist/prosemirror/preservedXmlReview.js +35 -0
  115. package/dist/prosemirror/runFormattingFromMarks.js +2 -2
  116. package/dist/prosemirror/runFormattingReconciliation.js +5 -4
  117. package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
  118. package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
  119. package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
  120. package/dist/prosemirror/runStyleFormatting.js +3 -1
  121. package/dist/prosemirror/schema/marks.d.ts +1 -0
  122. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  123. package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
  124. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
  125. package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
  126. package/dist/prosemirror/textInput.d.ts +5 -1
  127. package/dist/prosemirror/textInput.js +3 -3
  128. package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
  129. package/dist/prosemirror/trackedRevisionPath.js +39 -1
  130. package/dist/prosemirror/validation.js +3 -5
  131. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  132. package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
  133. package/dist/types/canonicalCapabilities.d.ts +6 -20
  134. package/dist/types/canonicalCapabilities.js +6 -20
  135. package/dist/types/canonicalComments.d.ts +51 -0
  136. package/dist/types/canonicalComments.js +0 -0
  137. package/dist/types/canonicalSections.d.ts +12 -0
  138. package/dist/types/canonicalSections.js +0 -0
  139. package/dist/utils/headingCollector.js +45 -4
  140. package/dist/utils/outlineDepth.d.ts +9 -0
  141. package/dist/utils/outlineDepth.js +9 -0
  142. package/package.json +2 -2
@@ -10,20 +10,25 @@ import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/A
10
10
  import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
11
11
  import { createParagraphChangeTrackerPlugin, markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
12
12
  import { toggleMarkForAllScripts, toggleUnderlineMark } from "../prosemirror/extensions/marks/markUtils.js";
13
+ import { HyperlinkRemovalRefusal } from "../prosemirror/hyperlinkRemoval.js";
14
+ import { markNoteReferenceReplay, noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
13
15
  import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
14
- import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
16
+ import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
15
17
  import { schema } from "../prosemirror/schema/index.js";
16
18
  import { createTextInputPlugin } from "../prosemirror/textInput.js";
17
19
  import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
18
20
  import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
19
21
  import { prepareCanonicalPaste } from "./canonicalClipboard.js";
22
+ import { canonicalCommentBody, compileCanonicalComments } from "./canonicalComments.js";
20
23
  import { createCanonicalInputBoundary } from "./canonicalInput.js";
24
+ import { createCanonicalSectionPropertiesOperation } from "./canonicalOperations.js";
21
25
  import { CanonicalPublicOperations } from "./canonicalPublicOperations.js";
26
+ import { restoreCanonicalSelection } from "./canonicalSelection.js";
22
27
  import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
23
28
  import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
24
29
  import { createHiddenEditorApi } from "./hiddenEditorApi.js";
25
30
  import { Result, TaggedError, panic } from "better-result";
26
- import { OP_STORIES } from "@stll/docx-core/ops";
31
+ import { OP_STORIES, freshCommentId } from "@stll/docx-core/ops";
27
32
  import { EditorState, Plugin } from "prosemirror-state";
28
33
  import { EditorView } from "prosemirror-view";
29
34
  //#region src/controller/hiddenEditorManager.ts
@@ -206,6 +211,7 @@ const createHiddenEditorManager = (deps) => {
206
211
  let view = null;
207
212
  let releaseCommandOwner;
208
213
  let editorSession = { type: "prosemirror" };
214
+ let canonicalSessionEpoch = 0;
209
215
  let modeOverride = null;
210
216
  const syncCanonicalMode = () => {
211
217
  if (editorSession.type !== "canonical") return;
@@ -253,6 +259,7 @@ const createHiddenEditorManager = (deps) => {
253
259
  type: "canonical",
254
260
  session: result.value
255
261
  };
262
+ canonicalSessionEpoch += 1;
256
263
  modeOverride = null;
257
264
  syncCanonicalMode();
258
265
  return true;
@@ -261,7 +268,7 @@ const createHiddenEditorManager = (deps) => {
261
268
  doc: session.projection.doc,
262
269
  plugins: [
263
270
  createParagraphChangeTrackerPlugin(),
264
- createDocumentStylesPlugin(deps.getStyles() ?? session.document.package.styles),
271
+ createDocumentStyleContextPlugin(deps.getStyles() ?? session.document.package.styles),
265
272
  createDocumentNumberingPlugin(session.document.package.numbering),
266
273
  ...[...deps.getExtensionManager()?.getPlugins() ?? [], ...deps.getExternalPlugins()].flatMap(({ props }) => props.transformPastedHTML === void 0 && props.transformPasted === void 0 && props.transformCopied === void 0 && props.clipboardTextSerializer === void 0 ? [] : [new Plugin({ props: {
267
274
  ...props.transformCopied === void 0 ? {} : { transformCopied: props.transformCopied },
@@ -271,7 +278,7 @@ const createHiddenEditorManager = (deps) => {
271
278
  } })])
272
279
  ]
273
280
  });
274
- const publishCommit = (commit) => {
281
+ const publishCommit = (commit, reportRefusal = refuse) => {
275
282
  if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
276
283
  const session = editorSession.session;
277
284
  const result = publishCanonicalProjection({
@@ -280,7 +287,7 @@ const createHiddenEditorManager = (deps) => {
280
287
  session
281
288
  });
282
289
  if (result.isErr()) {
283
- refuse(result.error.message, result.error.gap);
290
+ reportRefusal(result.error.message, result.error.gap);
284
291
  return false;
285
292
  }
286
293
  const staged = result.value;
@@ -312,7 +319,21 @@ const createHiddenEditorManager = (deps) => {
312
319
  refuse("Composition must finish before formatting.");
313
320
  return false;
314
321
  }
315
- const intents = getCanonicalCommandIntents(command, view.state);
322
+ const commandState = view.state;
323
+ const described = Result.try({
324
+ try: () => getCanonicalCommandIntents(command, commandState),
325
+ catch: (error) => error
326
+ });
327
+ if (described.isErr()) {
328
+ if (!(described.error instanceof HyperlinkRemovalRefusal)) throw described.error;
329
+ const refusal = new CanonicalSessionRefusalError({
330
+ gap: CANONICAL_GAP.commands,
331
+ message: described.error.message
332
+ });
333
+ refuse(refusal.message, refusal.gap);
334
+ return false;
335
+ }
336
+ const intents = described.value;
316
337
  if (intents === void 0) return void 0;
317
338
  syncCanonicalMode();
318
339
  editorSession.session.breakUndoGroup();
@@ -568,7 +589,11 @@ const createHiddenEditorManager = (deps) => {
568
589
  lastInputRule = void 0;
569
590
  editorSession.session.breakUndoGroup();
570
591
  }
592
+ const modules = deps.getCollaborationModules();
593
+ if (modules && transaction.getMeta(modules.yProseMirror.ySyncPluginKey) !== void 0) markNoteReferenceReplay(transaction);
571
594
  const applied = view.state.applyTransaction(transaction);
595
+ const noteIssue = noteReferenceTransactionIssue(transaction);
596
+ if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
572
597
  if (editorSession.type === "canonical" && !applied.state.doc.eq(view.state.doc)) {
573
598
  refuse("A plugin attempted an unclassified canonical document mutation.");
574
599
  return;
@@ -751,14 +776,15 @@ const createHiddenEditorManager = (deps) => {
751
776
  };
752
777
  const syncExternalDocument = () => {
753
778
  if (!view || isDestroying) return;
779
+ const canonicalRequested = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
754
780
  const collaboration = deps.getCollaboration();
755
781
  const collaborationModules = deps.getCollaborationModules();
756
- if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
782
+ if (collaboration && !collaborationModules && !canonicalRequested) return;
757
783
  const document = deps.getDocument();
758
784
  const currentDocId = deps.getDocumentIdentity();
759
785
  const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
760
786
  const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
761
- const sessionChanged = editorSession.type !== "prosemirror" !== usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
787
+ const sessionChanged = editorSession.type !== "prosemirror" !== canonicalRequested;
762
788
  if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
763
789
  if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
764
790
  input.reset();
@@ -790,13 +816,20 @@ const createHiddenEditorManager = (deps) => {
790
816
  };
791
817
  const publishStoryCommit = (storyView, commit) => {
792
818
  if (!view || editorSession.type !== "canonical") return false;
793
- if (deps.getEditingMode?.() === "suggesting") {
794
- refuse("Suggesting is unavailable in the experimental canonical session.", CANONICAL_GAP.suggesting);
795
- return false;
796
- }
797
819
  const session = editorSession.session;
798
820
  const bodyTransaction = view.state.tr;
799
821
  if (!bodyTransaction.doc.eq(commit.bodyProjection.doc)) bodyTransaction.replaceWith(0, bodyTransaction.doc.content.size, commit.bodyProjection.doc.content);
822
+ if (commit.selection.anchor.story === OP_STORIES.MAIN && commit.selection.head.story === OP_STORIES.MAIN) {
823
+ if (!restoreCanonicalSelection({
824
+ transaction: bodyTransaction,
825
+ projection: commit.bodyProjection,
826
+ selection: commit.selection,
827
+ unavailable: { type: "refuse" }
828
+ })) {
829
+ refuse("The canonical body history selection is unavailable.");
830
+ return false;
831
+ }
832
+ }
800
833
  markPackageChange(bodyTransaction);
801
834
  bodyTransaction.setMeta("addToHistory", false);
802
835
  const bodyStaged = Result.try(() => view?.state.applyTransaction(bodyTransaction));
@@ -839,6 +872,7 @@ const createHiddenEditorManager = (deps) => {
839
872
  };
840
873
  return executor;
841
874
  };
875
+ const isCanonicalModelSessionRequested = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
842
876
  return {
843
877
  ensureView,
844
878
  retryViewCreation,
@@ -851,6 +885,8 @@ const createHiddenEditorManager = (deps) => {
851
885
  api: createHiddenEditorApi({
852
886
  getView: () => view,
853
887
  getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
888
+ getCanonicalComments: () => editorSession.type === "canonical" ? editorSession.session.getCommittedComments() : null,
889
+ getCanonicalCommittedVersion: () => editorSession.type === "canonical" ? `${canonicalSessionEpoch}:${editorSession.session.version}` : null,
854
890
  isCanonicalSaveCurrent: (version) => editorSession.type === "canonical" && !editorSession.session.isComposing && editorSession.session.version === version,
855
891
  captureCanonicalSave: () => editorSession.type === "canonical" ? editorSession.session.captureSaveSnapshot() : null,
856
892
  getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
@@ -880,6 +916,120 @@ const createHiddenEditorManager = (deps) => {
880
916
  canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
881
917
  } : null,
882
918
  canonicalOperations: {
919
+ applyCanonicalSectionProperties: (patch) => {
920
+ ensureView();
921
+ const fail = (message) => {
922
+ refuse(message, CANONICAL_GAP.sectionProperties);
923
+ return {
924
+ status: "refused",
925
+ gap: CANONICAL_GAP.sectionProperties,
926
+ message
927
+ };
928
+ };
929
+ if (editorSession.type === "refused") return fail(editorSession.reason);
930
+ if (editorSession.type !== "canonical") {
931
+ if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for section changes.");
932
+ return null;
933
+ }
934
+ if (!view || deps.getReadOnly() || isDestroying) return fail("The document is not editable.");
935
+ const session = editorSession.session;
936
+ if (session.isComposing) return fail("Section properties cannot change during composition.");
937
+ const prepared = session.prepareOperations(view.state, [createCanonicalSectionPropertiesOperation(session.document, patch)]);
938
+ if (prepared.isErr()) return fail(prepared.error.message);
939
+ let failureMessage = "The section projection could not publish.";
940
+ if (!publishCommit(prepared.value, (message) => {
941
+ failureMessage = message;
942
+ })) return fail(failureMessage);
943
+ return {
944
+ status: "applied",
945
+ version: session.version
946
+ };
947
+ },
948
+ applyCanonicalComment: (request) => {
949
+ ensureView();
950
+ const fail = (message, retry = "never") => {
951
+ if (retry === "never") refuse(message, CANONICAL_GAP.comments);
952
+ return {
953
+ status: "refused",
954
+ gap: CANONICAL_GAP.comments,
955
+ message,
956
+ retry
957
+ };
958
+ };
959
+ if (editorSession.type === "refused") return fail(editorSession.reason);
960
+ if (editorSession.type !== "canonical") {
961
+ if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for comment changes.");
962
+ return null;
963
+ }
964
+ if (!view || deps.getReadOnly()) return fail("The document is not editable.");
965
+ const session = editorSession.session;
966
+ if (session.isComposing) return fail("Comments cannot change during composition.", "afterComposition");
967
+ let command;
968
+ if (request.type === "create") {
969
+ const id = freshCommentId(session.document);
970
+ if (id.isErr()) return fail(id.error.message);
971
+ let anchor;
972
+ switch (request.anchor.kind) {
973
+ case "selection": {
974
+ const projection = session.projectStory(request.anchor.story);
975
+ if (projection.isErr()) return fail(projection.error.message);
976
+ const from = projection.value.addressAt(request.anchor.from);
977
+ const to = projection.value.addressAt(request.anchor.to);
978
+ if (from.isErr()) return fail(from.error.message);
979
+ if (to.isErr()) return fail(to.error.message);
980
+ anchor = request.anchor.from === request.anchor.to ? {
981
+ kind: "point",
982
+ at: from.value
983
+ } : {
984
+ kind: "range",
985
+ from: from.value,
986
+ to: to.value
987
+ };
988
+ break;
989
+ }
990
+ case "reply":
991
+ anchor = {
992
+ kind: "reply",
993
+ parentId: request.anchor.parentId
994
+ };
995
+ break;
996
+ case "revision":
997
+ anchor = {
998
+ kind: "revision",
999
+ story: request.anchor.story,
1000
+ revisionId: request.anchor.revisionId
1001
+ };
1002
+ break;
1003
+ default: return request.anchor;
1004
+ }
1005
+ command = {
1006
+ type: "create",
1007
+ anchor,
1008
+ comment: {
1009
+ id: id.value,
1010
+ author: request.author,
1011
+ done: false,
1012
+ date: request.date ?? (/* @__PURE__ */ new Date()).toISOString(),
1013
+ content: canonicalCommentBody(session.document, request.text)
1014
+ }
1015
+ };
1016
+ } else command = request;
1017
+ const compiled = compileCanonicalComments({
1018
+ document: session.document,
1019
+ command
1020
+ });
1021
+ if (compiled.isErr()) return fail(compiled.error.message);
1022
+ if (compiled.value.ops.length > 0) {
1023
+ const prepared = session.prepareOperations(view.state, compiled.value.ops);
1024
+ if (prepared.isErr()) return fail(prepared.error.message);
1025
+ if (!publishCommit(prepared.value)) return fail("The comment projection could not publish.");
1026
+ }
1027
+ return {
1028
+ status: "applied",
1029
+ comments: session.getCommittedComments(),
1030
+ ...compiled.value.commentId === void 0 ? {} : { commentId: compiled.value.commentId }
1031
+ };
1032
+ },
883
1033
  applyCanonicalDocumentOperations: (options) => {
884
1034
  ensureView();
885
1035
  return getPublicOperations()?.apply(options) ?? null;
@@ -914,6 +1064,7 @@ const createHiddenEditorManager = (deps) => {
914
1064
  applyCanonicalStoryHistory: ({ view: storyView, story, direction }) => {
915
1065
  if (story === OP_STORIES.MAIN && storyView === view) return history(direction);
916
1066
  if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
1067
+ syncCanonicalMode();
917
1068
  const session = editorSession.session;
918
1069
  if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
919
1070
  const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
@@ -945,6 +1096,7 @@ const createHiddenEditorManager = (deps) => {
945
1096
  },
946
1097
  replaceCanonicalStoryText: ({ view: storyView, story, intent }) => {
947
1098
  if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
1099
+ syncCanonicalMode();
948
1100
  const prepared = editorSession.session.prepareReplace(storyView.state, {
949
1101
  ...intent,
950
1102
  story
@@ -959,7 +1111,8 @@ const createHiddenEditorManager = (deps) => {
959
1111
  isDestroying: () => isDestroying,
960
1112
  ensureView,
961
1113
  isViewRequested
962
- })
1114
+ }),
1115
+ isCanonicalComposing: () => editorSession.type === "canonical" && editorSession.session.isComposing
963
1116
  };
964
1117
  };
965
1118
  //#endregion
@@ -16,7 +16,7 @@ type NoteEditorManagerDeps = {
16
16
  getDocument: () => document_d_exports.Document | null;
17
17
  getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
18
18
  getExperimentalSession?: (() => "canonical" | undefined) | undefined;
19
- onSessionRefusal?: ((reason: string, gap: CanonicalGap) => void) | undefined;
19
+ onSessionRefusal?: ((reason: string, gap: CanonicalGap, error?: Error) => void) | undefined;
20
20
  getHost: () => HTMLElement | null;
21
21
  getPlugins?: (() => Plugin[]) | undefined;
22
22
  getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
@@ -7,11 +7,13 @@ import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js"
7
7
  import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
8
8
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
9
9
  import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
10
+ import { noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
10
11
  import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
11
- import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
12
+ import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
12
13
  import { schema } from "../prosemirror/schema/index.js";
13
14
  import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
14
15
  import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
16
+ import { CanonicalSessionError } from "./canonicalSession.js";
15
17
  import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
16
18
  import { OP_STORIES } from "@stll/docx-core/ops";
17
19
  import { EditorState, TextSelection } from "prosemirror-state";
@@ -88,11 +90,12 @@ const createNoteEditorManager = (deps) => {
88
90
  mounted.clear();
89
91
  active = null;
90
92
  };
93
+ const getOwnedDocument = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? null : deps.getDocument();
91
94
  const sync = () => {
92
95
  const host = deps.getHost();
93
96
  if (!host) return;
94
- if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
95
- const document = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? deps.getDocument() : deps.getDocument();
97
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
98
+ const document = getOwnedDocument();
96
99
  const styles = deps.getStyles();
97
100
  const theme = deps.getTheme();
98
101
  const numbering = document?.package.numbering;
@@ -116,7 +119,7 @@ const createNoteEditorManager = (deps) => {
116
119
  const existing = mounted.get(key);
117
120
  if (existing) {
118
121
  if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
119
- if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) {
122
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
120
123
  const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
121
124
  kind: storyKey.kind,
122
125
  id: storyKey.noteId
@@ -176,7 +179,7 @@ const createNoteEditorManager = (deps) => {
176
179
  },
177
180
  getView: () => view,
178
181
  getApi: () => deps.getCanonicalApi?.() ?? null,
179
- enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories),
182
+ enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting),
180
183
  onRefusal: deps.onSessionRefusal,
181
184
  onSelectionChange: () => deps.onTransaction?.({
182
185
  ...storyKey,
@@ -185,11 +188,11 @@ const createNoteEditorManager = (deps) => {
185
188
  selectionChanged: true
186
189
  })
187
190
  });
188
- const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
191
+ const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
189
192
  kind: storyKey.kind,
190
193
  id: storyKey.noteId
191
194
  }) : null;
192
- if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories) && !canonicalProjection) {
195
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !canonicalProjection) {
193
196
  manager.destroy();
194
197
  mountNode.remove();
195
198
  continue;
@@ -198,16 +201,20 @@ const createNoteEditorManager = (deps) => {
198
201
  ...canonical.props,
199
202
  state: canonicalProjection ? EditorState.create({
200
203
  doc: canonicalProjection,
201
- plugins: [createDocumentStylesPlugin(styles), createDocumentNumberingPlugin(numbering)]
204
+ plugins: [createDocumentStyleContextPlugin(styles), createDocumentNumberingPlugin(numbering)]
202
205
  }) : buildInitialState(proseDocument, styles, numbering, manager, externalPlugins),
203
206
  dispatchTransaction(transaction) {
204
207
  if (canonical.dispatch(transaction)) return;
205
- view.updateState(view.state.apply(transaction));
208
+ const nextState = view.state.apply(transaction);
209
+ const docChanged = !nextState.doc.eq(view.state.doc);
210
+ view.updateState(nextState);
211
+ const noteIssue = noteReferenceTransactionIssue(transaction);
212
+ if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
206
213
  const mountedStory = mounted.get(key);
207
- if (mountedStory && transaction.docChanged) mountedStory.dirty = true;
214
+ if (mountedStory && docChanged) mountedStory.dirty = true;
208
215
  deps.onTransaction?.({
209
216
  ...storyKey,
210
- docChanged: transaction.docChanged,
217
+ docChanged,
211
218
  selectionChanged: transaction.selectionSet,
212
219
  view
213
220
  });
@@ -245,9 +252,17 @@ const createNoteEditorManager = (deps) => {
245
252
  destroy,
246
253
  getActive: () => active,
247
254
  getView: (story) => mounted.get(storyMapKey(story))?.view ?? null,
248
- listStories: () => enumerateDocumentNoteStories(deps.getDocument()),
255
+ listStories: () => enumerateDocumentNoteStories(getOwnedDocument()),
249
256
  snapshotDocument: (document) => {
250
- if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.secondaryStories)) return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
257
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
258
+ const canonical = deps.getCanonicalApi?.()?.getCanonicalDocument();
259
+ if (canonical) return canonical;
260
+ throw new CanonicalSessionError({
261
+ gap: CANONICAL_GAP.authorityRouting,
262
+ reason: "refused",
263
+ message: "Canonical story snapshot is unavailable."
264
+ });
265
+ }
251
266
  let footnotes = document.package.footnotes;
252
267
  let endnotes = document.package.endnotes;
253
268
  let footnotesChanged = false;
@@ -1,5 +1,5 @@
1
1
  import { BUILT_IN_DEFAULT_PARAGRAPH_STYLE_NAME, resolveDefaultParagraphStyle } from "./defaultParagraphStyle.js";
2
- import { headingLevelOf } from "@stll/docx-core/model";
2
+ import { headingLevelOf, headingOutlineLevel } from "@stll/docx-core/model";
3
3
  //#region src/docx/builtInStyles.ts
4
4
  /**
5
5
  * Whether a paragraph is a heading, and of which level, without reading the
@@ -134,20 +134,27 @@ const headingOutlineLevelFromStyleName = (name) => {
134
134
  const CANONICAL_BY_NORMALIZED = new Map(Object.values(BUILT_IN_STYLE_NAME).map((name) => [normalizeStyleName(name), name]));
135
135
  const asBuiltInName = (normalized) => CANONICAL_BY_NORMALIZED.get(normalized);
136
136
  /**
137
- * The outline level a style chain sets: the style's own `w:outlineLvl`, else
138
- * the nearest ancestor's (17.7.1). `styleParser` already flattens `w:basedOn`
139
- * for a parsed package, but a style set built in memory carries the raw chain,
140
- * so the walk keeps both kinds of input on the same answer. `seen` guards the
141
- * circular `basedOn` a malformed package can contain.
137
+ * The effective outline contribution of a style chain: the nearest explicit
138
+ * `w:outlineLvl` wins across the chain; only when none exists does the nearest
139
+ * built-in heading name supply its implicit level. `styleParser` already flattens
140
+ * `w:basedOn` for a parsed package, but a style set built in memory carries the
141
+ * raw chain, so the walk keeps both kinds of input on the same answer. `seen`
142
+ * guards the circular `basedOn` a malformed package can contain.
142
143
  */
143
144
  const inheritedOutlineLevel = (style, styleById) => {
144
145
  const seen = /* @__PURE__ */ new Set();
145
146
  let current = style;
147
+ let nearestImplicitHeadingLevel;
146
148
  while (current && !seen.has(current.styleId)) {
147
149
  seen.add(current.styleId);
148
150
  if (current.pPr?.outlineLevel !== void 0) return current.pPr.outlineLevel;
151
+ if (nearestImplicitHeadingLevel === void 0) {
152
+ const namedLevel = headingOutlineLevelFromStyleName(current.name);
153
+ if (namedLevel !== void 0) nearestImplicitHeadingLevel = headingOutlineLevel(namedLevel);
154
+ }
149
155
  current = current.basedOn === void 0 ? void 0 : styleById.get(current.basedOn);
150
156
  }
157
+ return nearestImplicitHeadingLevel;
151
158
  };
152
159
  /** The level a heading style is indexed under, or undefined if it is not one. */
153
160
  const headingLevelForIndex = (namedLevel, statedLevel) => {
@@ -35,9 +35,11 @@ declare const CONTAINER_CHILDREN: {
35
35
  readonly "w:fldSimple": readonly ["bdo", "bookmarkEnd", "bookmarkStart", "commentRangeEnd", "commentRangeStart", "customXml", "customXmlDelRangeEnd", "customXmlDelRangeStart", "customXmlInsRangeEnd", "customXmlInsRangeStart", "customXmlMoveFromRangeEnd", "customXmlMoveFromRangeStart", "customXmlMoveToRangeEnd", "customXmlMoveToRangeStart", "del", "dir", "fldData", "fldSimple", "hyperlink", "ins", "moveFrom", "moveFromRangeEnd", "moveFromRangeStart", "moveTo", "moveToRangeEnd", "moveToRangeStart", "permEnd", "permStart", "proofErr", "r", "sdt", "smartTag", "subDoc"];
36
36
  readonly "block-content": readonly ["altChunk", "bookmarkEnd", "bookmarkStart", "commentRangeEnd", "commentRangeStart", "customXml", "customXmlDelRangeEnd", "customXmlDelRangeStart", "customXmlInsRangeEnd", "customXmlInsRangeStart", "customXmlMoveFromRangeEnd", "customXmlMoveFromRangeStart", "customXmlMoveToRangeEnd", "customXmlMoveToRangeStart", "del", "ins", "moveFrom", "moveFromRangeEnd", "moveFromRangeStart", "moveTo", "moveToRangeEnd", "moveToRangeStart", "p", "permEnd", "permStart", "proofErr", "sdt", "sectPr", "tbl", "tcPr"];
37
37
  };
38
+ /** WordprocessingML children permitted directly inside CT_RunTrackChange. */
39
+ declare const TRACKED_RUN_WORDPROCESSING_CHILDREN: readonly ["bdo", "bookmarkEnd", "bookmarkStart", "commentRangeEnd", "commentRangeStart", "customXml", "customXmlDelRangeEnd", "customXmlDelRangeStart", "customXmlInsRangeEnd", "customXmlInsRangeStart", "customXmlMoveFromRangeEnd", "customXmlMoveFromRangeStart", "customXmlMoveToRangeEnd", "customXmlMoveToRangeStart", "del", "dir", "ins", "moveFrom", "moveFromRangeEnd", "moveFromRangeStart", "moveTo", "moveToRangeEnd", "moveToRangeStart", "permEnd", "permStart", "proofErr", "r", "sdt", "smartTag"];
38
40
  /** A container the shared child dispatcher covers. */
39
41
  type DispatchedContainer = keyof typeof CONTAINER_CHILDREN;
40
42
  /** Every child name the schema declares for `Container`. */
41
43
  type DeclaredChild<Container extends DispatchedContainer> = (typeof CONTAINER_CHILDREN)[Container][number];
42
44
  //#endregion
43
- export { CONTAINER_CHILDREN, DeclaredChild, DispatchedContainer };
45
+ export { CONTAINER_CHILDREN, DeclaredChild, DispatchedContainer, TRACKED_RUN_WORDPROCESSING_CHILDREN };
@@ -260,5 +260,37 @@ const CONTAINER_CHILDREN = {
260
260
  ],
261
261
  ...SEQUENCE_CHILDREN
262
262
  };
263
+ /** WordprocessingML children permitted directly inside CT_RunTrackChange. */
264
+ const TRACKED_RUN_WORDPROCESSING_CHILDREN = [
265
+ "bdo",
266
+ "bookmarkEnd",
267
+ "bookmarkStart",
268
+ "commentRangeEnd",
269
+ "commentRangeStart",
270
+ "customXml",
271
+ "customXmlDelRangeEnd",
272
+ "customXmlDelRangeStart",
273
+ "customXmlInsRangeEnd",
274
+ "customXmlInsRangeStart",
275
+ "customXmlMoveFromRangeEnd",
276
+ "customXmlMoveFromRangeStart",
277
+ "customXmlMoveToRangeEnd",
278
+ "customXmlMoveToRangeStart",
279
+ "del",
280
+ "dir",
281
+ "ins",
282
+ "moveFrom",
283
+ "moveFromRangeEnd",
284
+ "moveFromRangeStart",
285
+ "moveTo",
286
+ "moveToRangeEnd",
287
+ "moveToRangeStart",
288
+ "permEnd",
289
+ "permStart",
290
+ "proofErr",
291
+ "r",
292
+ "sdt",
293
+ "smartTag"
294
+ ];
263
295
  //#endregion
264
- export { CONTAINER_CHILDREN };
296
+ export { CONTAINER_CHILDREN, TRACKED_RUN_WORDPROCESSING_CHILDREN };
@@ -231,8 +231,20 @@ function finalizeComplexField(ctx) {
231
231
  * @returns The display text
232
232
  */
233
233
  function getFieldDisplayValue(field) {
234
- if (field.type === "simpleField") return field.content.filter((c) => "content" in c).map((run) => getRunText(run)).join("");
235
- return field.fieldResult.map((run) => getRunText(run)).join("");
234
+ const displayText = (content) => content.map((child) => {
235
+ switch (child.type) {
236
+ case "run": return getRunText(child);
237
+ case "hyperlink": return displayText(child.children);
238
+ case "inlineWrapper":
239
+ case "insertion":
240
+ case "deletion":
241
+ case "moveFrom":
242
+ case "moveTo": return displayText(child.content);
243
+ case "preservedInline": return child.text;
244
+ default: return "";
245
+ }
246
+ }).join("");
247
+ return displayText(field.type === "simpleField" ? field.content : field.fieldResult);
236
248
  }
237
249
  /**
238
250
  * Helper to get text from a run (simplified)
@@ -86,7 +86,7 @@ declare const HYPERLINK_CHILD_HANDLERS: {
86
86
  readonly permEnd: "capture";
87
87
  readonly permStart: "capture";
88
88
  readonly proofErr: "capture";
89
- readonly sdt: "capture";
89
+ readonly sdt: (child: XmlElement, { push }: HyperlinkChildContext) => void;
90
90
  readonly subDoc: "capture";
91
91
  };
92
92
  /**
@@ -1,6 +1,7 @@
1
1
  import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
2
2
  import { CAPTURE, dispatchChildrenWithContext, ownedElsewhere, withPreservedChildren } from "./containerChildren.js";
3
3
  import { inlineWrapperOf } from "./inlineWrapperParser.js";
4
+ import { preserveLinkedSdt } from "./linkedSdtPreservation.js";
4
5
  import { preserveInlineChild, preservedInlineCapture } from "./preservedRunContent.js";
5
6
  import { standalonePreviewLedger } from "./previewBudget.js";
6
7
  import { RELATIONSHIP_TYPES, resolveRelationshipIdOfType } from "./relsParser.js";
@@ -9,6 +10,22 @@ import { runHoldsPayload } from "./runPayload.js";
9
10
  import { getAttribute, mergeXmlnsDeclarations, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
10
11
  //#region src/docx/hyperlinkParser.ts
11
12
  /**
13
+ * Hyperlink Parser - Parse hyperlinks (w:hyperlink) with URL resolution
14
+ *
15
+ * OOXML Reference:
16
+ * - Hyperlink element: w:hyperlink
17
+ * - Attributes:
18
+ * - r:id - Relationship ID for external link (resolves via .rels)
19
+ * - w:anchor - Internal bookmark name
20
+ * - w:tooltip - Tooltip/title text
21
+ * - w:tgtFrame - Target frame (_blank, _self, etc.)
22
+ * - w:history - Whether to add to history
23
+ * - w:docLocation - Location within a document
24
+ *
25
+ * External links use r:id to reference a relationship in document.xml.rels
26
+ * Internal links use w:anchor to reference a bookmark in the same document
27
+ */
28
+ /**
12
29
  * Parse bookmark start (w:bookmarkStart)
13
30
  *
14
31
  * Used for internal hyperlink targets within the document.
@@ -169,7 +186,9 @@ const HYPERLINK_CHILD_HANDLERS = {
169
186
  permEnd: CAPTURE,
170
187
  permStart: CAPTURE,
171
188
  proofErr: CAPTURE,
172
- sdt: CAPTURE,
189
+ sdt: (child, { push }) => {
190
+ push(preserveLinkedSdt(child));
191
+ },
173
192
  subDoc: CAPTURE
174
193
  };
175
194
  const LINKED_SMART_TAG_PROPERTIES_OWNER = ownedElsewhere({
@@ -138,14 +138,14 @@ declare const SIMPLE_FIELD_CONTENT: {
138
138
  readonly commentRangeStart: false;
139
139
  readonly commentReference: false;
140
140
  readonly complexField: false;
141
- readonly deletion: false;
141
+ readonly deletion: true;
142
142
  readonly inlineSdt: false;
143
- readonly insertion: false;
143
+ readonly insertion: true;
144
144
  readonly mathEquation: false;
145
- readonly moveFrom: false;
145
+ readonly moveFrom: true;
146
146
  readonly moveFromRangeEnd: false;
147
147
  readonly moveFromRangeStart: false;
148
- readonly moveTo: false;
148
+ readonly moveTo: true;
149
149
  readonly moveToRangeEnd: false;
150
150
  readonly moveToRangeStart: false;
151
151
  readonly simpleField: false;
@@ -137,14 +137,14 @@ const SIMPLE_FIELD_CONTENT = {
137
137
  commentRangeStart: false,
138
138
  commentReference: false,
139
139
  complexField: false,
140
- deletion: false,
140
+ deletion: true,
141
141
  inlineSdt: false,
142
- insertion: false,
142
+ insertion: true,
143
143
  mathEquation: false,
144
- moveFrom: false,
144
+ moveFrom: true,
145
145
  moveFromRangeEnd: false,
146
146
  moveFromRangeStart: false,
147
- moveTo: false,
147
+ moveTo: true,
148
148
  moveToRangeEnd: false,
149
149
  moveToRangeStart: false,
150
150
  simpleField: false
@@ -0,0 +1,10 @@
1
+ import { XmlElement } from "./xmlParser.js";
2
+ //#region src/docx/linkedSdtPreservation.d.ts
3
+ declare const UnrepresentableLinkedSdtRevisionError_base: import("better-result").TaggedErrorClass<"UnrepresentableLinkedSdtRevisionError">;
4
+ declare class UnrepresentableLinkedSdtRevisionError extends UnrepresentableLinkedSdtRevisionError_base<{
5
+ message: string;
6
+ }> {}
7
+ /** Capture only the unsupported hyperlink child, never its enclosing revision. */
8
+ declare const preserveLinkedSdt: (root: XmlElement) => import("@stll/docx-core/model").PreservedInline;
9
+ //#endregion
10
+ export { UnrepresentableLinkedSdtRevisionError, preserveLinkedSdt };