@stll/folio-core 0.11.0 → 0.12.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 (194) hide show
  1. package/dist/ai-edits/apply.js +602 -50
  2. package/dist/ai-edits/block-identity.d.ts +4 -0
  3. package/dist/ai-edits/block-identity.js +9 -0
  4. package/dist/ai-edits/blockRange.d.ts +28 -1
  5. package/dist/ai-edits/blockRange.js +67 -1
  6. package/dist/ai-edits/headless.d.ts +4 -4
  7. package/dist/ai-edits/headless.js +9 -9
  8. package/dist/ai-edits/index.d.ts +2 -2
  9. package/dist/ai-edits/index.js +2 -2
  10. package/dist/ai-edits/read.d.ts +7 -7
  11. package/dist/ai-edits/read.js +110 -3
  12. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  13. package/dist/ai-edits/table-cell-mutations.js +237 -0
  14. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  15. package/dist/ai-edits/table-mutation-plan.js +90 -0
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +100 -0
  17. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  18. package/dist/ai-edits/table-targets.d.ts +32 -0
  19. package/dist/ai-edits/table-targets.js +70 -0
  20. package/dist/ai-edits/types.d.ts +34 -0
  21. package/dist/compat/eigenpal.js +1 -1
  22. package/dist/content-controls/mutateContentControls.js +1 -1
  23. package/dist/controller/activeEditorStory.d.ts +36 -0
  24. package/dist/controller/activeEditorStory.js +30 -0
  25. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  26. package/dist/controller/contentControlWidgetController.js +141 -0
  27. package/dist/controller/fontReadiness.js +2 -0
  28. package/dist/controller/headerFooterEditorManager.js +1 -1
  29. package/dist/controller/hiddenEditorApi.js +2 -2
  30. package/dist/controller/hiddenEditorManager.d.ts +12 -1
  31. package/dist/controller/hiddenEditorManager.js +32 -11
  32. package/dist/controller/layoutPipeline.d.ts +2 -0
  33. package/dist/controller/layoutPipeline.js +16 -1
  34. package/dist/controller/noteEditorManager.d.ts +36 -0
  35. package/dist/controller/noteEditorManager.js +210 -0
  36. package/dist/document-operations.d.ts +35 -3
  37. package/dist/document-operations.js +161 -3
  38. package/dist/docx/blockContentParser.js +2 -2
  39. package/dist/docx/commentParser.js +6 -1
  40. package/dist/docx/conformance.js +8 -1
  41. package/dist/docx/documentGrid.d.ts +8 -0
  42. package/dist/docx/documentGrid.js +8 -0
  43. package/dist/docx/drawingUtils.js +1 -1
  44. package/dist/docx/ensureParaIds.js +1 -1
  45. package/dist/docx/fieldParser.js +1 -1
  46. package/dist/docx/notePropertiesParser.js +1 -1
  47. package/dist/docx/numberingParser.js +1 -1
  48. package/dist/docx/paragraphParser.js +63 -58
  49. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  50. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  51. package/dist/docx/paragraphTraversal.js +1 -1
  52. package/dist/docx/parser.js +3 -3
  53. package/dist/docx/rezip.js +1 -1
  54. package/dist/docx/runParser.js +4 -2
  55. package/dist/docx/sdtProperties.js +1 -1
  56. package/dist/docx/sectionParser.js +1 -1
  57. package/dist/docx/selectiveSave.js +1 -1
  58. package/dist/docx/serializer/commentSerializer.js +1 -2
  59. package/dist/docx/serializer/documentSerializer.js +2 -2
  60. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  61. package/dist/docx/serializer/noteSerializer.js +2 -2
  62. package/dist/docx/serializer/paragraphSerializer.js +7 -1
  63. package/dist/docx/serializer/runSerializer.js +4 -2
  64. package/dist/docx/serializer/stylesSerializer.js +1 -1
  65. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  66. package/dist/docx/serializer/tableSerializer.js +17 -13
  67. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  68. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  69. package/dist/docx/server/boundedArchive.d.ts +14 -3
  70. package/dist/docx/server/boundedArchive.js +56 -11
  71. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  72. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  73. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  74. package/dist/docx/server/inspectDocxPackage.js +217 -0
  75. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  76. package/dist/docx/server/validateDocxConformance.js +336 -0
  77. package/dist/docx/settingsParser.js +11 -1
  78. package/dist/docx/shapeParser.js +1 -1
  79. package/dist/docx/styleParser.js +4 -2
  80. package/dist/docx/tableParser.js +18 -7
  81. package/dist/docx/textBoxParser.d.ts +3 -3
  82. package/dist/docx/textBoxParser.js +16 -12
  83. package/dist/docx/xmlSafety.d.ts +5 -0
  84. package/dist/docx/xmlSafety.js +9 -0
  85. package/dist/fields/resolveFieldValues.js +1 -3
  86. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  87. package/dist/i18n/messages/catalogs.gen.js +17 -0
  88. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  89. package/dist/index.js +1 -1
  90. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  91. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  92. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  93. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  94. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  95. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  96. package/dist/layout-bridge/convert/toFlowBlocks.js +136 -20
  97. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  98. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  99. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  100. package/dist/layout-engine/index.d.ts +2 -2
  101. package/dist/layout-engine/index.js +43 -28
  102. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  103. package/dist/layout-engine/justificationCompatibility.js +8 -0
  104. package/dist/layout-engine/keep-together.js +11 -1
  105. package/dist/layout-engine/measure/cache.js +21 -5
  106. package/dist/layout-engine/measure/lineBreakProvider.js +53 -34
  107. package/dist/layout-engine/measure/measureBlocks.js +6 -3
  108. package/dist/layout-engine/measure/measureContainer.js +1 -1
  109. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  110. package/dist/layout-engine/measure/measureHelpers.js +3 -3
  111. package/dist/layout-engine/measure/measureParagraph.js +69 -25
  112. package/dist/layout-engine/measure/measureProvider.js +4 -3
  113. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  114. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  115. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  116. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  117. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  118. package/dist/layout-engine/paginator.js +5 -1
  119. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  120. package/dist/layout-engine/paragraphSpacing.js +107 -13
  121. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  122. package/dist/layout-engine/types.d.ts +26 -13
  123. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  124. package/dist/layout-painter/renderPage.d.ts +5 -2
  125. package/dist/layout-painter/renderPage.js +56 -12
  126. package/dist/layout-painter/renderParagraph.js +22 -6
  127. package/dist/layout-painter/renderTable.d.ts +5 -1
  128. package/dist/layout-painter/renderTable.js +5 -2
  129. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  130. package/dist/layout-painter/renderTextBox.js +25 -14
  131. package/dist/managers/DocumentLoaderManager.js +1 -1
  132. package/dist/model.js +1 -1
  133. package/dist/prosemirror/attrs/index.d.ts +4 -2
  134. package/dist/prosemirror/attrs/index.js +154 -18
  135. package/dist/prosemirror/commands/comments.d.ts +3 -3
  136. package/dist/prosemirror/commands/comments.js +248 -12
  137. package/dist/prosemirror/commands/contentControls.js +1 -1
  138. package/dist/prosemirror/commands/index.js +1 -1
  139. package/dist/prosemirror/commands/pageBreak.js +1 -1
  140. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  141. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  142. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  143. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  144. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  145. package/dist/prosemirror/conversion/fromProseDoc.js +286 -61
  146. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  147. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  148. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  149. package/dist/prosemirror/conversion/toProseDoc.js +347 -98
  150. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  151. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  152. package/dist/prosemirror/extensions/core/ParagraphExtension.js +4 -1
  153. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  154. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  155. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  156. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  157. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  158. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  159. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  160. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  161. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +24 -1
  162. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  163. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  164. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  165. package/dist/prosemirror/extensions/nodes/TableExtension.js +9 -3
  166. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  167. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  168. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  169. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  170. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +34 -8
  171. package/dist/prosemirror/plugins/contentControlWidgets.js +125 -91
  172. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  173. package/dist/prosemirror/plugins/suggestionMode.js +1 -1
  174. package/dist/prosemirror/schema/index.d.ts +2 -2
  175. package/dist/prosemirror/schema/marks.d.ts +5 -1
  176. package/dist/prosemirror/schema/nodes.d.ts +64 -7
  177. package/dist/prosemirror/selectionState.js +1 -0
  178. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  179. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  180. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  181. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  182. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  183. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  184. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  185. package/dist/prosemirror/validation.js +9 -1
  186. package/dist/server.d.ts +6 -2
  187. package/dist/server.js +5 -1
  188. package/dist/utils/fontFamilyMerge.js +9 -11
  189. package/dist/utils/fontLoader.js +3 -2
  190. package/dist/utils/fontResolver.js +22 -4
  191. package/dist/utils/fontWeights.d.ts +1 -1
  192. package/dist/utils/fontWeights.js +1 -1
  193. package/dist/utils/paragraphFormattingMerge.js +1 -0
  194. package/package.json +1 -1
@@ -0,0 +1,141 @@
1
+ import { CONTENT_CONTROL_WIDGET_EVENT_NAME, dispatchDatePick, dispatchDropdownPick, handleContentControlWidgetClick } from "../prosemirror/plugins/contentControlWidgets.js";
2
+ import { Subscribable } from "../managers/Subscribable.js";
3
+ //#region src/controller/contentControlWidgetController.ts
4
+ const CLOSED_SNAPSHOT = { status: "closed" };
5
+ const PICKER_GAP_PX = 4;
6
+ const isListItem = (value) => {
7
+ if (typeof value !== "object" || value === null) return false;
8
+ if (!("displayText" in value) || !("value" in value)) return false;
9
+ return typeof value.displayText === "string" && typeof value.value === "string";
10
+ };
11
+ const parseContentControlListItems = (raw) => {
12
+ if (!raw) return [];
13
+ let parsed;
14
+ try {
15
+ parsed = JSON.parse(raw);
16
+ } catch {
17
+ return [];
18
+ }
19
+ if (!Array.isArray(parsed)) return [];
20
+ return parsed.filter(isListItem);
21
+ };
22
+ const pickerPosition = (event) => {
23
+ const rect = event.anchor.getBoundingClientRect();
24
+ return {
25
+ x: rect.left,
26
+ y: rect.bottom + PICKER_GAP_PX
27
+ };
28
+ };
29
+ const isContentControlWidgetEvent = (value) => {
30
+ if (typeof value !== "object" || value === null || !("kind" in value)) return false;
31
+ if (!("tag" in value) || typeof value.tag !== "string" || !("pmPos" in value) || typeof value.pmPos !== "number" || !("anchor" in value) || typeof value.anchor !== "object" || value.anchor === null || !("getBoundingClientRect" in value.anchor) || typeof value.anchor.getBoundingClientRect !== "function") return false;
32
+ if (value.kind === "dropdownOpen") return "sdtType" in value && (value.sdtType === "dropdown" || value.sdtType === "comboBox") && "listItemsJson" in value && (value.listItemsJson === void 0 || typeof value.listItemsJson === "string");
33
+ if (value.kind === "datePick") return "currentValue" in value && (value.currentValue === void 0 || typeof value.currentValue === "string");
34
+ return value.kind === "refused" && "sdtType" in value && "error" in value;
35
+ };
36
+ var ContentControlWidgetController = class extends Subscribable {
37
+ options;
38
+ view = null;
39
+ viewDom = null;
40
+ eventRoot = null;
41
+ ownerWindow = null;
42
+ constructor(options = {}) {
43
+ super(CLOSED_SNAPSHOT);
44
+ this.options = options;
45
+ }
46
+ bind(view, eventRoot = null) {
47
+ if (this.view === view && this.eventRoot === eventRoot) return;
48
+ this.unbindView();
49
+ this.view = view;
50
+ this.viewDom = view?.dom ?? null;
51
+ this.eventRoot = eventRoot;
52
+ this.viewDom?.addEventListener(CONTENT_CONTROL_WIDGET_EVENT_NAME, this.onDomEvent);
53
+ this.eventRoot?.addEventListener("click", this.onPaintedClick);
54
+ }
55
+ handleWidgetEvent(event) {
56
+ if (event.kind === "refused") {
57
+ this.close();
58
+ this.options.onRefused?.(event);
59
+ return;
60
+ }
61
+ if (event.kind === "dropdownOpen") {
62
+ this.open({
63
+ status: "dropdown",
64
+ items: parseContentControlListItems(event.listItemsJson),
65
+ pmPos: event.pmPos,
66
+ position: pickerPosition(event)
67
+ });
68
+ return;
69
+ }
70
+ this.open({
71
+ status: "date",
72
+ currentValue: event.currentValue ?? null,
73
+ pmPos: event.pmPos,
74
+ position: pickerPosition(event)
75
+ });
76
+ }
77
+ pickDropdown(value) {
78
+ const snapshot = this.getSnapshot();
79
+ if (snapshot.status !== "dropdown" || !this.view) return false;
80
+ const changed = dispatchDropdownPick(this.view, snapshot.pmPos, value);
81
+ this.close();
82
+ return changed;
83
+ }
84
+ pickDate(value) {
85
+ const snapshot = this.getSnapshot();
86
+ if (snapshot.status !== "date" || !this.view || value.length === 0) return false;
87
+ const changed = dispatchDatePick(this.view, snapshot.pmPos, value);
88
+ this.close();
89
+ return changed;
90
+ }
91
+ close() {
92
+ this.removeDismissListeners();
93
+ if (this.getSnapshot().status !== "closed") this.setSnapshot(CLOSED_SNAPSHOT);
94
+ }
95
+ destroy() {
96
+ this.unbindView();
97
+ this.view = null;
98
+ }
99
+ onDomEvent = (event) => {
100
+ if (!("detail" in event)) return;
101
+ const detail = event.detail;
102
+ if (isContentControlWidgetEvent(detail)) this.handleWidgetEvent(detail);
103
+ };
104
+ onPaintedClick = (event) => {
105
+ if (!this.view || !isPaintedBodyClick(event.target)) return;
106
+ handleContentControlWidgetClick({
107
+ view: this.view,
108
+ event,
109
+ onEvent: (widgetEvent) => this.handleWidgetEvent(widgetEvent)
110
+ });
111
+ };
112
+ onKeyDown = (event) => {
113
+ if (event.key === "Escape") this.close();
114
+ };
115
+ onScroll = () => this.close();
116
+ open(snapshot) {
117
+ this.removeDismissListeners();
118
+ this.ownerWindow = this.viewDom?.ownerDocument.defaultView ?? null;
119
+ this.ownerWindow?.addEventListener("keydown", this.onKeyDown);
120
+ this.ownerWindow?.addEventListener("scroll", this.onScroll, true);
121
+ this.setSnapshot(snapshot);
122
+ }
123
+ removeDismissListeners() {
124
+ this.ownerWindow?.removeEventListener("keydown", this.onKeyDown);
125
+ this.ownerWindow?.removeEventListener("scroll", this.onScroll, true);
126
+ this.ownerWindow = null;
127
+ }
128
+ unbindView() {
129
+ this.close();
130
+ this.viewDom?.removeEventListener(CONTENT_CONTROL_WIDGET_EVENT_NAME, this.onDomEvent);
131
+ this.eventRoot?.removeEventListener("click", this.onPaintedClick);
132
+ this.viewDom = null;
133
+ this.eventRoot = null;
134
+ }
135
+ };
136
+ const isPaintedBodyClick = (target) => {
137
+ if (typeof target !== "object" || target === null || !("closest" in target) || typeof target.closest !== "function") return false;
138
+ return target.closest(".layout-page-content") !== null;
139
+ };
140
+ //#endregion
141
+ export { ContentControlWidgetController, parseContentControlListItems };
@@ -11,6 +11,8 @@ function documentFontsAreLoaded() {
11
11
  const INITIAL_LAYOUT_FONT_TIMEOUT_MS = 2e3;
12
12
  const DEFAULT_LAYOUT_FONT_FAMILY = "Calibri";
13
13
  const OFFICE_FONT_FAMILY_MAP = {
14
+ Aptos: "Lato",
15
+ "Aptos Display": "Lato",
14
16
  Arial: "Arimo",
15
17
  Calibri: "Carlito",
16
18
  Cambria: "Caladea",
@@ -1,4 +1,3 @@
1
- import { clearHeaderFooterVerbatimXml } from "../docx/headerFooterVerbatim.js";
2
1
  import { proseDocToBlocks } from "../prosemirror/conversion/fromProseDoc.js";
3
2
  import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js";
4
3
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
@@ -7,6 +6,7 @@ import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdA
7
6
  import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
8
7
  import { schema } from "../prosemirror/schema/index.js";
9
8
  import { headerFooterToProseDoc } from "../prosemirror/conversion/toProseDoc.js";
9
+ import { clearHeaderFooterVerbatimXml } from "../docx/headerFooterVerbatim.js";
10
10
  import { EditorState } from "prosemirror-state";
11
11
  import { EditorView } from "prosemirror-view";
12
12
  //#region src/controller/headerFooterEditorManager.ts
@@ -1,7 +1,7 @@
1
1
  import { fromProseDoc } from "../prosemirror/conversion/fromProseDoc.js";
2
- import { NodeSelection, Selection, TextSelection } from "prosemirror-state";
3
- import { redo, undo } from "prosemirror-history";
4
2
  import { CellSelection } from "prosemirror-tables";
3
+ import { redo, undo } from "prosemirror-history";
4
+ import { NodeSelection, Selection, TextSelection } from "prosemirror-state";
5
5
  //#region src/controller/hiddenEditorApi.ts
6
6
  /**
7
7
  * Hidden-editor imperative API
@@ -72,11 +72,22 @@ type HiddenEditorManagerDeps = {
72
72
  onTransaction: (transaction: Transaction, newState: EditorState) => void;
73
73
  onSelectionChange: (state: EditorState) => void;
74
74
  onKeyDown: (view: EditorView, event: KeyboardEvent) => boolean;
75
+ onCopy?: () => void;
76
+ onCut?: () => void;
77
+ onPaste?: () => void;
75
78
  onReadOnlyEditAttempt: () => void;
76
79
  onEditorViewReady: (view: EditorView) => void;
77
80
  onEditorViewDestroy: () => void;
78
81
  onRemoteSelectionsChange: (selections: HiddenProseMirrorRemoteSelection[]) => void;
79
82
  };
83
+ type PreventableDomEvent = {
84
+ preventDefault: () => void;
85
+ };
86
+ declare const createHiddenEditorClipboardHandlers: (deps: Pick<HiddenEditorManagerDeps, "getReadOnly" | "onCopy" | "onCut" | "onPaste" | "onReadOnlyEditAttempt">) => {
87
+ copy: () => boolean;
88
+ cut: (_view: unknown, event: PreventableDomEvent) => boolean;
89
+ paste: (_view: unknown, event: PreventableDomEvent) => boolean;
90
+ };
80
91
  type HiddenEditorManager = {
81
92
  /** Request the view (sets the requested flag, then attempts creation). */ensureView: () => void; /** Re-attempt a previously-requested-but-deferred creation (no-op otherwise). */
82
93
  retryViewCreation: () => void;
@@ -90,4 +101,4 @@ type HiddenEditorManager = {
90
101
  };
91
102
  declare const createHiddenEditorManager: (deps: HiddenEditorManagerDeps) => HiddenEditorManager;
92
103
  //#endregion
93
- export { CollaborationModules, CreateHiddenEditorStateOptions, HiddenEditorManager, HiddenEditorManagerDeps, HiddenProseMirrorCollaboration, HiddenProseMirrorRemoteSelection, collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState };
104
+ export { CollaborationModules, CreateHiddenEditorStateOptions, HiddenEditorManager, HiddenEditorManagerDeps, HiddenProseMirrorCollaboration, HiddenProseMirrorRemoteSelection, collectRemoteSelections, createHiddenEditorClipboardHandlers, createHiddenEditorManager, createHiddenEditorState };
@@ -1,6 +1,6 @@
1
1
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
2
2
  import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
3
- import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
3
+ import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
4
4
  import { schema } from "../prosemirror/schema/index.js";
5
5
  import { createEmptyDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
6
6
  import { createHiddenEditorApi } from "./hiddenEditorApi.js";
@@ -23,6 +23,7 @@ import { EditorView } from "prosemirror-view";
23
23
  * *when* to act) and drives this manager through the methods below.
24
24
  */
25
25
  const normalizeSeedState = (state) => ensureBaseDirectionInState(ensureParaIdsInState(state));
26
+ const normalizeLocalSeedState = (state) => ensureBaseDirectionInState(state);
26
27
  const isObjectRecord = (value) => typeof value === "object" && value !== null;
27
28
  const isYSyncState = (value, yjs) => {
28
29
  if (!isObjectRecord(value)) return false;
@@ -92,8 +93,9 @@ function createHiddenEditorState(options) {
92
93
  if (document) {
93
94
  const startedAt = performance.now();
94
95
  localDoc = styles === void 0 || styles === null ? toProseDoc(document) : toProseDoc(document, { styles });
96
+ localDoc = ensureParaIdsInDoc(localDoc);
95
97
  recordHiddenEditorPhase(reason, "to-prose-doc", performance.now() - startedAt);
96
- }
98
+ } else localDoc = ensureParaIdsInDoc(localDoc);
97
99
  const styleResolverPlugin = createDocumentStylesPlugin(styles ?? document?.package.styles);
98
100
  const plugins = [
99
101
  ...externalPlugins,
@@ -103,7 +105,7 @@ function createHiddenEditorState(options) {
103
105
  if (collaboration) {
104
106
  if (!collaborationModules) panic("Collaboration modules must be loaded before creating collaborative editor state.");
105
107
  if (collaboration.shouldSeed && collaboration.yXmlFragment.length === 0) {
106
- const seedState = normalizeSeedState(EditorState.create({
108
+ const seedState = normalizeLocalSeedState(EditorState.create({
107
109
  doc: localDoc,
108
110
  schema: activeSchema,
109
111
  plugins
@@ -131,7 +133,7 @@ function createHiddenEditorState(options) {
131
133
  return state;
132
134
  }
133
135
  const startedAt = performance.now();
134
- const state = normalizeSeedState(EditorState.create({
136
+ const state = normalizeLocalSeedState(EditorState.create({
135
137
  doc: localDoc,
136
138
  schema: activeSchema,
137
139
  plugins
@@ -149,6 +151,30 @@ function syncHiddenEditorAccessibility(view, readOnly) {
149
151
  if (!dom.hasAttribute("tabindex")) dom.tabIndex = 0;
150
152
  dom.setAttribute("aria-readonly", readOnly ? "true" : "false");
151
153
  }
154
+ const createHiddenEditorClipboardHandlers = (deps) => ({
155
+ copy: () => {
156
+ deps.onCopy?.();
157
+ return false;
158
+ },
159
+ cut: (_view, event) => {
160
+ if (!deps.getReadOnly()) {
161
+ deps.onCut?.();
162
+ return false;
163
+ }
164
+ deps.onReadOnlyEditAttempt();
165
+ event.preventDefault();
166
+ return true;
167
+ },
168
+ paste: (_view, event) => {
169
+ if (!deps.getReadOnly()) {
170
+ deps.onPaste?.();
171
+ return false;
172
+ }
173
+ deps.onReadOnlyEditAttempt();
174
+ event.preventDefault();
175
+ return true;
176
+ }
177
+ });
152
178
  const createHiddenEditorManager = (deps) => {
153
179
  let view = null;
154
180
  let isDestroying = false;
@@ -207,18 +233,13 @@ const createHiddenEditorManager = (deps) => {
207
233
  handleDOMEvents: {
208
234
  focus: () => false,
209
235
  blur: () => false,
236
+ ...createHiddenEditorClipboardHandlers(deps),
210
237
  beforeinput: (_view, event) => {
211
238
  if (!deps.getReadOnly()) return false;
212
239
  deps.onReadOnlyEditAttempt();
213
240
  event.preventDefault();
214
241
  return true;
215
242
  },
216
- paste: (_view, event) => {
217
- if (!deps.getReadOnly()) return false;
218
- deps.onReadOnlyEditAttempt();
219
- event.preventDefault();
220
- return true;
221
- },
222
243
  drop: (_view, event) => {
223
244
  if (!deps.getReadOnly()) return false;
224
245
  deps.onReadOnlyEditAttempt();
@@ -305,4 +326,4 @@ const createHiddenEditorManager = (deps) => {
305
326
  };
306
327
  };
307
328
  //#endregion
308
- export { collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState };
329
+ export { collectRemoteSelections, createHiddenEditorClipboardHandlers, createHiddenEditorManager, createHiddenEditorState };
@@ -31,6 +31,8 @@ type LayoutPipelineDeps<THfPMs> = {
31
31
  };
32
32
  margins: PageMargins;
33
33
  pageGap: number;
34
+ showMarginGuides: boolean;
35
+ marginGuideColor: string | undefined;
34
36
  syncCoordinator: LayoutSelectionGate;
35
37
  headerContent: document_d_exports.HeaderFooter | null | undefined;
36
38
  footerContent: document_d_exports.HeaderFooter | null | undefined;
@@ -1,6 +1,8 @@
1
1
  import "../layout-engine/types.js";
2
+ import { resolveEffectiveParagraphSpacingTree } from "../layout-engine/paragraphSpacing.js";
2
3
  import { renderPages } from "../layout-painter/renderPage.js";
3
4
  import { templatePreviewValuesKey } from "../prosemirror/plugins/templatePreviewValues.js";
5
+ import { resolveDocumentGridLinePitch } from "../docx/documentGrid.js";
4
6
  import { getMargins, getPageSize, twipsToPixels } from "../paged-layout/sectionGeometry.js";
5
7
  import { getColumns } from "../layout-bridge/sectionColumns.js";
6
8
  import { toFlowBlocks } from "../layout-bridge/convert/toFlowBlocks.js";
@@ -14,6 +16,7 @@ import { installCanvasMeasureProvider } from "../layout-engine/measure/measureCo
14
16
  import { buildFootnoteContentMap, collectEndnoteRefs, collectFootnoteRefs, computeNoteDisplayNumbers, remapNoteMarkerText } from "../layout-bridge/convert/footnoteLayout.js";
15
17
  import { applyTemplatePreviewToBlocks } from "../layout-bridge/convert/templatePreviewFlow.js";
16
18
  import { layoutDocument } from "../layout-engine/index.js";
19
+ import { resolveJustificationCompatibility } from "../layout-engine/justificationCompatibility.js";
17
20
  import { measureBlocks, measureSingleBlockWithoutFloatingZones } from "../layout-engine/measure/measureBlocks.js";
18
21
  import { tryBuildIncrementalMeasures } from "../paged-layout/incrementalMeasure.js";
19
22
  import { computePerBlockMeasureInputs } from "../paged-layout/sectionBlockWidths.js";
@@ -56,7 +59,7 @@ function bodyBlocksClearSectionHeaderFooter(blocks, { authoredMargins, sectionHe
56
59
  return changed ? nextBlocks : blocks;
57
60
  }
58
61
  function runLayoutPipeline(deps, state, options = {}) {
59
- const { contentWidth, columns, pageSize, margins, pageGap, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
62
+ const { contentWidth, columns, pageSize, margins, pageGap, showMarginGuides, marginGuideColor, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
60
63
  let outcome = {};
61
64
  let pendingArtifacts;
62
65
  let pendingTemplatePreview;
@@ -75,12 +78,16 @@ function runLayoutPipeline(deps, state, options = {}) {
75
78
  if (defaultTabStop !== void 0) flowOpts.defaultTabStopTwips = defaultTabStop;
76
79
  if (document?.package.settings?.lineBreakRules) flowOpts.lineBreakRules = document.package.settings.lineBreakRules;
77
80
  const documentSettings = document?.package.settings;
81
+ const justificationCompatibility = resolveJustificationCompatibility(documentSettings?.compatibilityMode);
82
+ if (justificationCompatibility) flowOpts.justificationCompatibility = justificationCompatibility;
78
83
  if (documentSettings?.autoHyphenation === true) flowOpts.automaticHyphenation = {
79
84
  enabled: true,
80
85
  ...documentSettings.doNotHyphenateCaps !== void 0 ? { doNotHyphenateCaps: documentSettings.doNotHyphenateCaps } : {},
81
86
  ...documentSettings.consecutiveHyphenLimit !== void 0 ? { consecutiveLineLimit: documentSettings.consecutiveHyphenLimit } : {},
82
87
  ...documentSettings.hyphenationZoneTwips !== void 0 ? { hyphenationZoneTwips: documentSettings.hyphenationZoneTwips } : {}
83
88
  };
89
+ const finalSectionDocumentGridLinePitchTwips = resolveDocumentGridLinePitch(document?.package.document.sections?.at(-1)?.properties.docGrid);
90
+ if (finalSectionDocumentGridLinePitchTwips !== void 0) flowOpts.finalSectionDocumentGridLinePitchTwips = finalSectionDocumentGridLinePitchTwips;
84
91
  let newBlocks = toFlowBlocks(state.doc, flowOpts);
85
92
  const previewState = templatePreviewValuesKey.getState(state);
86
93
  const previewEntries = previewState?.entries ?? EMPTY_TEMPLATE_PREVIEW_ENTRIES;
@@ -127,6 +134,7 @@ function runLayoutPipeline(deps, state, options = {}) {
127
134
  measureBlocks: hfMeasureBlocks,
128
135
  ...defaultTabStop !== void 0 ? { defaultTabStopTwips: defaultTabStop } : {},
129
136
  ...flowOpts.lineBreakRules ? { lineBreakRules: flowOpts.lineBreakRules } : {},
137
+ ...flowOpts.justificationCompatibility ? { justificationCompatibility: flowOpts.justificationCompatibility } : {},
130
138
  ...flowOpts.automaticHyphenation ? { automaticHyphenation: flowOpts.automaticHyphenation } : {}
131
139
  };
132
140
  };
@@ -209,6 +217,8 @@ function runLayoutPipeline(deps, state, options = {}) {
209
217
  marginRight: blockMeasureInputs.marginRights,
210
218
  marginBottom: blockMeasureInputs.marginBottoms
211
219
  });
220
+ newBlocks = resolveEffectiveParagraphSpacingTree(newBlocks);
221
+ outcome.blocks = newBlocks;
212
222
  pendingArtifacts = {
213
223
  blocks: newBlocks,
214
224
  blockWidths,
@@ -256,6 +266,7 @@ function runLayoutPipeline(deps, state, options = {}) {
256
266
  if (_theme !== void 0) footnoteOptions.theme = _theme;
257
267
  if (defaultTabStop !== void 0) footnoteOptions.defaultTabStopTwips = defaultTabStop;
258
268
  if (flowOpts.lineBreakRules) footnoteOptions.lineBreakRules = flowOpts.lineBreakRules;
269
+ if (flowOpts.justificationCompatibility) footnoteOptions.justificationCompatibility = flowOpts.justificationCompatibility;
259
270
  if (flowOpts.automaticHyphenation) footnoteOptions.automaticHyphenation = flowOpts.automaticHyphenation;
260
271
  return footnoteOptions;
261
272
  })());
@@ -372,6 +383,10 @@ function runLayoutPipeline(deps, state, options = {}) {
372
383
  blockLookup,
373
384
  titlePg: hasTitlePg
374
385
  };
386
+ if (showMarginGuides) {
387
+ renderOpts.showMarginGuides = true;
388
+ if (marginGuideColor !== void 0) renderOpts.marginGuideColor = marginGuideColor;
389
+ }
375
390
  if (headerContentForRender) renderOpts.headerContent = headerContentForRender;
376
391
  if (footerContentForRender) renderOpts.footerContent = footerContentForRender;
377
392
  if (firstPageHeaderForRender) renderOpts.firstPageHeaderContent = firstPageHeaderForRender;
@@ -0,0 +1,36 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { Plugin } from "prosemirror-state";
3
+ import { EditorView } from "prosemirror-view";
4
+
5
+ //#region src/controller/noteEditorManager.d.ts
6
+ type NoteStoryKind = "footnote" | "endnote";
7
+ type NoteStoryKey = {
8
+ kind: NoteStoryKind;
9
+ noteId: number;
10
+ };
11
+ type NoteEditorTransaction = NoteStoryKey & {
12
+ docChanged: boolean;
13
+ selectionChanged: boolean;
14
+ view: EditorView;
15
+ };
16
+ type NoteEditorManagerDeps = {
17
+ getDocument: () => document_d_exports.Document | null;
18
+ getHost: () => HTMLElement | null;
19
+ getPlugins?: (() => Plugin[]) | undefined;
20
+ getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
21
+ getTheme: () => document_d_exports.Theme | null | undefined;
22
+ onTransaction?: ((transaction: NoteEditorTransaction) => void) | undefined;
23
+ };
24
+ type NoteEditorManager = {
25
+ activate: (story: NoteStoryKey | null) => EditorView | null;
26
+ destroy: () => void;
27
+ getActive: () => NoteStoryKey | null;
28
+ getView: (story: NoteStoryKey) => EditorView | null;
29
+ listStories: () => NoteStoryKey[];
30
+ snapshotDocument: (document: document_d_exports.Document) => document_d_exports.Document;
31
+ sync: () => void;
32
+ };
33
+ declare const enumerateDocumentNoteStories: (document: document_d_exports.Document | null) => NoteStoryKey[];
34
+ declare const createNoteEditorManager: (deps: NoteEditorManagerDeps) => NoteEditorManager;
35
+ //#endregion
36
+ export { NoteEditorManager, NoteEditorManagerDeps, NoteEditorTransaction, NoteStoryKey, NoteStoryKind, createNoteEditorManager, enumerateDocumentNoteStories };
@@ -0,0 +1,210 @@
1
+ import { proseDocToBlocks } from "../prosemirror/conversion/fromProseDoc.js";
2
+ import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js";
3
+ import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
4
+ import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
5
+ import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
6
+ import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
7
+ import { schema } from "../prosemirror/schema/index.js";
8
+ import { footnoteToProseDoc } from "../prosemirror/conversion/toProseDoc.js";
9
+ import { isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
10
+ import { EditorState } from "prosemirror-state";
11
+ import { EditorView } from "prosemirror-view";
12
+ //#region src/controller/noteEditorManager.ts
13
+ /** Framework-neutral lifecycle owner for editable footnote and endnote stories. */
14
+ const EMPTY_PLUGINS = [];
15
+ const storyMapKey = ({ kind, noteId }) => `${kind}:${String(noteId)}`;
16
+ const isNormalFootnote = (note) => !isSeparatorFootnote(note);
17
+ const isNormalEndnote = (note) => !isSeparatorEndnote(note);
18
+ const enumerateDocumentNoteStories = (document) => [...(document?.package.footnotes ?? []).filter(isNormalFootnote).map(({ id }) => ({
19
+ kind: "footnote",
20
+ noteId: id
21
+ })), ...(document?.package.endnotes ?? []).filter(isNormalEndnote).map(({ id }) => ({
22
+ kind: "endnote",
23
+ noteId: id
24
+ }))];
25
+ const resolveNote = (document, story) => {
26
+ return (story.kind === "footnote" ? document?.package.footnotes : document?.package.endnotes)?.find(({ id }) => id === story.noteId) ?? null;
27
+ };
28
+ const noteToProseDocument = (note, styles, theme) => {
29
+ const options = {};
30
+ if (styles) options.styles = styles;
31
+ if (theme !== void 0) options.theme = theme;
32
+ return footnoteToProseDoc(note.content, options);
33
+ };
34
+ const buildInitialState = (document, styles, manager, externalPlugins) => {
35
+ return ensureBaseDirectionInState(ensureParaIdsInState(EditorState.create({
36
+ doc: document,
37
+ schema,
38
+ plugins: [
39
+ ...manager.getPlugins(),
40
+ ...externalPlugins,
41
+ createDocumentStylesPlugin(styles)
42
+ ]
43
+ })));
44
+ };
45
+ const createNoteEditorManager = (deps) => {
46
+ const mounted = /* @__PURE__ */ new Map();
47
+ let active = null;
48
+ const updateVisibility = () => {
49
+ const activeKey = active ? storyMapKey(active) : null;
50
+ for (const [key, story] of mounted) story.mountNode.hidden = key !== activeKey;
51
+ };
52
+ const destroyMounted = (story) => {
53
+ story.view.destroy();
54
+ story.manager.destroy();
55
+ story.mountNode.remove();
56
+ };
57
+ const destroy = () => {
58
+ for (const story of mounted.values()) destroyMounted(story);
59
+ mounted.clear();
60
+ active = null;
61
+ };
62
+ const sync = () => {
63
+ const host = deps.getHost();
64
+ if (!host) return;
65
+ const document = deps.getDocument();
66
+ const styles = deps.getStyles();
67
+ const theme = deps.getTheme();
68
+ const externalPlugins = deps.getPlugins?.() ?? EMPTY_PLUGINS;
69
+ const wanted = new Map(enumerateDocumentNoteStories(document).map((story) => [storyMapKey(story), story]));
70
+ const activeKey = active ? storyMapKey(active) : null;
71
+ for (const [key, story] of mounted) {
72
+ if (wanted.has(key)) continue;
73
+ destroyMounted(story);
74
+ mounted.delete(key);
75
+ }
76
+ for (const [key, storyKey] of wanted) {
77
+ if (!mounted.has(key) && key !== activeKey) continue;
78
+ const note = resolveNote(document, storyKey);
79
+ if (!note) continue;
80
+ const existing = mounted.get(key);
81
+ if (existing) {
82
+ if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
83
+ const nextProseDocument = noteToProseDocument(note, styles, theme);
84
+ const contextIsCurrent = existing.appliedStyles === styles && existing.appliedTheme === theme && existing.appliedPlugins === externalPlugins;
85
+ if ((existing.appliedNote === note && existing.appliedContent === note.content || existing.appliedProseDocument.eq(nextProseDocument)) && contextIsCurrent) {
86
+ existing.appliedNote = note;
87
+ existing.appliedContent = note.content;
88
+ existing.appliedProseDocument = nextProseDocument;
89
+ continue;
90
+ }
91
+ existing.view.updateState(buildInitialState(nextProseDocument, styles, existing.manager, externalPlugins));
92
+ existing.appliedNote = note;
93
+ existing.appliedContent = note.content;
94
+ existing.appliedStyles = styles;
95
+ existing.appliedTheme = theme;
96
+ existing.appliedPlugins = externalPlugins;
97
+ existing.appliedProseDocument = nextProseDocument;
98
+ existing.dirty = false;
99
+ continue;
100
+ }
101
+ const manager = new ExtensionManager(createStarterKit());
102
+ manager.buildSchema();
103
+ manager.initializeRuntime();
104
+ const mountNode = host.ownerDocument.createElement("div");
105
+ mountNode.dataset["noteKind"] = storyKey.kind;
106
+ mountNode.dataset["noteId"] = String(storyKey.noteId);
107
+ host.append(mountNode);
108
+ const proseDocument = noteToProseDocument(note, styles, theme);
109
+ const view = new EditorView(mountNode, {
110
+ state: buildInitialState(proseDocument, styles, manager, externalPlugins),
111
+ dispatchTransaction(transaction) {
112
+ view.updateState(view.state.apply(transaction));
113
+ const mountedStory = mounted.get(key);
114
+ if (mountedStory && transaction.docChanged) mountedStory.dirty = true;
115
+ deps.onTransaction?.({
116
+ ...storyKey,
117
+ docChanged: transaction.docChanged,
118
+ selectionChanged: transaction.selectionSet,
119
+ view
120
+ });
121
+ }
122
+ });
123
+ mounted.set(key, {
124
+ appliedContent: note.content,
125
+ appliedNote: note,
126
+ appliedPlugins: externalPlugins,
127
+ appliedProseDocument: proseDocument,
128
+ appliedStyles: styles,
129
+ appliedTheme: theme,
130
+ dirty: false,
131
+ manager,
132
+ mountNode,
133
+ note: storyKey,
134
+ view
135
+ });
136
+ }
137
+ if (active && !wanted.has(storyMapKey(active))) active = null;
138
+ updateVisibility();
139
+ };
140
+ return {
141
+ activate: (story) => {
142
+ active = story;
143
+ sync();
144
+ if (!story) return null;
145
+ const view = mounted.get(storyMapKey(story))?.view ?? null;
146
+ if (view) return view;
147
+ active = null;
148
+ updateVisibility();
149
+ return null;
150
+ },
151
+ destroy,
152
+ getActive: () => active,
153
+ getView: (story) => mounted.get(storyMapKey(story))?.view ?? null,
154
+ listStories: () => enumerateDocumentNoteStories(deps.getDocument()),
155
+ snapshotDocument: (document) => {
156
+ let footnotes = document.package.footnotes;
157
+ let endnotes = document.package.endnotes;
158
+ let footnotesChanged = false;
159
+ let endnotesChanged = false;
160
+ for (const story of mounted.values()) {
161
+ if (!story.dirty) continue;
162
+ if (story.note.kind === "footnote") {
163
+ const index = footnotes?.findIndex(({ id }) => id === story.note.noteId) ?? -1;
164
+ const current = index === -1 ? null : footnotes?.at(index);
165
+ if (!current || !footnotes) continue;
166
+ if (!footnotesChanged) {
167
+ footnotes = [...footnotes];
168
+ footnotesChanged = true;
169
+ }
170
+ const updated = {
171
+ ...current,
172
+ content: proseDocToBlocks(story.view.state.doc)
173
+ };
174
+ footnotes[index] = updated;
175
+ story.appliedNote = updated;
176
+ story.appliedContent = updated.content;
177
+ story.appliedProseDocument = noteToProseDocument(updated, story.appliedStyles, story.appliedTheme);
178
+ continue;
179
+ }
180
+ const index = endnotes?.findIndex(({ id }) => id === story.note.noteId) ?? -1;
181
+ const current = index === -1 ? null : endnotes?.at(index);
182
+ if (!current || !endnotes) continue;
183
+ if (!endnotesChanged) {
184
+ endnotes = [...endnotes];
185
+ endnotesChanged = true;
186
+ }
187
+ const updated = {
188
+ ...current,
189
+ content: proseDocToBlocks(story.view.state.doc)
190
+ };
191
+ endnotes[index] = updated;
192
+ story.appliedNote = updated;
193
+ story.appliedContent = updated.content;
194
+ story.appliedProseDocument = noteToProseDocument(updated, story.appliedStyles, story.appliedTheme);
195
+ }
196
+ if (!footnotesChanged && !endnotesChanged) return document;
197
+ return {
198
+ ...document,
199
+ package: {
200
+ ...document.package,
201
+ ...footnotesChanged && footnotes ? { footnotes } : {},
202
+ ...endnotesChanged && endnotes ? { endnotes } : {}
203
+ }
204
+ };
205
+ },
206
+ sync
207
+ };
208
+ };
209
+ //#endregion
210
+ export { createNoteEditorManager, enumerateDocumentNoteStories };