@extend-ai/react-docx 0.7.0-alpha.3 → 0.7.0-alpha.5

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/index.cjs CHANGED
@@ -160,6 +160,15 @@ function __wbg_get_imports() {
160
160
  getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
161
161
  getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
162
162
  },
163
+ __wbg___wbindgen_is_null_ced4761460071341: function(arg0) {
164
+ const ret = getObject(arg0) === null;
165
+ return ret;
166
+ },
167
+ __wbg___wbindgen_is_object_3a2c414391dbf751: function(arg0) {
168
+ const val = getObject(arg0);
169
+ const ret = typeof val === "object" && val !== null;
170
+ return ret;
171
+ },
163
172
  __wbg___wbindgen_is_undefined_4410e3c20a99fa97: function(arg0) {
164
173
  const ret = getObject(arg0) === void 0;
165
174
  return ret;
@@ -175,12 +184,83 @@ function __wbg_get_imports() {
175
184
  __wbg___wbindgen_throw_bbadd78c1bac3a77: function(arg0, arg1) {
176
185
  throw new Error(getStringFromWasm0(arg0, arg1));
177
186
  },
187
+ __wbg_create_00e11a7cefe80760: function(arg0) {
188
+ const ret = Object.create(getObject(arg0));
189
+ return addHeapObject(ret);
190
+ },
191
+ __wbg_get_52a8a619f7b88df6: function() {
192
+ return handleError(function(arg0, arg1) {
193
+ const ret = Reflect.get(getObject(arg0), getObject(arg1));
194
+ return addHeapObject(ret);
195
+ }, arguments);
196
+ },
197
+ __wbg_get_unchecked_46e778e3cec74b5e: function(arg0, arg1) {
198
+ const ret = getObject(arg0)[arg1 >>> 0];
199
+ return addHeapObject(ret);
200
+ },
201
+ __wbg_instanceof_ArrayBuffer_a581da923203f29f: function(arg0) {
202
+ let result;
203
+ try {
204
+ result = getObject(arg0) instanceof ArrayBuffer;
205
+ } catch (_) {
206
+ result = false;
207
+ }
208
+ const ret = result;
209
+ return ret;
210
+ },
211
+ __wbg_instanceof_Uint8Array_b6fe1ac89eba107e: function(arg0) {
212
+ let result;
213
+ try {
214
+ result = getObject(arg0) instanceof Uint8Array;
215
+ } catch (_) {
216
+ result = false;
217
+ }
218
+ const ret = result;
219
+ return ret;
220
+ },
221
+ __wbg_isArray_139f48e3c057ede8: function(arg0) {
222
+ const ret = Array.isArray(getObject(arg0));
223
+ return ret;
224
+ },
225
+ __wbg_keys_bd51ff67a9b04698: function(arg0) {
226
+ const ret = Object.keys(getObject(arg0));
227
+ return addHeapObject(ret);
228
+ },
229
+ __wbg_length_68a9d5278d084f4f: function(arg0) {
230
+ const ret = getObject(arg0).length;
231
+ return ret;
232
+ },
233
+ __wbg_length_fb04d16d7bdf6d4c: function(arg0) {
234
+ const ret = getObject(arg0).length;
235
+ return ret;
236
+ },
237
+ __wbg_new_20b778a4c5c691c3: function() {
238
+ const ret = new Object();
239
+ return addHeapObject(ret);
240
+ },
241
+ __wbg_new_b06772b280cc6e52: function(arg0) {
242
+ const ret = new Uint8Array(getObject(arg0));
243
+ return addHeapObject(ret);
244
+ },
245
+ __wbg_new_from_slice_bb2d1778c0b87eb1: function(arg0, arg1) {
246
+ const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
247
+ return addHeapObject(ret);
248
+ },
178
249
  __wbg_parse_246201845d0eb98c: function() {
179
250
  return handleError(function(arg0, arg1) {
180
251
  const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
181
252
  return addHeapObject(ret);
182
253
  }, arguments);
183
254
  },
255
+ __wbg_prototypesetcall_956c7493c68e29b4: function(arg0, arg1, arg2) {
256
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), getObject(arg2));
257
+ },
258
+ __wbg_set_a6ba3ac0e634b822: function() {
259
+ return handleError(function(arg0, arg1, arg2) {
260
+ const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
261
+ return ret;
262
+ }, arguments);
263
+ },
184
264
  __wbg_stringify_a42c95ea9a7591c9: function() {
185
265
  return handleError(function(arg0) {
186
266
  const ret = JSON.stringify(getObject(arg0));
@@ -474,9 +554,15 @@ async function defaultWasmSource() {
474
554
  async function initWasm(source) {
475
555
  if (!initPromise) {
476
556
  const chosen = source ?? overrideSource;
477
- initPromise = (chosen !== void 0 ? Promise.resolve(chosen) : defaultWasmSource()).then(
478
- (module_or_path) => __wbg_init({ module_or_path })
479
- );
557
+ initPromise = (chosen !== void 0 ? Promise.resolve(chosen) : defaultWasmSource()).then((module_or_path) => __wbg_init({ module_or_path })).catch((error) => {
558
+ if (error instanceof WebAssembly.CompileError) {
559
+ throw new Error(
560
+ `react-docx: the bundled WebAssembly binary failed to compile. It requires WebAssembly SIMD support (Chrome 91+, Firefox 89+, Safari 16.4+, Node 16.4+). Original error: ${error.message}`,
561
+ { cause: error }
562
+ );
563
+ }
564
+ throw error;
565
+ });
480
566
  }
481
567
  return initPromise;
482
568
  }
@@ -515,7 +601,7 @@ function mapsToWasmPackage(input) {
515
601
  }
516
602
  const binaryAssets = {};
517
603
  for (const [name, asset] of input.binaryAssets.entries()) {
518
- binaryAssets[name] = Array.from(asset);
604
+ binaryAssets[name] = asset;
519
605
  }
520
606
  return { parts, binaryAssets };
521
607
  }
@@ -627,327 +713,7 @@ var init_src2 = __esm({
627
713
  }
628
714
  });
629
715
 
630
- // src/index.tsx
631
- var index_exports = {};
632
- __export(index_exports, {
633
- DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX: () => DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX,
634
- DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX: () => DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX,
635
- DocxEditorViewer: () => DocxEditorViewer,
636
- ReactDocxViewer: () => ReactDocxViewer,
637
- applyRunStyle: () => applyRunStyle,
638
- buildDocModel: () => buildDocModel,
639
- buildDocModelFromBytes: () => buildDocModelFromBytes,
640
- buildDocumentPageNodeSegments: () => buildDocumentPageNodeSegments2,
641
- buildDocumentPageRanges: () => buildDocumentPageRanges,
642
- buildLayoutSnapshot: () => buildLayoutSnapshot,
643
- cloneDocModel: () => cloneDocModel,
644
- collectDocxEstimatedOverflowBreakStartNodeIndexes: () => collectDocxEstimatedOverflowBreakStartNodeIndexes,
645
- collectDocxHardPageBreakStartNodeIndexes: () => collectDocxHardPageBreakStartNodeIndexes2,
646
- collectDocxLastRenderedPageBreakStartNodeIndexes: () => collectDocxLastRenderedPageBreakStartNodeIndexes,
647
- collectTableExplicitPageBreakInfo: () => collectTableExplicitPageBreakInfo2,
648
- collectTopLevelExplicitPageBreakStartNodeIndexes: () => collectTopLevelExplicitPageBreakStartNodeIndexes2,
649
- copyParagraphs: () => copyParagraphs,
650
- createMinimalDocxPackage: () => createMinimalDocxPackage,
651
- defaultStarterModel: () => defaultStarterModel,
652
- duplicateParagraph: () => duplicateParagraph,
653
- getPart: () => getPart,
654
- initWasm: () => initWasm,
655
- insertParagraph: () => insertParagraph,
656
- layoutDocument: () => layoutDocument,
657
- modelToDocumentXml: () => modelToDocumentXml,
658
- normalizeDocModel: () => normalizeDocModel,
659
- packageToArrayBuffer: () => packageToArrayBuffer,
660
- paragraphAfterSpacingPx: () => paragraphAfterSpacingPx2,
661
- paragraphBeforeSpacingPx: () => paragraphBeforeSpacingPx2,
662
- paragraphHasExplicitPageBreak: () => paragraphHasExplicitPageBreak3,
663
- paragraphHasLastRenderedPageBreak: () => paragraphHasLastRenderedPageBreak2,
664
- paragraphHasPageBreakBefore: () => paragraphHasPageBreakBefore3,
665
- paragraphLetterheadColumnGroupAtSegmentOffset: () => paragraphLetterheadColumnGroupAtSegmentOffset2,
666
- paragraphLetterheadFloatSideAtNodeIndex: () => paragraphLetterheadFloatSideAtNodeIndex,
667
- paragraphStartsWithLastRenderedPageBreak: () => paragraphStartsWithLastRenderedPageBreak2,
668
- parseDocx: () => parseDocx,
669
- parseParagraphsFromClipboard: () => parseParagraphsFromClipboard,
670
- parseSectionLayout: () => parseSectionLayout,
671
- pasteParagraphs: () => pasteParagraphs,
672
- removeParagraph: () => removeParagraph,
673
- replaceText: () => replaceText,
674
- resolveDocumentForLayout: () => resolveDocumentForLayout,
675
- resolveDocumentLayout: () => resolveDocumentLayout,
676
- resolveDocumentPageSegmentStartNodeIndex: () => resolveDocumentPageSegmentStartNodeIndex,
677
- resolveDocumentSectionsFromMetadata: () => resolveDocumentSectionsFromMetadata2,
678
- resolveDocxPageThumbnailResolution: () => resolveDocxPageThumbnailResolution,
679
- resolvePaginationSectionMetricsIndexForNodeIndex: () => resolvePaginationSectionMetricsIndexForNodeIndex2,
680
- resolveParagraphBeforeSpacingPx: () => resolveParagraphBeforeSpacingPx2,
681
- resolveSectionIndexForNodeIndex: () => resolveSectionIndexForNodeIndex2,
682
- resolveSectionPropertiesXmlForNodeIndex: () => resolveSectionPropertiesXmlForNodeIndex,
683
- scalePaginationSectionMetricsHeights: () => scalePaginationSectionMetricsHeights2,
684
- scorePaginationAgainstStoredPageBreaks: () => scorePaginationAgainstStoredPageBreaks,
685
- sectionBreakAfterParagraphStartsNewPage: () => sectionBreakAfterParagraphStartsNewPage2,
686
- sectionBreakPropertiesStartNewPage: () => sectionBreakPropertiesStartNewPage2,
687
- sectionTitlePageEnabled: () => sectionTitlePageEnabled2,
688
- selectSectionVariantForPage: () => selectSectionVariantForPage2,
689
- serializeDocModel: () => serializeDocModel,
690
- serializeDocx: () => serializeDocx,
691
- serializeParagraphsForClipboard: () => serializeParagraphsForClipboard,
692
- setParagraphAlignment: () => setParagraphAlignment,
693
- setParagraphHeading: () => setParagraphHeading,
694
- setRunColor: () => setRunColor,
695
- setRunHighlight: () => setRunHighlight,
696
- setWasmSource: () => setWasmSource,
697
- splitParagraphChildrenAtTextOffsets: () => splitParagraphChildrenAtTextOffsets,
698
- toggleRunStyleFlag: () => toggleRunStyleFlag,
699
- updateParagraphText: () => updateParagraphText,
700
- updateTableCellParagraphText: () => updateTableCellParagraphText,
701
- updateTableCellParagraphTextRecursive: () => updateTableCellParagraphTextRecursive,
702
- updateTableCellText: () => updateTableCellText,
703
- useDocxBorders: () => useDocxBorders,
704
- useDocxDocumentTheme: () => useDocxDocumentTheme,
705
- useDocxEditor: () => useDocxEditor,
706
- useDocxFormFields: () => useDocxFormFields,
707
- useDocxImageWrapMenu: () => useDocxImageWrapMenu,
708
- useDocxLineSpacing: () => useDocxLineSpacing,
709
- useDocxModel: () => useDocxModel,
710
- useDocxPageLayout: () => useDocxPageLayout,
711
- useDocxPageThumbnails: () => useDocxPageThumbnails,
712
- useDocxPagination: () => useDocxPagination,
713
- useDocxParagraphStyles: () => useDocxParagraphStyles,
714
- useDocxTrackChanges: () => useDocxTrackChanges,
715
- useDocxViewerThumbnails: () => useDocxViewerThumbnails,
716
- withPart: () => withPart
717
- });
718
- module.exports = __toCommonJS(index_exports);
719
- init_cjs_shims();
720
- var React2 = __toESM(require("react"), 1);
721
-
722
- // ../layout-engine/src/index.ts
723
- init_cjs_shims();
724
- var DEFAULT_OPTIONS = {
725
- pageWidth: 816,
726
- pageHeight: 1056,
727
- margin: 72,
728
- minLineHeight: 22,
729
- paragraphSpacing: 8,
730
- tableCellPadding: 8
731
- };
732
- function headingScale(level) {
733
- if (!level) {
734
- return 1;
735
- }
736
- switch (level) {
737
- case 1:
738
- return 2.15;
739
- case 2:
740
- return 1.75;
741
- case 3:
742
- return 1.45;
743
- case 4:
744
- return 1.28;
745
- case 5:
746
- return 1.15;
747
- case 6:
748
- return 1.05;
749
- default:
750
- return 1;
751
- }
752
- }
753
- function runHeightPx(run) {
754
- if (run.kind === "image") {
755
- if (run.floating) {
756
- return 0;
757
- }
758
- return run.heightPx ?? 96;
759
- }
760
- const fontSizePt = run.style?.fontSizePt ?? 12;
761
- return Math.round(fontSizePt * 1.6);
762
- }
763
- function lineHeightFromRuns(runs, minLineHeight, headingLevel) {
764
- const base = runs.reduce((largest, run) => {
765
- return Math.max(largest, runHeightPx(run));
766
- }, 12) * headingScale(headingLevel);
767
- return Math.max(minLineHeight, Math.round(base));
768
- }
769
- function spacingForBlock(baseSpacing, headingLevel) {
770
- if (!headingLevel) {
771
- return baseSpacing;
772
- }
773
- return baseSpacing + Math.max(4, (7 - headingLevel) * 2);
774
- }
775
- function formFieldDisplayText(field) {
776
- switch (field.fieldType) {
777
- case "checkbox":
778
- return field.checked ? field.checkedSymbol ?? "\u2612" : field.uncheckedSymbol ?? "\u2610";
779
- case "dropdown":
780
- case "date":
781
- case "text":
782
- default:
783
- return field.value ?? "";
784
- }
785
- }
786
- function paragraphToLayout(paragraph, idPrefix, x, y, width, minLineHeight) {
787
- const runs = paragraph.children.map((child, runIndex) => {
788
- if (child.type === "text") {
789
- return {
790
- kind: "text",
791
- id: `${idPrefix}-run-${runIndex}`,
792
- text: child.text,
793
- style: child.style,
794
- link: child.link
795
- };
796
- }
797
- if (child.type === "form-field") {
798
- return {
799
- kind: "text",
800
- id: `${idPrefix}-run-${runIndex}`,
801
- text: formFieldDisplayText(child),
802
- style: child.style,
803
- link: child.link
804
- };
805
- }
806
- return {
807
- kind: "image",
808
- id: `${idPrefix}-run-${runIndex}`,
809
- src: child.src,
810
- alt: child.alt,
811
- widthPx: child.widthPx,
812
- heightPx: child.heightPx,
813
- contentType: child.contentType,
814
- data: child.data ? new Uint8Array(child.data) : void 0,
815
- floating: Boolean(child.floating)
816
- };
817
- });
818
- return {
819
- kind: "paragraph",
820
- id: idPrefix,
821
- runs,
822
- align: paragraph.style?.align ?? "left",
823
- headingLevel: paragraph.style?.headingLevel,
824
- x,
825
- y,
826
- width,
827
- height: lineHeightFromRuns(runs, minLineHeight, paragraph.style?.headingLevel)
828
- };
829
- }
830
- function paragraphsForTableCellNodes(nodes) {
831
- const paragraphs = [];
832
- const walk = (items) => {
833
- for (const item of items) {
834
- if (item.type === "paragraph") {
835
- paragraphs.push(item);
836
- continue;
837
- }
838
- for (const row of item.rows) {
839
- for (const cell of row.cells) {
840
- walk(cell.nodes);
841
- }
842
- }
843
- }
844
- };
845
- walk(nodes);
846
- return paragraphs;
847
- }
848
- function tableToLayout(table, idPrefix, x, y, width, options) {
849
- const columnCount = Math.max(
850
- 1,
851
- ...table.rows.map(
852
- (row) => row.cells.reduce(
853
- (sum, cell) => sum + (cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1),
854
- 0
855
- )
856
- )
857
- );
858
- const baseCellWidth = width / columnCount;
859
- let tableHeight = 0;
860
- const rows = table.rows.map((row, rowIndex) => {
861
- let rowHeight = options.minLineHeight + options.tableCellPadding * 2;
862
- let columnCursor = 0;
863
- const cells = row.cells.map((cell, cellIndex) => {
864
- const colSpan = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
865
- const cellWidth = baseCellWidth * colSpan;
866
- const cellParagraphs = paragraphsForTableCellNodes(cell.nodes);
867
- const paragraphBlocks = cellParagraphs.map(
868
- (paragraph, paragraphIndex) => paragraphToLayout(
869
- paragraph,
870
- `${idPrefix}-r${rowIndex}-c${cellIndex}-p${paragraphIndex}`,
871
- x + columnCursor * baseCellWidth,
872
- y,
873
- cellWidth,
874
- options.minLineHeight
875
- )
876
- );
877
- const paragraphsHeight = paragraphBlocks.reduce((sum, block) => sum + block.height, 0);
878
- rowHeight = Math.max(rowHeight, paragraphsHeight + options.tableCellPadding * 2);
879
- columnCursor += colSpan;
880
- return {
881
- id: `${idPrefix}-r${rowIndex}-c${cellIndex}`,
882
- colSpan,
883
- backgroundColor: cell.style?.backgroundColor ?? row.style?.backgroundColor,
884
- paragraphs: paragraphBlocks
885
- };
886
- });
887
- tableHeight += rowHeight;
888
- return {
889
- id: `${idPrefix}-row-${rowIndex}`,
890
- backgroundColor: row.style?.backgroundColor,
891
- cells
892
- };
893
- });
894
- return {
895
- kind: "table",
896
- id: idPrefix,
897
- x,
898
- y,
899
- width,
900
- height: Math.max(tableHeight, options.minLineHeight * 2),
901
- rows
902
- };
903
- }
904
- function estimateBlockHeight(block) {
905
- if (block.kind === "paragraph") {
906
- return block.height;
907
- }
908
- return block.height;
909
- }
910
- function layoutDocument(model, options = {}) {
911
- const resolved = { ...DEFAULT_OPTIONS, ...options };
912
- const pages = [{ number: 1, blocks: [] }];
913
- const contentWidth = resolved.pageWidth - resolved.margin * 2;
914
- const pageBottom = resolved.pageHeight - resolved.margin;
915
- let cursorY = resolved.margin;
916
- for (const [index, node] of model.nodes.entries()) {
917
- const block = node.type === "paragraph" ? paragraphToLayout(
918
- node,
919
- `paragraph-${index}`,
920
- resolved.margin,
921
- cursorY,
922
- contentWidth,
923
- resolved.minLineHeight
924
- ) : tableToLayout(node, `table-${index}`, resolved.margin, cursorY, contentWidth, resolved);
925
- const blockHeight = estimateBlockHeight(block);
926
- const currentPage = pages[pages.length - 1];
927
- if (cursorY + blockHeight > pageBottom && currentPage.blocks.length > 0) {
928
- pages.push({
929
- number: pages.length + 1,
930
- blocks: []
931
- });
932
- cursorY = resolved.margin;
933
- if (block.kind === "paragraph") {
934
- block.y = cursorY;
935
- } else {
936
- block.y = cursorY;
937
- }
938
- }
939
- pages[pages.length - 1].blocks.push(block);
940
- cursorY += blockHeight + (block.kind === "paragraph" ? spacingForBlock(resolved.paragraphSpacing, block.headingLevel) : resolved.paragraphSpacing + 10);
941
- }
942
- return pages;
943
- }
944
-
945
- // ../doc-model/src/index.ts
946
- init_cjs_shims();
947
- init_src();
948
-
949
716
  // ../doc-model/src/normalize.ts
950
- init_cjs_shims();
951
717
  function normalizeUint8Array(value) {
952
718
  if (value instanceof Uint8Array) {
953
719
  return value;
@@ -1034,12 +800,22 @@ function normalizeDocModel(model) {
1034
800
  }
1035
801
  };
1036
802
  }
803
+ var init_normalize = __esm({
804
+ "../doc-model/src/normalize.ts"() {
805
+ "use strict";
806
+ init_cjs_shims();
807
+ }
808
+ });
1037
809
 
1038
810
  // ../doc-model/src/types.ts
1039
- init_cjs_shims();
811
+ var init_types = __esm({
812
+ "../doc-model/src/types.ts"() {
813
+ "use strict";
814
+ init_cjs_shims();
815
+ }
816
+ });
1040
817
 
1041
818
  // ../doc-model/src/clone.ts
1042
- init_cjs_shims();
1043
819
  function isParagraphCellContent(node) {
1044
820
  return node.type === "paragraph";
1045
821
  }
@@ -1337,12 +1113,26 @@ function cloneDocModel(model) {
1337
1113
  endnotes: model.metadata.endnotes?.map((note) => ({
1338
1114
  ...note,
1339
1115
  nodes: note.nodes?.map(cloneDocNode)
1340
- }))
1116
+ })),
1117
+ comments: model.metadata.comments?.map((comment) => ({ ...comment }))
1341
1118
  }
1342
1119
  };
1343
1120
  }
1121
+ var init_clone = __esm({
1122
+ "../doc-model/src/clone.ts"() {
1123
+ "use strict";
1124
+ init_cjs_shims();
1125
+ }
1126
+ });
1344
1127
 
1345
1128
  // ../doc-model/src/index.ts
1129
+ var src_exports2 = {};
1130
+ __export(src_exports2, {
1131
+ buildDocModel: () => buildDocModel,
1132
+ buildDocModelFromBytes: () => buildDocModelFromBytes,
1133
+ cloneDocModel: () => cloneDocModel,
1134
+ normalizeDocModel: () => normalizeDocModel
1135
+ });
1346
1136
  async function buildDocModel(pkg) {
1347
1137
  const wasmPackage = mapsToWasmPackage({
1348
1138
  parts: pkg.parts,
@@ -1359,9 +1149,474 @@ async function buildDocModelFromBytes(bytes) {
1359
1149
  const model = await buildDocModel(pkg);
1360
1150
  return { package: pkg, model };
1361
1151
  }
1152
+ var init_src3 = __esm({
1153
+ "../doc-model/src/index.ts"() {
1154
+ "use strict";
1155
+ init_cjs_shims();
1156
+ init_src();
1157
+ init_normalize();
1158
+ init_types();
1159
+ init_clone();
1160
+ init_normalize();
1161
+ }
1162
+ });
1362
1163
 
1363
1164
  // src/index.tsx
1364
- init_src2();
1165
+ var index_exports = {};
1166
+ __export(index_exports, {
1167
+ DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX: () => DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX,
1168
+ DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX: () => DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX,
1169
+ DocxEditorViewer: () => DocxEditorViewer,
1170
+ ReactDocxViewer: () => ReactDocxViewer,
1171
+ applyRunStyle: () => applyRunStyle,
1172
+ buildDocModel: () => buildDocModel,
1173
+ buildDocModelFromBytes: () => buildDocModelFromBytes,
1174
+ buildDocumentPageNodeSegments: () => buildDocumentPageNodeSegments2,
1175
+ buildDocumentPageRanges: () => buildDocumentPageRanges,
1176
+ buildLayoutSnapshot: () => buildLayoutSnapshot,
1177
+ cloneDocModel: () => cloneDocModel,
1178
+ collectDocxEstimatedOverflowBreakStartNodeIndexes: () => collectDocxEstimatedOverflowBreakStartNodeIndexes,
1179
+ collectDocxHardPageBreakStartNodeIndexes: () => collectDocxHardPageBreakStartNodeIndexes2,
1180
+ collectDocxLastRenderedPageBreakStartNodeIndexes: () => collectDocxLastRenderedPageBreakStartNodeIndexes,
1181
+ collectTableExplicitPageBreakInfo: () => collectTableExplicitPageBreakInfo2,
1182
+ collectTopLevelExplicitPageBreakStartNodeIndexes: () => collectTopLevelExplicitPageBreakStartNodeIndexes2,
1183
+ copyParagraphs: () => copyParagraphs,
1184
+ createMinimalDocxPackage: () => createMinimalDocxPackage,
1185
+ defaultStarterModel: () => defaultStarterModel,
1186
+ duplicateParagraph: () => duplicateParagraph,
1187
+ getPart: () => getPart,
1188
+ initWasm: () => initWasm,
1189
+ insertParagraph: () => insertParagraph,
1190
+ layoutDocument: () => layoutDocument,
1191
+ modelToDocumentXml: () => modelToDocumentXml,
1192
+ normalizeDocModel: () => normalizeDocModel,
1193
+ packageToArrayBuffer: () => packageToArrayBuffer,
1194
+ paragraphAfterSpacingPx: () => paragraphAfterSpacingPx2,
1195
+ paragraphBeforeSpacingPx: () => paragraphBeforeSpacingPx2,
1196
+ paragraphHasExplicitPageBreak: () => paragraphHasExplicitPageBreak3,
1197
+ paragraphHasLastRenderedPageBreak: () => paragraphHasLastRenderedPageBreak2,
1198
+ paragraphHasPageBreakBefore: () => paragraphHasPageBreakBefore3,
1199
+ paragraphLetterheadColumnGroupAtSegmentOffset: () => paragraphLetterheadColumnGroupAtSegmentOffset2,
1200
+ paragraphLetterheadFloatSideAtNodeIndex: () => paragraphLetterheadFloatSideAtNodeIndex,
1201
+ paragraphStartsWithLastRenderedPageBreak: () => paragraphStartsWithLastRenderedPageBreak2,
1202
+ parseDocx: () => parseDocx,
1203
+ parseParagraphsFromClipboard: () => parseParagraphsFromClipboard,
1204
+ parseSectionLayout: () => parseSectionLayout,
1205
+ pasteParagraphs: () => pasteParagraphs,
1206
+ removeParagraph: () => removeParagraph,
1207
+ replaceText: () => replaceText,
1208
+ resolveDocumentForLayout: () => resolveDocumentForLayout,
1209
+ resolveDocumentLayout: () => resolveDocumentLayout,
1210
+ resolveDocumentPageSegmentStartNodeIndex: () => resolveDocumentPageSegmentStartNodeIndex,
1211
+ resolveDocumentSectionsFromMetadata: () => resolveDocumentSectionsFromMetadata2,
1212
+ resolveDocxPageThumbnailResolution: () => resolveDocxPageThumbnailResolution,
1213
+ resolvePaginationSectionMetricsIndexForNodeIndex: () => resolvePaginationSectionMetricsIndexForNodeIndex2,
1214
+ resolveParagraphBeforeSpacingPx: () => resolveParagraphBeforeSpacingPx2,
1215
+ resolveSectionIndexForNodeIndex: () => resolveSectionIndexForNodeIndex2,
1216
+ resolveSectionPropertiesXmlForNodeIndex: () => resolveSectionPropertiesXmlForNodeIndex,
1217
+ scalePaginationSectionMetricsHeights: () => scalePaginationSectionMetricsHeights2,
1218
+ scorePaginationAgainstStoredPageBreaks: () => scorePaginationAgainstStoredPageBreaks,
1219
+ sectionBreakAfterParagraphStartsNewPage: () => sectionBreakAfterParagraphStartsNewPage2,
1220
+ sectionBreakPropertiesStartNewPage: () => sectionBreakPropertiesStartNewPage2,
1221
+ sectionTitlePageEnabled: () => sectionTitlePageEnabled2,
1222
+ selectSectionVariantForPage: () => selectSectionVariantForPage2,
1223
+ serializeDocModel: () => serializeDocModel,
1224
+ serializeDocx: () => serializeDocx,
1225
+ serializeParagraphsForClipboard: () => serializeParagraphsForClipboard,
1226
+ setParagraphAlignment: () => setParagraphAlignment,
1227
+ setParagraphHeading: () => setParagraphHeading,
1228
+ setRunColor: () => setRunColor,
1229
+ setRunHighlight: () => setRunHighlight,
1230
+ setWasmSource: () => setWasmSource,
1231
+ splitParagraphChildrenAtTextOffsets: () => splitParagraphChildrenAtTextOffsets,
1232
+ toggleRunStyleFlag: () => toggleRunStyleFlag,
1233
+ updateParagraphText: () => updateParagraphText,
1234
+ updateTableCellParagraphText: () => updateTableCellParagraphText,
1235
+ updateTableCellParagraphTextRecursive: () => updateTableCellParagraphTextRecursive,
1236
+ updateTableCellText: () => updateTableCellText,
1237
+ useDocxBorders: () => useDocxBorders,
1238
+ useDocxComments: () => useDocxComments,
1239
+ useDocxDocumentTheme: () => useDocxDocumentTheme,
1240
+ useDocxEditor: () => useDocxEditor,
1241
+ useDocxFormFields: () => useDocxFormFields,
1242
+ useDocxImageWrapMenu: () => useDocxImageWrapMenu,
1243
+ useDocxLineSpacing: () => useDocxLineSpacing,
1244
+ useDocxModel: () => useDocxModel,
1245
+ useDocxPageLayout: () => useDocxPageLayout,
1246
+ useDocxPageThumbnails: () => useDocxPageThumbnails,
1247
+ useDocxPagination: () => useDocxPagination,
1248
+ useDocxParagraphStyles: () => useDocxParagraphStyles,
1249
+ useDocxTrackChanges: () => useDocxTrackChanges,
1250
+ useDocxViewerThumbnails: () => useDocxViewerThumbnails,
1251
+ withPart: () => withPart
1252
+ });
1253
+ module.exports = __toCommonJS(index_exports);
1254
+ init_cjs_shims();
1255
+ var React2 = __toESM(require("react"), 1);
1256
+
1257
+ // ../layout-engine/src/index.ts
1258
+ init_cjs_shims();
1259
+ var DEFAULT_OPTIONS = {
1260
+ pageWidth: 816,
1261
+ pageHeight: 1056,
1262
+ margin: 72,
1263
+ minLineHeight: 22,
1264
+ paragraphSpacing: 8,
1265
+ tableCellPadding: 8
1266
+ };
1267
+ function headingScale(level) {
1268
+ if (!level) {
1269
+ return 1;
1270
+ }
1271
+ switch (level) {
1272
+ case 1:
1273
+ return 2.15;
1274
+ case 2:
1275
+ return 1.75;
1276
+ case 3:
1277
+ return 1.45;
1278
+ case 4:
1279
+ return 1.28;
1280
+ case 5:
1281
+ return 1.15;
1282
+ case 6:
1283
+ return 1.05;
1284
+ default:
1285
+ return 1;
1286
+ }
1287
+ }
1288
+ function runHeightPx(run) {
1289
+ if (run.kind === "image") {
1290
+ if (run.floating) {
1291
+ return 0;
1292
+ }
1293
+ return run.heightPx ?? 96;
1294
+ }
1295
+ const fontSizePt = run.style?.fontSizePt ?? 12;
1296
+ return Math.round(fontSizePt * 1.6);
1297
+ }
1298
+ function lineHeightFromRuns(runs, minLineHeight, headingLevel) {
1299
+ const base = runs.reduce((largest, run) => {
1300
+ return Math.max(largest, runHeightPx(run));
1301
+ }, 12) * headingScale(headingLevel);
1302
+ return Math.max(minLineHeight, Math.round(base));
1303
+ }
1304
+ function spacingForBlock(baseSpacing, headingLevel) {
1305
+ if (!headingLevel) {
1306
+ return baseSpacing;
1307
+ }
1308
+ return baseSpacing + Math.max(4, (7 - headingLevel) * 2);
1309
+ }
1310
+ function formFieldDisplayText(field) {
1311
+ switch (field.fieldType) {
1312
+ case "checkbox":
1313
+ return field.checked ? field.checkedSymbol ?? "\u2612" : field.uncheckedSymbol ?? "\u2610";
1314
+ case "dropdown":
1315
+ case "date":
1316
+ case "text":
1317
+ default:
1318
+ return field.value ?? "";
1319
+ }
1320
+ }
1321
+ function paragraphToLayout(paragraph, idPrefix, x, y, width, minLineHeight) {
1322
+ const runs = paragraph.children.map((child, runIndex) => {
1323
+ if (child.type === "text") {
1324
+ return {
1325
+ kind: "text",
1326
+ id: `${idPrefix}-run-${runIndex}`,
1327
+ text: child.text,
1328
+ style: child.style,
1329
+ link: child.link
1330
+ };
1331
+ }
1332
+ if (child.type === "form-field") {
1333
+ return {
1334
+ kind: "text",
1335
+ id: `${idPrefix}-run-${runIndex}`,
1336
+ text: formFieldDisplayText(child),
1337
+ style: child.style,
1338
+ link: child.link
1339
+ };
1340
+ }
1341
+ return {
1342
+ kind: "image",
1343
+ id: `${idPrefix}-run-${runIndex}`,
1344
+ src: child.src,
1345
+ alt: child.alt,
1346
+ widthPx: child.widthPx,
1347
+ heightPx: child.heightPx,
1348
+ contentType: child.contentType,
1349
+ data: child.data ? new Uint8Array(child.data) : void 0,
1350
+ floating: Boolean(child.floating)
1351
+ };
1352
+ });
1353
+ return {
1354
+ kind: "paragraph",
1355
+ id: idPrefix,
1356
+ runs,
1357
+ align: paragraph.style?.align ?? "left",
1358
+ headingLevel: paragraph.style?.headingLevel,
1359
+ x,
1360
+ y,
1361
+ width,
1362
+ height: lineHeightFromRuns(runs, minLineHeight, paragraph.style?.headingLevel)
1363
+ };
1364
+ }
1365
+ function paragraphsForTableCellNodes(nodes) {
1366
+ const paragraphs = [];
1367
+ const walk = (items) => {
1368
+ for (const item of items) {
1369
+ if (item.type === "paragraph") {
1370
+ paragraphs.push(item);
1371
+ continue;
1372
+ }
1373
+ for (const row of item.rows) {
1374
+ for (const cell of row.cells) {
1375
+ walk(cell.nodes);
1376
+ }
1377
+ }
1378
+ }
1379
+ };
1380
+ walk(nodes);
1381
+ return paragraphs;
1382
+ }
1383
+ function tableToLayout(table, idPrefix, x, y, width, options) {
1384
+ const columnCount = Math.max(
1385
+ 1,
1386
+ ...table.rows.map(
1387
+ (row) => row.cells.reduce(
1388
+ (sum, cell) => sum + (cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1),
1389
+ 0
1390
+ )
1391
+ )
1392
+ );
1393
+ const baseCellWidth = width / columnCount;
1394
+ let tableHeight = 0;
1395
+ const rows = table.rows.map((row, rowIndex) => {
1396
+ let rowHeight = options.minLineHeight + options.tableCellPadding * 2;
1397
+ let columnCursor = 0;
1398
+ const cells = row.cells.map((cell, cellIndex) => {
1399
+ const colSpan = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
1400
+ const cellWidth = baseCellWidth * colSpan;
1401
+ const cellParagraphs = paragraphsForTableCellNodes(cell.nodes);
1402
+ const paragraphBlocks = cellParagraphs.map(
1403
+ (paragraph, paragraphIndex) => paragraphToLayout(
1404
+ paragraph,
1405
+ `${idPrefix}-r${rowIndex}-c${cellIndex}-p${paragraphIndex}`,
1406
+ x + columnCursor * baseCellWidth,
1407
+ y,
1408
+ cellWidth,
1409
+ options.minLineHeight
1410
+ )
1411
+ );
1412
+ const paragraphsHeight = paragraphBlocks.reduce((sum, block) => sum + block.height, 0);
1413
+ rowHeight = Math.max(rowHeight, paragraphsHeight + options.tableCellPadding * 2);
1414
+ columnCursor += colSpan;
1415
+ return {
1416
+ id: `${idPrefix}-r${rowIndex}-c${cellIndex}`,
1417
+ colSpan,
1418
+ backgroundColor: cell.style?.backgroundColor ?? row.style?.backgroundColor,
1419
+ paragraphs: paragraphBlocks
1420
+ };
1421
+ });
1422
+ tableHeight += rowHeight;
1423
+ return {
1424
+ id: `${idPrefix}-row-${rowIndex}`,
1425
+ backgroundColor: row.style?.backgroundColor,
1426
+ cells
1427
+ };
1428
+ });
1429
+ return {
1430
+ kind: "table",
1431
+ id: idPrefix,
1432
+ x,
1433
+ y,
1434
+ width,
1435
+ height: Math.max(tableHeight, options.minLineHeight * 2),
1436
+ rows
1437
+ };
1438
+ }
1439
+ function estimateBlockHeight(block) {
1440
+ if (block.kind === "paragraph") {
1441
+ return block.height;
1442
+ }
1443
+ return block.height;
1444
+ }
1445
+ function layoutDocument(model, options = {}) {
1446
+ const resolved = { ...DEFAULT_OPTIONS, ...options };
1447
+ const pages = [{ number: 1, blocks: [] }];
1448
+ const contentWidth = resolved.pageWidth - resolved.margin * 2;
1449
+ const pageBottom = resolved.pageHeight - resolved.margin;
1450
+ let cursorY = resolved.margin;
1451
+ for (const [index, node] of model.nodes.entries()) {
1452
+ const block = node.type === "paragraph" ? paragraphToLayout(
1453
+ node,
1454
+ `paragraph-${index}`,
1455
+ resolved.margin,
1456
+ cursorY,
1457
+ contentWidth,
1458
+ resolved.minLineHeight
1459
+ ) : tableToLayout(node, `table-${index}`, resolved.margin, cursorY, contentWidth, resolved);
1460
+ const blockHeight = estimateBlockHeight(block);
1461
+ const currentPage = pages[pages.length - 1];
1462
+ if (cursorY + blockHeight > pageBottom && currentPage.blocks.length > 0) {
1463
+ pages.push({
1464
+ number: pages.length + 1,
1465
+ blocks: []
1466
+ });
1467
+ cursorY = resolved.margin;
1468
+ if (block.kind === "paragraph") {
1469
+ block.y = cursorY;
1470
+ } else {
1471
+ block.y = cursorY;
1472
+ }
1473
+ }
1474
+ pages[pages.length - 1].blocks.push(block);
1475
+ cursorY += blockHeight + (block.kind === "paragraph" ? spacingForBlock(resolved.paragraphSpacing, block.headingLevel) : resolved.paragraphSpacing + 10);
1476
+ }
1477
+ return pages;
1478
+ }
1479
+
1480
+ // src/docx-import.ts
1481
+ init_cjs_shims();
1482
+ var nextImportWorkerRequestId = 1;
1483
+ function createAbortError() {
1484
+ if (typeof DOMException !== "undefined") {
1485
+ return new DOMException("DOCX import was aborted", "AbortError");
1486
+ }
1487
+ const error = new Error("DOCX import was aborted");
1488
+ error.name = "AbortError";
1489
+ return error;
1490
+ }
1491
+ function errorFromWorkerResponse(response) {
1492
+ const error = new Error(response.error.message);
1493
+ error.name = response.error.name ?? "Error";
1494
+ if (response.error.stack) {
1495
+ error.stack = response.error.stack;
1496
+ }
1497
+ return error;
1498
+ }
1499
+ function canUseDocxImportWorker(options) {
1500
+ return options.useWorker !== false && typeof Worker !== "undefined";
1501
+ }
1502
+ function createDocxImportWorker() {
1503
+ return new Worker(new URL("./docx-import-worker.js", importMetaUrl), {
1504
+ type: "module",
1505
+ name: "react-docx-import"
1506
+ });
1507
+ }
1508
+ async function importDocxOnMainThread(buffer, signal) {
1509
+ if (signal?.aborted) {
1510
+ throw createAbortError();
1511
+ }
1512
+ const startedAt = performanceNow();
1513
+ const [{ parseDocx: parseDocx2 }, { buildDocModel: buildDocModel2 }] = await Promise.all([
1514
+ Promise.resolve().then(() => (init_src2(), src_exports)),
1515
+ Promise.resolve().then(() => (init_src3(), src_exports2))
1516
+ ]);
1517
+ const pkg = await parseDocx2(buffer);
1518
+ const parsedAt = performanceNow();
1519
+ if (signal?.aborted) {
1520
+ throw createAbortError();
1521
+ }
1522
+ const model = await buildDocModel2(pkg);
1523
+ const finishedAt = performanceNow();
1524
+ if (signal?.aborted) {
1525
+ throw createAbortError();
1526
+ }
1527
+ return {
1528
+ package: pkg,
1529
+ model,
1530
+ source: "main-thread",
1531
+ timings: {
1532
+ totalMs: finishedAt - startedAt,
1533
+ parseMs: parsedAt - startedAt,
1534
+ buildModelMs: finishedAt - parsedAt
1535
+ }
1536
+ };
1537
+ }
1538
+ function performanceNow() {
1539
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
1540
+ }
1541
+ async function importDocxBuffer(buffer, options = {}) {
1542
+ if (options.signal?.aborted) {
1543
+ throw createAbortError();
1544
+ }
1545
+ if (!canUseDocxImportWorker(options)) {
1546
+ return importDocxOnMainThread(buffer, options.signal);
1547
+ }
1548
+ let worker;
1549
+ try {
1550
+ worker = createDocxImportWorker();
1551
+ } catch {
1552
+ return importDocxOnMainThread(buffer, options.signal);
1553
+ }
1554
+ const requestId = nextImportWorkerRequestId;
1555
+ nextImportWorkerRequestId += 1;
1556
+ return new Promise((resolve, reject) => {
1557
+ let settled = false;
1558
+ const cleanup = () => {
1559
+ worker.removeEventListener("message", handleMessage);
1560
+ worker.removeEventListener("error", handleError2);
1561
+ worker.removeEventListener("messageerror", handleMessageError);
1562
+ options.signal?.removeEventListener("abort", handleAbort);
1563
+ worker.terminate();
1564
+ };
1565
+ const settle = (resolver) => {
1566
+ if (settled) {
1567
+ return;
1568
+ }
1569
+ settled = true;
1570
+ cleanup();
1571
+ resolver();
1572
+ };
1573
+ const handleAbort = () => {
1574
+ settle(() => reject(createAbortError()));
1575
+ };
1576
+ const handleError2 = (event) => {
1577
+ const message = event.message || "DOCX import worker failed";
1578
+ settle(() => reject(new Error(message)));
1579
+ };
1580
+ const handleMessageError = () => {
1581
+ settle(() => reject(new Error("DOCX import worker returned an unreadable response")));
1582
+ };
1583
+ const handleMessage = (event) => {
1584
+ const response = event.data;
1585
+ if (!response || response.id !== requestId) {
1586
+ return;
1587
+ }
1588
+ if (response.type === "error") {
1589
+ settle(() => reject(errorFromWorkerResponse(response)));
1590
+ return;
1591
+ }
1592
+ settle(
1593
+ () => resolve({
1594
+ package: response.package,
1595
+ model: response.model,
1596
+ source: "worker",
1597
+ timings: response.timings
1598
+ })
1599
+ );
1600
+ };
1601
+ worker.addEventListener("message", handleMessage);
1602
+ worker.addEventListener("error", handleError2);
1603
+ worker.addEventListener("messageerror", handleMessageError);
1604
+ options.signal?.addEventListener("abort", handleAbort, { once: true });
1605
+ try {
1606
+ const request = {
1607
+ id: requestId,
1608
+ type: "import-docx",
1609
+ buffer
1610
+ };
1611
+ const transfer = options.transferBuffer ? [buffer] : [];
1612
+ worker.postMessage(request, transfer);
1613
+ } catch (error) {
1614
+ settle(
1615
+ () => reject(error instanceof Error ? error : new Error("Failed to start DOCX import worker"))
1616
+ );
1617
+ }
1618
+ });
1619
+ }
1365
1620
 
1366
1621
  // src/section-layout.ts
1367
1622
  init_cjs_shims();
@@ -1733,9 +1988,11 @@ var React = __toESM(require("react"), 1);
1733
1988
  var import_react_dom = require("react-dom");
1734
1989
  var import_server = require("react-dom/server");
1735
1990
  var import_react_virtual = require("@tanstack/react-virtual");
1991
+ init_src3();
1736
1992
 
1737
1993
  // ../editor-ops/src/index.ts
1738
1994
  init_cjs_shims();
1995
+ init_src3();
1739
1996
  function paragraphFromText(text, options) {
1740
1997
  return {
1741
1998
  type: "paragraph",
@@ -2718,9 +2975,6 @@ function parseParagraphsFromClipboard(input) {
2718
2975
  }
2719
2976
  }
2720
2977
 
2721
- // src/editor.tsx
2722
- init_src2();
2723
-
2724
2978
  // ../serializer/src/index.ts
2725
2979
  init_cjs_shims();
2726
2980
  init_src();
@@ -3097,6 +3351,13 @@ function reconcilePageCountCandidateToTargetCountByScalingHeight(options) {
3097
3351
  previousScale = scale;
3098
3352
  previousPageCount = candidate.pageCount;
3099
3353
  }
3354
+ if (!needMorePages && selectedCandidate.pageCount !== safeTargetPageCount) {
3355
+ return {
3356
+ pageCount: initialPageCount,
3357
+ pages: initialPages,
3358
+ scale: 1
3359
+ };
3360
+ }
3100
3361
  return selectedCandidate;
3101
3362
  }
3102
3363
 
@@ -4371,6 +4632,20 @@ var SerialIdleTaskQueue = class {
4371
4632
  this.schedulePump();
4372
4633
  });
4373
4634
  }
4635
+ /** Drops queued work for a single key, resolving its waiters. */
4636
+ cancel(key) {
4637
+ const remaining = [];
4638
+ this.pending.forEach((entry) => {
4639
+ if (entry.key === key) {
4640
+ entry.resolvers.forEach((resolveEntry) => {
4641
+ resolveEntry();
4642
+ });
4643
+ return;
4644
+ }
4645
+ remaining.push(entry);
4646
+ });
4647
+ this.pending.splice(0, this.pending.length, ...remaining);
4648
+ }
4374
4649
  /** Drops all queued tasks, resolving their waiters without running them. */
4375
4650
  clear() {
4376
4651
  const dropped = this.pending.splice(0, this.pending.length);
@@ -4555,6 +4830,29 @@ var MEASURED_BODY_FOOTER_OVERLAP_STABILITY_THRESHOLD = 1;
4555
4830
  var WORD_TABLE_CELL_PARAGRAPH_AUTO_LINE_TWIPS = 240;
4556
4831
  var WORD_TABLE_CELL_PARAGRAPH_BEFORE_TWIPS = 0;
4557
4832
  var WORD_TABLE_CELL_PARAGRAPH_AFTER_TWIPS = 0;
4833
+ var DOCX_IMPORT_PERFORMANCE_PREFIX = "react-docx.import";
4834
+ function markDocxImportPerformance(name) {
4835
+ if (typeof performance === "undefined" || typeof performance.mark !== "function") {
4836
+ return;
4837
+ }
4838
+ try {
4839
+ performance.mark(name);
4840
+ } catch {
4841
+ }
4842
+ }
4843
+ function measureDocxImportPerformance(name, startMark, endMark) {
4844
+ if (typeof performance === "undefined" || typeof performance.measure !== "function") {
4845
+ return;
4846
+ }
4847
+ try {
4848
+ performance.measure(name, startMark, endMark);
4849
+ } catch {
4850
+ }
4851
+ }
4852
+ function createDocxImportPerformanceTraceName(fileName) {
4853
+ const normalizedName = fileName.replace(/[^a-z0-9._-]+/gi, "_").slice(0, 80);
4854
+ return `${DOCX_IMPORT_PERFORMANCE_PREFIX}.${Date.now()}.${normalizedName}`;
4855
+ }
4558
4856
  var TABLE_ROW_SLICE_VISUAL_BLEED_PX = 1;
4559
4857
  var TABLE_CELL_SLICE_FULLY_VISIBLE_BOTTOM_BUFFER_PX = 4;
4560
4858
  var DEFAULT_SPLIT_PARAGRAPH_LINE_TWIPS = 259;
@@ -4642,6 +4940,7 @@ var tableEstimatedRowHeightsByNode = /* @__PURE__ */ new WeakMap();
4642
4940
  var paragraphExplicitIndentBySourceXml = /* @__PURE__ */ new Map();
4643
4941
  var paragraphDropCapBySourceXml = /* @__PURE__ */ new Map();
4644
4942
  var paragraphTrackedMarkupBySourceXml = /* @__PURE__ */ new Map();
4943
+ var paragraphCommentMarkupBySourceXml = /* @__PURE__ */ new Map();
4645
4944
  var paragraphMeasureCanvasContext;
4646
4945
  var textWidthByFontAndValue = /* @__PURE__ */ new Map();
4647
4946
  var estimatedTextAdvanceWidthByFontAndValue = /* @__PURE__ */ new Map();
@@ -7139,15 +7438,6 @@ function paragraphHasOnlyWhitespaceText(paragraph) {
7139
7438
  function paragraphContainsSectionBreakProperties(paragraph) {
7140
7439
  return /<w:sectPr\b/i.test(paragraph.sourceXml ?? "");
7141
7440
  }
7142
- function paragraphAbsoluteFloatingAnchorsDependOnParagraphFlow(paragraph) {
7143
- return paragraph.children.some((child) => {
7144
- if (child.type !== "image" || !shouldRenderAbsoluteFloatingImage(child) || child.syntheticTextBox !== true || !floatingTextBoxVisibleTextFromImage(child) || child.floating?.behindDocument !== true) {
7145
- return false;
7146
- }
7147
- const verticalRelativeTo = child.floating?.verticalRelativeTo?.trim().toLowerCase();
7148
- return verticalRelativeTo === void 0 || verticalRelativeTo === "" || verticalRelativeTo === "paragraph" || verticalRelativeTo === "line";
7149
- });
7150
- }
7151
7441
  function likelyFullPageCoverImageRelativeToContentBox(image, pageContentWidthPx, pageContentHeightPx) {
7152
7442
  if (!shouldRenderAbsoluteFloatingImage(image) || !image.floating) {
7153
7443
  return false;
@@ -9375,8 +9665,11 @@ function emptyParagraphLineScaleForFontFamily(fontFamily) {
9375
9665
  }
9376
9666
  return WORD_EMPTY_PARAGRAPH_LINE_SCALE;
9377
9667
  }
9668
+ function paragraphRendersTextFreeLine(paragraph) {
9669
+ return paragraphHasOnlyWhitespaceText(paragraph) || paragraphIsFloatingImageAnchorOnly(paragraph);
9670
+ }
9378
9671
  function resolveParagraphSingleLineAutoScale(paragraph, fontFamily) {
9379
- if (paragraphHasOnlyWhitespaceText(paragraph)) {
9672
+ if (paragraphRendersTextFreeLine(paragraph)) {
9380
9673
  return emptyParagraphLineScaleForFontFamily(fontFamily);
9381
9674
  }
9382
9675
  const baseScale = singleLineAutoScaleForFontFamily(fontFamily);
@@ -9649,9 +9942,7 @@ function estimateTabLeaderWrappedLineCountForParagraph(paragraph, maxLineWidthPx
9649
9942
  leadingSegments,
9650
9943
  paragraphBaseFontPx
9651
9944
  );
9652
- const tabStopPositionsPx = (paragraph.style?.tabStops ?? []).map((tabStop) => twipsToPixels(tabStop.positionTwips)).filter(
9653
- (positionPx) => Number.isFinite(positionPx) && positionPx > 0
9654
- ).sort((left, right) => left - right);
9945
+ const tabStopPositionsPx = resolveParagraphFirstLineLeftTabStopsPx(paragraph);
9655
9946
  const explicitLeadingTabStopPx = tableOfContentsLeadingLeftTabStopPx(paragraph);
9656
9947
  const leadingReservationWidthPx = leadingSegments.length === 0 ? 0 : Number.isFinite(explicitLeadingTabStopPx) && explicitLeadingTabStopPx > 0 ? Math.max(
9657
9948
  leadingTextWidthPx,
@@ -10194,7 +10485,7 @@ function estimateParagraphLineHeightPx(paragraph, docGridLinePitchPx, disableDoc
10194
10485
  lineTwips,
10195
10486
  defaultLineMultiple
10196
10487
  );
10197
- const multiple = paragraphHasOnlyWhitespaceText(paragraph) ? Math.max(
10488
+ const multiple = paragraphRendersTextFreeLine(paragraph) ? Math.max(
10198
10489
  MIN_AUTO_LINE_MULTIPLE,
10199
10490
  Number((resolvedAutoMultiple * singleLineScale).toFixed(3))
10200
10491
  ) : calibrateAutoLineSpacingMultiple(
@@ -10253,10 +10544,7 @@ function estimateParagraphHeightPx(paragraph, availableWidthPx, numberingDefinit
10253
10544
  numberingLabel
10254
10545
  );
10255
10546
  const absoluteFloatingAnchorOnlyParagraph = paragraphIsAbsoluteFloatingImageAnchorOnly(paragraph);
10256
- const sectionBreakAnchorCarryoverParagraph = paragraphIsSectionBreakAnchorCarryover(paragraph);
10257
- const collapsibleAbsoluteFloatingAnchorOnlyParagraph = absoluteFloatingAnchorOnlyParagraph && (!paragraphAbsoluteFloatingAnchorsDependOnParagraphFlow(paragraph) || sectionBreakAnchorCarryoverParagraph);
10258
- const paragraphFlowAnchoredAbsoluteFloatingAnchorOnlyParagraph = absoluteFloatingAnchorOnlyParagraph && !collapsibleAbsoluteFloatingAnchorOnlyParagraph;
10259
- const decorativeBehindTextAnchorOnlyParagraph = paragraphActsAsDecorativeBehindTextBackgroundOverlay(paragraph);
10547
+ const collapsibleAbsoluteFloatingAnchorOnlyParagraph = absoluteFloatingAnchorOnlyParagraph && paragraphIsSectionBreakAnchorCarryover(paragraph);
10260
10548
  const inlineImageHeightPx = paragraph.children.reduce((largest, child) => {
10261
10549
  if (child.type !== "image") {
10262
10550
  return largest;
@@ -10275,14 +10563,14 @@ function estimateParagraphHeightPx(paragraph, availableWidthPx, numberingDefinit
10275
10563
  estimateWrappedFloatingImageFootprintPx(paragraph, child)
10276
10564
  );
10277
10565
  }, 0);
10278
- const emptyParagraphHeightPx = decorativeBehindTextAnchorOnlyParagraph ? 0 : paragraphIsEffectivelyEmpty(paragraph) ? lineHeightPx + EMPTY_PARAGRAPH_EXTRA_HEIGHT_PX : 0;
10566
+ const emptyParagraphHeightPx = paragraphIsEffectivelyEmpty(paragraph) ? lineHeightPx + EMPTY_PARAGRAPH_EXTRA_HEIGHT_PX : 0;
10279
10567
  const topBorderInsetPx = paragraphBorderInsetPx(
10280
10568
  paragraph.style?.borders?.top
10281
10569
  );
10282
10570
  const bottomBorderInsetPx = paragraphBorderInsetPx(
10283
10571
  paragraph.style?.borders?.bottom
10284
10572
  );
10285
- const textFlowHeightPx = collapsibleAbsoluteFloatingAnchorOnlyParagraph ? 0 : paragraphFlowAnchoredAbsoluteFloatingAnchorOnlyParagraph ? MIN_PARAGRAPH_LINE_HEIGHT_PX : (
10573
+ const textFlowHeightPx = collapsibleAbsoluteFloatingAnchorOnlyParagraph ? 0 : (
10286
10574
  // When excluding the wrapped-float footprint, the dual-wrapped block
10287
10575
  // height spans the image; but the rendered paragraph only occupies its
10288
10576
  // text lines while the float overhangs. Use the text-line height so the
@@ -10290,7 +10578,7 @@ function estimateParagraphHeightPx(paragraph, availableWidthPx, numberingDefinit
10290
10578
  dualWrappedLayout && !excludeWrappedFloatingImageFootprint ? wrappedPretextParagraphBlockHeightPx(dualWrappedLayout.layout) : lineHeightPx * lineCount
10291
10579
  );
10292
10580
  const contentHeightPx = Math.max(
10293
- collapsibleAbsoluteFloatingAnchorOnlyParagraph || decorativeBehindTextAnchorOnlyParagraph ? 0 : paragraphFlowAnchoredAbsoluteFloatingAnchorOnlyParagraph ? MIN_PARAGRAPH_LINE_HEIGHT_PX : lineHeightPx,
10581
+ collapsibleAbsoluteFloatingAnchorOnlyParagraph ? 0 : lineHeightPx,
10294
10582
  textFlowHeightPx,
10295
10583
  inlineImageHeightPx,
10296
10584
  wrappedFloatingImageHeightPx,
@@ -11617,11 +11905,6 @@ function buildDocumentPageNodeSegments(model, pageContentHeightPx, pageContentWi
11617
11905
  previousParagraphAfterPx = 0;
11618
11906
  continue;
11619
11907
  }
11620
- if (node.type === "paragraph" && paragraphActsAsDecorativeBehindTextBackgroundOverlay(node)) {
11621
- currentPageSegments.push({ nodeIndex });
11622
- previousParagraphAfterPx = 0;
11623
- continue;
11624
- }
11625
11908
  if (node.type === "paragraph" && paragraphCollapsesIntoPreviousParagraph(node, model.nodes[nodeIndex - 1])) {
11626
11909
  continue;
11627
11910
  }
@@ -12895,7 +13178,7 @@ function paragraphLineHeight(paragraph, docGridLinePitchPx, disableDocGridSnap =
12895
13178
  lineTwips,
12896
13179
  DEFAULT_PARAGRAPH_LINE_MULTIPLE
12897
13180
  );
12898
- const lineMultiple = paragraphHasOnlyWhitespaceText(paragraph) ? Math.max(
13181
+ const lineMultiple = paragraphRendersTextFreeLine(paragraph) ? Math.max(
12899
13182
  MIN_AUTO_LINE_MULTIPLE,
12900
13183
  Number((resolvedAutoMultiple * singleLineScale).toFixed(3))
12901
13184
  ) : calibrateAutoLineSpacingMultiple(
@@ -13242,8 +13525,7 @@ function paragraphBlockStyle(paragraph, numberingDefinitions, headingStyles, doc
13242
13525
  const suppressTocNumberingTextIndent = isTableOfContentsParagraph(paragraph) && paragraphHasNumbering(paragraph);
13243
13526
  const suppressIndentForFloatingAnchorOnlyParagraph = paragraphIsFloatingImageAnchorOnly(paragraph);
13244
13527
  const suppressStackingContextForBehindTextAnchorOnlyParagraph = paragraphIsBehindTextAbsoluteFloatingImageAnchorOnly(paragraph);
13245
- const suppressFlowFootprintForBehindTextAnchorOnlyParagraph = paragraphActsAsDecorativeBehindTextBackgroundOverlay(paragraph);
13246
- const reservedMinHeightPx = suppressFlowFootprintForBehindTextAnchorOnlyParagraph ? void 0 : paragraphIsEffectivelyEmpty(paragraph) ? estimateParagraphLineHeightPx(
13528
+ const reservedMinHeightPx = paragraphIsEffectivelyEmpty(paragraph) ? estimateParagraphLineHeightPx(
13247
13529
  paragraph,
13248
13530
  docGridLinePitchPx,
13249
13531
  disableDocGridSnap
@@ -13262,15 +13544,13 @@ function paragraphBlockStyle(paragraph, numberingDefinitions, headingStyles, doc
13262
13544
  // line-box strut tracks the actual content instead of the browser's
13263
13545
  // 16px default, which inflates lines for sub-12pt paragraphs.
13264
13546
  fontSize: `${paragraphBaseFontSizePx(paragraph)}px`,
13265
- lineHeight: suppressFlowFootprintForBehindTextAnchorOnlyParagraph ? 0 : paragraphLineHeight(paragraph, docGridLinePitchPx, disableDocGridSnap),
13266
- ...suppressFlowFootprintForBehindTextAnchorOnlyParagraph ? {
13267
- height: 0,
13268
- marginTop: 0,
13269
- marginBottom: 0
13270
- } : {
13271
- marginTop: beforeSpacing,
13272
- marginBottom: afterSpacing
13273
- },
13547
+ lineHeight: paragraphLineHeight(
13548
+ paragraph,
13549
+ docGridLinePitchPx,
13550
+ disableDocGridSnap
13551
+ ),
13552
+ marginTop: beforeSpacing,
13553
+ marginBottom: afterSpacing,
13274
13554
  marginLeft: suppressIndentForFloatingAnchorOnlyParagraph ? 0 : leftIndent,
13275
13555
  marginRight: suppressIndentForFloatingAnchorOnlyParagraph ? 0 : rightIndent,
13276
13556
  backgroundColor: paragraph.style?.backgroundColor,
@@ -13528,10 +13808,7 @@ function tableOfContentsLeadingLeftTabStopPx(paragraph) {
13528
13808
  if (!isTableOfContentsParagraph(paragraph)) {
13529
13809
  return void 0;
13530
13810
  }
13531
- const leftTabStopPositionsPx = (paragraph.style?.tabStops ?? []).filter((tabStop) => tabStop.alignment === "left").map((tabStop) => twipsToPixels(tabStop.positionTwips)).filter(
13532
- (positionPx) => Number.isFinite(positionPx) && positionPx > 0
13533
- ).sort((left, right) => left - right);
13534
- return leftTabStopPositionsPx[0];
13811
+ return resolveParagraphFirstLineLeftTabStopsPx(paragraph)[0];
13535
13812
  }
13536
13813
  function paragraphContainsTabCharacter(paragraph) {
13537
13814
  return paragraph.children.some((child) => {
@@ -14581,6 +14858,81 @@ function resolveParagraphTrackedMarkup(paragraph) {
14581
14858
  setCacheEntry(paragraphTrackedMarkupBySourceXml, sourceXml, resolved);
14582
14859
  return resolved;
14583
14860
  }
14861
+ function resolveParagraphCommentMarkup(paragraph) {
14862
+ const sourceXml = paragraph.sourceXml ?? "";
14863
+ if (!sourceXml || !/commentRange|commentReference/i.test(sourceXml)) {
14864
+ return void 0;
14865
+ }
14866
+ const cached = paragraphCommentMarkupBySourceXml.get(sourceXml);
14867
+ if (cached !== void 0) {
14868
+ return cached ?? void 0;
14869
+ }
14870
+ const rangeStartById = /* @__PURE__ */ new Map();
14871
+ const rangeEndById = /* @__PURE__ */ new Map();
14872
+ for (const match of sourceXml.matchAll(
14873
+ /<w:commentRangeStart\b[^>]*w:id="(-?\d+)"[^>]*\/?>/gi
14874
+ )) {
14875
+ const commentId = Number.parseInt(match[1] ?? "", 10);
14876
+ if (Number.isFinite(commentId) && match.index !== void 0) {
14877
+ rangeStartById.set(commentId, match.index + match[0].length);
14878
+ }
14879
+ }
14880
+ for (const match of sourceXml.matchAll(
14881
+ /<w:commentRangeEnd\b[^>]*w:id="(-?\d+)"[^>]*\/?>/gi
14882
+ )) {
14883
+ const commentId = Number.parseInt(match[1] ?? "", 10);
14884
+ if (Number.isFinite(commentId) && match.index !== void 0) {
14885
+ rangeEndById.set(commentId, match.index);
14886
+ }
14887
+ }
14888
+ const ranges = [];
14889
+ const rangeIds = /* @__PURE__ */ new Set([
14890
+ ...rangeStartById.keys(),
14891
+ ...rangeEndById.keys()
14892
+ ]);
14893
+ rangeIds.forEach((commentId) => {
14894
+ const start = rangeStartById.get(commentId) ?? 0;
14895
+ const end = rangeEndById.get(commentId) ?? sourceXml.length;
14896
+ if (end > start) {
14897
+ ranges.push({ commentId, start, end });
14898
+ }
14899
+ });
14900
+ if (ranges.length === 0) {
14901
+ setCacheEntry(paragraphCommentMarkupBySourceXml, sourceXml, null);
14902
+ return void 0;
14903
+ }
14904
+ const commentIdsByVisibleChildIndex = [];
14905
+ let visibleChildIndex = 0;
14906
+ const runPattern = /<w:r\b[\s\S]*?<\/w:r>/gi;
14907
+ for (const runMatch of sourceXml.matchAll(runPattern)) {
14908
+ const runXml = runMatch[0] ?? "";
14909
+ if (!runXml) {
14910
+ continue;
14911
+ }
14912
+ const runStart = runMatch.index ?? 0;
14913
+ const contentRunXml = stripTextBoxContentFromRunXml(runXml);
14914
+ const visibleTokens = parseTrackedRunTokens(contentRunXml, false);
14915
+ const hasImage = /<w:(?:drawing|pict)\b/i.test(runXml);
14916
+ const visibleChildCount = visibleTokens.filter((token) => token.text.length > 0 || token.isNote).length + (hasImage ? 1 : 0);
14917
+ if (visibleChildCount === 0) {
14918
+ continue;
14919
+ }
14920
+ const activeCommentIds = ranges.filter((range) => runStart >= range.start && runStart < range.end).map((range) => range.commentId);
14921
+ if (activeCommentIds.length > 0) {
14922
+ for (let index = 0; index < visibleChildCount; index += 1) {
14923
+ commentIdsByVisibleChildIndex[visibleChildIndex + index] = activeCommentIds;
14924
+ }
14925
+ }
14926
+ visibleChildIndex += visibleChildCount;
14927
+ }
14928
+ if (commentIdsByVisibleChildIndex.length === 0) {
14929
+ setCacheEntry(paragraphCommentMarkupBySourceXml, sourceXml, null);
14930
+ return void 0;
14931
+ }
14932
+ const resolved = { commentIdsByVisibleChildIndex };
14933
+ setCacheEntry(paragraphCommentMarkupBySourceXml, sourceXml, resolved);
14934
+ return resolved;
14935
+ }
14584
14936
  function instructionTextToPageFieldKind(rawInstruction) {
14585
14937
  const normalized = decodeXmlText(rawInstruction).replace(/\s+/g, " ").trim().toUpperCase();
14586
14938
  if (!normalized || normalized.includes("PAGEREF")) {
@@ -14627,11 +14979,16 @@ function paragraphPageFieldSequence(paragraph) {
14627
14979
  }
14628
14980
  return fields;
14629
14981
  }
14982
+ var pageFieldValueSequenceBySourceXml = /* @__PURE__ */ new Map();
14630
14983
  function paragraphPageFieldValueSequence(paragraph) {
14631
14984
  const xml = paragraph.sourceXml ?? "";
14632
14985
  if (!xml) {
14633
14986
  return [];
14634
14987
  }
14988
+ const cached = pageFieldValueSequenceBySourceXml.get(xml);
14989
+ if (cached) {
14990
+ return cached;
14991
+ }
14635
14992
  const values = [];
14636
14993
  const fieldStack = [];
14637
14994
  const tokenPattern = /<w:fldSimple\b[^>]*\bw:instr="([^"]+)"[^>]*>[\s\S]*?<\/w:fldSimple>|<w:r\b[\s\S]*?<\/w:r>/gi;
@@ -14711,13 +15068,19 @@ function paragraphPageFieldValueSequence(paragraph) {
14711
15068
  fieldStack.pop();
14712
15069
  }
14713
15070
  }
15071
+ setCacheEntry(pageFieldValueSequenceBySourceXml, xml, values);
14714
15072
  return values;
14715
15073
  }
15074
+ var styleRefFieldValueSequenceBySourceXml = /* @__PURE__ */ new Map();
14716
15075
  function paragraphStyleRefFieldValueSequence(paragraph) {
14717
15076
  const xml = paragraph.sourceXml ?? "";
14718
15077
  if (!xml) {
14719
15078
  return [];
14720
15079
  }
15080
+ const cached = styleRefFieldValueSequenceBySourceXml.get(xml);
15081
+ if (cached) {
15082
+ return cached;
15083
+ }
14721
15084
  const values = [];
14722
15085
  const fieldStack = [];
14723
15086
  const tokenPattern = /<w:fldSimple\b[^>]*\bw:instr="([^"]+)"[^>]*>[\s\S]*?<\/w:fldSimple>|<w:r\b[\s\S]*?<\/w:r>/gi;
@@ -14797,6 +15160,7 @@ function paragraphStyleRefFieldValueSequence(paragraph) {
14797
15160
  fieldStack.pop();
14798
15161
  }
14799
15162
  }
15163
+ setCacheEntry(styleRefFieldValueSequenceBySourceXml, xml, values);
14800
15164
  return values;
14801
15165
  }
14802
15166
  function normalizeStyleRefTarget(value) {
@@ -14931,6 +15295,7 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
14931
15295
  const showTrackedChanges = options?.showTrackedChanges === true;
14932
15296
  const showTrackedInlineMarkup = showTrackedChanges && options?.trackedMarkupMode !== "gutter";
14933
15297
  const trackedMarkup = showTrackedInlineMarkup ? resolveParagraphTrackedMarkup(paragraph) : void 0;
15298
+ const commentMarkup = options?.showCommentHighlights === true ? resolveParagraphCommentMarkup(paragraph) : void 0;
14934
15299
  const tocParagraphLevel = tableOfContentsLevel(paragraph);
14935
15300
  const tocLinkColor = tocParagraphLevel ? options?.tocLinkColorByLevel?.[tocParagraphLevel] : void 0;
14936
15301
  const floatingAnchorOriginCorrectionXPx = Number.isFinite(
@@ -14972,8 +15337,19 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
14972
15337
  });
14973
15338
  };
14974
15339
  const currentTrackedInlineChange = () => trackedMarkup?.inlineChangeByVisibleChildIndex[trackedVisibleChildCursor];
15340
+ const currentCommentHighlightStyle = () => {
15341
+ const commentIds = commentMarkup?.commentIdsByVisibleChildIndex[trackedVisibleChildCursor];
15342
+ if (!commentIds || commentIds.length === 0) {
15343
+ return void 0;
15344
+ }
15345
+ const accent = commentAccentColor(documentTheme);
15346
+ return {
15347
+ backgroundColor: documentTheme === "dark" ? "rgba(251, 191, 36, 0.24)" : "rgba(251, 191, 36, 0.3)",
15348
+ borderBottom: `2px solid ${accent}`
15349
+ };
15350
+ };
14975
15351
  const consumeTrackedVisibleChild = (child) => {
14976
- if (!trackedMarkup) {
15352
+ if (!trackedMarkup && !commentMarkup) {
14977
15353
  return;
14978
15354
  }
14979
15355
  if (child.type === "form-field") {
@@ -15142,20 +15518,26 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15142
15518
  const resolveFieldText = (value, preferredZone) => resolvePageFieldText(resolveStyleRefFieldText(value), preferredZone);
15143
15519
  const trackedLinkStyle = (style, trackedInlineChange) => {
15144
15520
  if (!isTableOfContentsParagraph(paragraph)) {
15145
- return trackedInlineStyle(
15146
- linkStyleToCss(style, documentTheme),
15147
- trackedInlineChange
15148
- );
15521
+ return {
15522
+ ...trackedInlineStyle(
15523
+ linkStyleToCss(style, documentTheme),
15524
+ trackedInlineChange
15525
+ ),
15526
+ ...currentCommentHighlightStyle()
15527
+ };
15149
15528
  }
15150
15529
  const base = runStyleToCss(style, documentTheme);
15151
- return trackedInlineStyle(
15152
- {
15153
- ...base,
15154
- color: tocLinkColor ? themedRunColor(tocLinkColor, documentTheme) : "inherit",
15155
- textDecoration: "none"
15156
- },
15157
- trackedInlineChange
15158
- );
15530
+ return {
15531
+ ...trackedInlineStyle(
15532
+ {
15533
+ ...base,
15534
+ color: tocLinkColor ? themedRunColor(tocLinkColor, documentTheme) : "inherit",
15535
+ textDecoration: "none"
15536
+ },
15537
+ trackedInlineChange
15538
+ ),
15539
+ ...currentCommentHighlightStyle()
15540
+ };
15159
15541
  };
15160
15542
  const usesExternalHorizontalAnchorOrigin = (image) => {
15161
15543
  const horizontalRelativeTo = image.floating?.horizontalRelativeTo?.trim().toLowerCase();
@@ -15202,10 +15584,13 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15202
15584
  trackTextAdvance(text, child.style);
15203
15585
  return;
15204
15586
  }
15205
- const trackedStyle = trackedInlineStyle(
15206
- runStyleToCss(child.style, documentTheme),
15207
- trackedInlineChange
15208
- );
15587
+ const trackedStyle = {
15588
+ ...trackedInlineStyle(
15589
+ runStyleToCss(child.style, documentTheme),
15590
+ trackedInlineChange
15591
+ ),
15592
+ ...currentCommentHighlightStyle()
15593
+ };
15209
15594
  if (text === " " && !useTabLeaderLayout && !useAnchoredTabLayout) {
15210
15595
  target.push(
15211
15596
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: tabTextStyle(child.style, trackedStyle), children: "\xA0" }, key)
@@ -15461,10 +15846,13 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15461
15846
  }
15462
15847
  return;
15463
15848
  }
15464
- const textStyle = trackedInlineStyle(
15465
- runStyleToCss(child.style, documentTheme),
15466
- trackedInlineChange
15467
- );
15849
+ const textStyle = {
15850
+ ...trackedInlineStyle(
15851
+ runStyleToCss(child.style, documentTheme),
15852
+ trackedInlineChange
15853
+ ),
15854
+ ...currentCommentHighlightStyle()
15855
+ };
15468
15856
  const noteLabel = noteMarkerLabel(
15469
15857
  child.noteReference,
15470
15858
  safeNoteMarkerIndexes.footnote,
@@ -16753,11 +17141,22 @@ function parseEmbeddedTableRuntimeKey(tableRuntimeKey) {
16753
17141
  descendants
16754
17142
  };
16755
17143
  }
17144
+ var columnWidthsByTable = /* @__PURE__ */ new WeakMap();
16756
17145
  function columnWidthsFromTableDefinition(table, columnCount) {
17146
+ const cachedByCount = columnWidthsByTable.get(table);
17147
+ if (cachedByCount?.has(columnCount)) {
17148
+ return cachedByCount.get(columnCount);
17149
+ }
17150
+ const resolved = computeColumnWidthsFromTableDefinition(table, columnCount);
17151
+ const cache = cachedByCount ?? /* @__PURE__ */ new Map();
17152
+ cache.set(columnCount, resolved);
17153
+ columnWidthsByTable.set(table, cache);
17154
+ return resolved;
17155
+ }
17156
+ function computeColumnWidthsFromTableDefinition(table, columnCount) {
16757
17157
  const gridWidths = table.style?.columnWidthsTwips;
16758
17158
  const rowDerivedWidths = deriveColumnWidthsFromTableRows(table, columnCount);
16759
17159
  if (gridWidths && gridWidths.length === columnCount) {
16760
- console.log("[colw]", columnCount, gridWidths.length, !!rowDerivedWidths, gridConflictsWithRowWidths(table, gridWidths));
16761
17160
  if (rowDerivedWidths && rowDerivedWidths.length > 0 && gridConflictsWithRowWidths(table, gridWidths)) {
16762
17161
  return rowDerivedWidths;
16763
17162
  }
@@ -18298,6 +18697,127 @@ function collectTrackedChangesFromModel(model) {
18298
18697
  });
18299
18698
  return trackedChanges;
18300
18699
  }
18700
+ function decodeCommentRangeText(rangeXml) {
18701
+ const texts = [];
18702
+ for (const match of rangeXml.matchAll(
18703
+ /<w:t\b[^>]*>([\s\S]*?)<\/w:t>/gi
18704
+ )) {
18705
+ texts.push(decodeXmlText(match[1] ?? ""));
18706
+ }
18707
+ const combined = texts.join("").replace(/\s+/g, " ").trim();
18708
+ if (!combined) {
18709
+ return void 0;
18710
+ }
18711
+ return combined.length > 120 ? `${combined.slice(0, 119)}\u2026` : combined;
18712
+ }
18713
+ function resolveCommentAnchorText(sourceXml, commentId) {
18714
+ const startMatch = sourceXml.match(
18715
+ new RegExp(`<w:commentRangeStart\\b[^>]*w:id="${commentId}"[^>]*/?>`, "i")
18716
+ );
18717
+ const endMatch = sourceXml.match(
18718
+ new RegExp(`<w:commentRangeEnd\\b[^>]*w:id="${commentId}"[^>]*/?>`, "i")
18719
+ );
18720
+ const startIndex = startMatch?.index !== void 0 ? startMatch.index + startMatch[0].length : (
18721
+ // Range opened in an earlier paragraph: take from the paragraph start.
18722
+ endMatch?.index !== void 0 ? 0 : void 0
18723
+ );
18724
+ if (startIndex === void 0) {
18725
+ return void 0;
18726
+ }
18727
+ const endIndex = endMatch?.index !== void 0 ? endMatch.index : sourceXml.length;
18728
+ if (endIndex <= startIndex) {
18729
+ return void 0;
18730
+ }
18731
+ return decodeCommentRangeText(sourceXml.slice(startIndex, endIndex));
18732
+ }
18733
+ function collectCommentsFromModel(model) {
18734
+ const definitions = model.metadata.comments ?? [];
18735
+ if (definitions.length === 0) {
18736
+ return [];
18737
+ }
18738
+ const definitionById = new Map(
18739
+ definitions.map((definition) => [definition.id, definition])
18740
+ );
18741
+ const comments = [];
18742
+ const appendParagraphComments = (paragraph, nodeIndex, location) => {
18743
+ const sourceXml = paragraph.sourceXml ?? "";
18744
+ if (!sourceXml || !/commentReference/i.test(sourceXml)) {
18745
+ return;
18746
+ }
18747
+ for (const match of sourceXml.matchAll(
18748
+ /<w:commentReference\b[^>]*w:id="(-?\d+)"/gi
18749
+ )) {
18750
+ const commentId = Number.parseInt(match[1] ?? "", 10);
18751
+ const definition = Number.isFinite(commentId) ? definitionById.get(commentId) : void 0;
18752
+ if (!definition) {
18753
+ continue;
18754
+ }
18755
+ comments.push({
18756
+ id: `${paragraphLocationKey(location)}:comment:${commentId}`,
18757
+ commentId,
18758
+ author: definition.author,
18759
+ initials: definition.initials,
18760
+ date: definition.date,
18761
+ text: definition.text,
18762
+ parentId: definition.parentId,
18763
+ resolved: definition.resolved,
18764
+ anchorText: resolveCommentAnchorText(sourceXml, commentId),
18765
+ nodeIndex,
18766
+ location: location.kind === "paragraph" ? { kind: "paragraph", nodeIndex: location.nodeIndex } : {
18767
+ kind: "table-cell",
18768
+ tableIndex: location.tableIndex,
18769
+ rowIndex: location.rowIndex,
18770
+ cellIndex: location.cellIndex,
18771
+ paragraphIndex: location.paragraphIndex
18772
+ }
18773
+ });
18774
+ }
18775
+ };
18776
+ model.nodes.forEach((node, nodeIndex) => {
18777
+ if (node.type === "paragraph") {
18778
+ appendParagraphComments(node, nodeIndex, {
18779
+ kind: "paragraph",
18780
+ nodeIndex
18781
+ });
18782
+ return;
18783
+ }
18784
+ node.rows.forEach((row, rowIndex) => {
18785
+ row.cells.forEach((cell, cellIndex) => {
18786
+ const directParagraphs = tableCellParagraphs(cell.nodes);
18787
+ directParagraphs.forEach((paragraph, paragraphIndex) => {
18788
+ appendParagraphComments(paragraph, nodeIndex, {
18789
+ kind: "table-cell",
18790
+ tableIndex: nodeIndex,
18791
+ rowIndex,
18792
+ cellIndex,
18793
+ paragraphIndex
18794
+ });
18795
+ });
18796
+ const nestedParagraphs = tableCellParagraphsRecursively(
18797
+ cell.nodes
18798
+ ).filter((paragraph) => !directParagraphs.includes(paragraph));
18799
+ nestedParagraphs.forEach((paragraph, nestedParagraphIndex) => {
18800
+ appendParagraphComments(paragraph, nodeIndex, {
18801
+ kind: "table-cell",
18802
+ tableIndex: nodeIndex,
18803
+ rowIndex,
18804
+ cellIndex,
18805
+ paragraphIndex: -(nestedParagraphIndex + 1)
18806
+ });
18807
+ });
18808
+ });
18809
+ });
18810
+ });
18811
+ return comments;
18812
+ }
18813
+ function commentAccentColor(documentTheme) {
18814
+ return documentTheme === "dark" ? "#fbbf24" : "#d97706";
18815
+ }
18816
+ function estimateCommentCardHeight(comment) {
18817
+ const snippet = comment.text || "Comment";
18818
+ const lines = Math.max(1, Math.ceil(snippet.length / 30));
18819
+ return Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, 34 + lines * 14);
18820
+ }
18301
18821
  function trackedChangeKindLabel(kind) {
18302
18822
  switch (kind) {
18303
18823
  case "insertion":
@@ -18346,15 +18866,15 @@ function trackedChangeAccentColor(kind, documentTheme) {
18346
18866
  return palette.format;
18347
18867
  }
18348
18868
  }
18349
- function trackedChangeSortTuple(change) {
18350
- if (change.location.kind === "paragraph") {
18351
- return [change.location.nodeIndex, 0, 0, 0];
18869
+ function gutterAnnotationSortTuple(location) {
18870
+ if (location.kind === "paragraph") {
18871
+ return [location.nodeIndex, 0, 0, 0];
18352
18872
  }
18353
18873
  return [
18354
- change.location.tableIndex,
18355
- change.location.rowIndex,
18356
- change.location.cellIndex,
18357
- change.location.paragraphIndex
18874
+ location.tableIndex,
18875
+ location.rowIndex,
18876
+ location.cellIndex,
18877
+ location.paragraphIndex
18358
18878
  ];
18359
18879
  }
18360
18880
  function trackedChangeBelongsToPageSegments(location, pageSegments) {
@@ -18373,10 +18893,10 @@ function trackedChangeBelongsToPageSegments(location, pageSegments) {
18373
18893
  return location.rowIndex >= segment.tableRowRange.startRowIndex && location.rowIndex < segment.tableRowRange.endRowIndex;
18374
18894
  });
18375
18895
  }
18376
- function resolveTrackedChangePageIndex(change, pageNodeSegmentsByPage) {
18896
+ function resolveGutterAnnotationPageIndex(location, pageNodeSegmentsByPage) {
18377
18897
  for (let pageIndex = 0; pageIndex < pageNodeSegmentsByPage.length; pageIndex += 1) {
18378
18898
  if (trackedChangeBelongsToPageSegments(
18379
- change.location,
18899
+ location,
18380
18900
  pageNodeSegmentsByPage[pageIndex] ?? []
18381
18901
  )) {
18382
18902
  return pageIndex;
@@ -18431,30 +18951,30 @@ function estimateTrackedChangeCardHeight(change) {
18431
18951
  const lines = Math.max(1, Math.ceil(snippet.length / 30));
18432
18952
  return Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, 34 + lines * 14);
18433
18953
  }
18434
- function layoutTrackedChangesForPage(changes, anchorByChangeId, cardHeightsByChangeId, pageWidthPx, pageHeightPx) {
18435
- if (changes.length === 0) {
18954
+ function layoutTrackedChangesForPage(annotations, anchorByChangeId, cardHeightsByChangeId, pageWidthPx, pageHeightPx) {
18955
+ if (annotations.length === 0) {
18436
18956
  return [];
18437
18957
  }
18438
18958
  const fallbackStride = Math.max(
18439
18959
  18,
18440
- pageHeightPx / Math.max(1, changes.length + 1)
18960
+ pageHeightPx / Math.max(1, annotations.length + 1)
18441
18961
  );
18442
- const withAnchors = changes.map((change, index) => {
18962
+ const withAnchors = annotations.map((annotation, index) => {
18443
18963
  const defaultAnchor = Math.min(
18444
18964
  Math.max(10, Math.round((index + 1) * fallbackStride)),
18445
18965
  Math.max(10, pageHeightPx - 10)
18446
18966
  );
18447
- const anchorPoint = anchorByChangeId.get(change.id);
18967
+ const anchorPoint = anchorByChangeId.get(annotation.id);
18448
18968
  const anchorY = anchorPoint?.y ?? defaultAnchor;
18449
18969
  const anchorX = anchorPoint?.x ?? Math.max(10, pageWidthPx - 10);
18450
- const measuredHeightPx = cardHeightsByChangeId?.get(change.id);
18451
- const estimatedHeightPx = estimateTrackedChangeCardHeight(change);
18970
+ const measuredHeightPx = cardHeightsByChangeId?.get(annotation.id);
18971
+ const estimatedHeightPx = annotation.trackedChange ? estimateTrackedChangeCardHeight(annotation.trackedChange) : annotation.comment ? estimateCommentCardHeight(annotation.comment) : TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX;
18452
18972
  const heightPx = Number.isFinite(measuredHeightPx) && measuredHeightPx > 0 ? Math.max(
18453
18973
  TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX,
18454
18974
  Math.round(measuredHeightPx)
18455
18975
  ) : estimatedHeightPx;
18456
18976
  return {
18457
- change,
18977
+ annotation,
18458
18978
  anchorX: clampNumber(
18459
18979
  Math.round(anchorX),
18460
18980
  10,
@@ -19485,10 +20005,14 @@ function useDocxEditor(options = {}) {
19485
20005
  const [isImporting, setIsImporting] = React.useState(false);
19486
20006
  const [documentTheme, setDocumentThemeState] = React.useState(options.initialDocumentTheme ?? "light");
19487
20007
  const [showTrackedChanges, setShowTrackedChangesState] = React.useState(options.initialShowTrackedChanges ?? false);
20008
+ const [showComments, setShowCommentsState] = React.useState(
20009
+ options.initialShowComments ?? false
20010
+ );
19488
20011
  const [paginationInfo, setPaginationInfo] = React.useState({
19489
20012
  currentPage: 1,
19490
20013
  totalPages: 1
19491
20014
  });
20015
+ const activeImportAbortControllerRef = React.useRef(void 0);
19492
20016
  const [history, setHistory] = React.useState({
19493
20017
  past: [],
19494
20018
  future: []
@@ -19801,6 +20325,9 @@ function useDocxEditor(options = {}) {
19801
20325
  () => collectTrackedChangesFromModel(model),
19802
20326
  [model]
19803
20327
  );
20328
+ const comments = React.useMemo(() => collectCommentsFromModel(model), [
20329
+ model
20330
+ ]);
19804
20331
  const hasUnorderedList = selectedListType === "unordered";
19805
20332
  const hasOrderedList = selectedListType === "ordered";
19806
20333
  const canUndo = history.past.length > 0;
@@ -19821,6 +20348,15 @@ function useDocxEditor(options = {}) {
19821
20348
  const toggleShowTrackedChanges = React.useCallback(() => {
19822
20349
  setShowTrackedChangesState((current) => !current);
19823
20350
  }, []);
20351
+ const setShowComments = React.useCallback(
20352
+ (nextShowComments) => {
20353
+ setShowCommentsState(nextShowComments);
20354
+ },
20355
+ []
20356
+ );
20357
+ const toggleShowComments = React.useCallback(() => {
20358
+ setShowCommentsState((current) => !current);
20359
+ }, []);
19824
20360
  const registerPendingExportModelTransformer = React.useCallback(
19825
20361
  (transformer) => {
19826
20362
  pendingExportModelTransformerRef.current = transformer;
@@ -19884,6 +20420,7 @@ function useDocxEditor(options = {}) {
19884
20420
  );
19885
20421
  React.useEffect(() => {
19886
20422
  return () => {
20423
+ activeImportAbortControllerRef.current?.abort();
19887
20424
  unloadEmbeddedFonts();
19888
20425
  };
19889
20426
  }, [unloadEmbeddedFonts]);
@@ -20019,6 +20556,8 @@ function useDocxEditor(options = {}) {
20019
20556
  );
20020
20557
  const importDocxFile = React.useCallback(
20021
20558
  async (file) => {
20559
+ activeImportAbortControllerRef.current?.abort();
20560
+ activeImportAbortControllerRef.current = void 0;
20022
20561
  if (!/\.docx?$/i.test(file.name)) {
20023
20562
  replaceDocumentWithImportError(
20024
20563
  file.name,
@@ -20029,11 +20568,50 @@ function useDocxEditor(options = {}) {
20029
20568
  setIsImporting(true);
20030
20569
  setImportError(void 0);
20031
20570
  setStatus(`Loading ${file.name}...`);
20571
+ const importAbortController = new AbortController();
20572
+ activeImportAbortControllerRef.current = importAbortController;
20573
+ const traceName = createDocxImportPerformanceTraceName(file.name);
20574
+ const startMark = `${traceName}:start`;
20575
+ const bufferStartMark = `${traceName}:arrayBuffer:start`;
20576
+ const bufferEndMark = `${traceName}:arrayBuffer:end`;
20577
+ const workerStartMark = `${traceName}:worker:start`;
20578
+ const workerEndMark = `${traceName}:worker:end`;
20579
+ const fontsStartMark = `${traceName}:fonts:start`;
20580
+ const fontsEndMark = `${traceName}:fonts:end`;
20581
+ const stateStartMark = `${traceName}:state:start`;
20582
+ const stateEndMark = `${traceName}:state:end`;
20583
+ markDocxImportPerformance(startMark);
20032
20584
  try {
20585
+ markDocxImportPerformance(bufferStartMark);
20033
20586
  const buffer = await file.arrayBuffer();
20034
- const pkg = await parseDocx(buffer);
20587
+ markDocxImportPerformance(bufferEndMark);
20588
+ measureDocxImportPerformance(
20589
+ `${traceName}:arrayBuffer`,
20590
+ bufferStartMark,
20591
+ bufferEndMark
20592
+ );
20593
+ markDocxImportPerformance(workerStartMark);
20594
+ const importResult = await importDocxBuffer(buffer, {
20595
+ signal: importAbortController.signal,
20596
+ transferBuffer: true
20597
+ });
20598
+ markDocxImportPerformance(workerEndMark);
20599
+ measureDocxImportPerformance(
20600
+ `${traceName}:${importResult.source}`,
20601
+ workerStartMark,
20602
+ workerEndMark
20603
+ );
20604
+ const pkg = importResult.package;
20605
+ const nextModel = importResult.model;
20606
+ markDocxImportPerformance(fontsStartMark);
20035
20607
  await loadEmbeddedFontsFromPackage(pkg);
20036
- const nextModel = await buildDocModel(pkg);
20608
+ markDocxImportPerformance(fontsEndMark);
20609
+ measureDocxImportPerformance(
20610
+ `${traceName}:fonts`,
20611
+ fontsStartMark,
20612
+ fontsEndMark
20613
+ );
20614
+ markDocxImportPerformance(stateStartMark);
20037
20615
  setModel(nextModel);
20038
20616
  setDocumentLoadNonce((current) => current + 1);
20039
20617
  setHistory({ past: [], future: [] });
@@ -20046,16 +20624,31 @@ function useDocxEditor(options = {}) {
20046
20624
  setSelectedFormFieldLocation(void 0);
20047
20625
  setImportError(void 0);
20048
20626
  setStatus(`Loaded ${file.name}`);
20627
+ markDocxImportPerformance(stateEndMark);
20628
+ measureDocxImportPerformance(
20629
+ `${traceName}:state-dispatch`,
20630
+ stateStartMark,
20631
+ stateEndMark
20632
+ );
20633
+ measureDocxImportPerformance(`${traceName}:total`, startMark, stateEndMark);
20049
20634
  } catch (error) {
20635
+ if (error instanceof Error && error.name === "AbortError" && activeImportAbortControllerRef.current !== importAbortController) {
20636
+ return;
20637
+ }
20050
20638
  const nextError = error instanceof Error ? error : new Error("Unknown error");
20051
20639
  replaceDocumentWithImportError(file.name, nextError);
20052
20640
  } finally {
20053
- setIsImporting(false);
20641
+ if (activeImportAbortControllerRef.current === importAbortController) {
20642
+ activeImportAbortControllerRef.current = void 0;
20643
+ setIsImporting(false);
20644
+ }
20054
20645
  }
20055
20646
  },
20056
20647
  [loadEmbeddedFontsFromPackage, replaceDocumentWithImportError]
20057
20648
  );
20058
20649
  const newDocument = React.useCallback(() => {
20650
+ activeImportAbortControllerRef.current?.abort();
20651
+ activeImportAbortControllerRef.current = void 0;
20059
20652
  unloadEmbeddedFonts();
20060
20653
  setModel(cloneDocModel(starterTemplateRef.current));
20061
20654
  setDocumentLoadNonce((current) => current + 1);
@@ -22981,6 +23574,8 @@ function useDocxEditor(options = {}) {
22981
23574
  documentTheme,
22982
23575
  trackedChanges,
22983
23576
  showTrackedChanges,
23577
+ comments,
23578
+ showComments,
22984
23579
  currentPage: paginationInfo.currentPage,
22985
23580
  totalPages: paginationInfo.totalPages,
22986
23581
  selection,
@@ -23008,8 +23603,10 @@ function useDocxEditor(options = {}) {
23008
23603
  setStatus,
23009
23604
  setDocumentTheme,
23010
23605
  setShowTrackedChanges,
23606
+ setShowComments,
23011
23607
  syncPaginationInfo,
23012
23608
  toggleShowTrackedChanges,
23609
+ toggleShowComments,
23013
23610
  importDocxFile,
23014
23611
  newDocument,
23015
23612
  exportDocx,
@@ -23296,6 +23893,7 @@ function useDocxPageThumbnails(editor, options = {}) {
23296
23893
  if (!targetCanvas) {
23297
23894
  return;
23298
23895
  }
23896
+ const requiresAttachedTarget = canvas === void 0;
23299
23897
  const pageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
23300
23898
  if (!pageElement || !pageElement.isConnected) {
23301
23899
  updatePageThumbnailState(pageIndex, "unavailable");
@@ -23309,6 +23907,9 @@ function useDocxPageThumbnails(editor, options = {}) {
23309
23907
  }
23310
23908
  updatePageThumbnailState(pageIndex, "rendering");
23311
23909
  await ensureThumbnailRasterQueue().enqueue(targetCanvas, async () => {
23910
+ if (requiresAttachedTarget && attachedCanvasByPageRef.current.get(pageIndex) !== targetCanvas) {
23911
+ return;
23912
+ }
23312
23913
  const livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
23313
23914
  if (!livePageElement || !livePageElement.isConnected) {
23314
23915
  updatePageThumbnailState(pageIndex, "unavailable");
@@ -23455,6 +24056,10 @@ function useDocxPageThumbnails(editor, options = {}) {
23455
24056
  void renderPageThumbnailToCanvasRef.current(pageIndex, canvas);
23456
24057
  return;
23457
24058
  }
24059
+ const previousCanvas = attachedCanvasByPageRef.current.get(pageIndex);
24060
+ if (previousCanvas) {
24061
+ thumbnailRasterQueueRef.current?.cancel(previousCanvas);
24062
+ }
23458
24063
  attachedCanvasByPageRef.current.delete(pageIndex);
23459
24064
  };
23460
24065
  canvasRefCallbacksRef.current.set(pageIndex, nextCanvasRef);
@@ -23722,6 +24327,42 @@ function useDocxTrackChanges(editor) {
23722
24327
  ]
23723
24328
  );
23724
24329
  }
24330
+ function useDocxComments(editor) {
24331
+ const commentsByLocation = React.useMemo(() => {
24332
+ const grouped = /* @__PURE__ */ new Map();
24333
+ editor.comments.forEach((comment) => {
24334
+ const key = paragraphLocationKey(comment.location);
24335
+ const bucket = grouped.get(key) ?? [];
24336
+ bucket.push(comment);
24337
+ grouped.set(key, bucket);
24338
+ });
24339
+ return grouped;
24340
+ }, [editor.comments]);
24341
+ const getCommentsForLocation = React.useCallback(
24342
+ (location) => {
24343
+ return commentsByLocation.get(paragraphLocationKey(location)) ?? [];
24344
+ },
24345
+ [commentsByLocation]
24346
+ );
24347
+ return React.useMemo(
24348
+ () => ({
24349
+ comments: editor.comments,
24350
+ showComments: editor.showComments,
24351
+ setShowComments: editor.setShowComments,
24352
+ toggleShowComments: editor.toggleShowComments,
24353
+ commentsByLocation,
24354
+ getCommentsForLocation
24355
+ }),
24356
+ [
24357
+ editor.comments,
24358
+ editor.showComments,
24359
+ editor.setShowComments,
24360
+ editor.toggleShowComments,
24361
+ commentsByLocation,
24362
+ getCommentsForLocation
24363
+ ]
24364
+ );
24365
+ }
23725
24366
  function useDocxPageLayout(editor) {
23726
24367
  const primarySectionPropertiesXml = editor.model.metadata.sections?.[0]?.sectionPropertiesXml ?? editor.model.metadata.sectionPropertiesXml;
23727
24368
  const layout = React.useMemo(() => {
@@ -24594,6 +25235,8 @@ function DocxEditorViewer({
24594
25235
  headingStyles,
24595
25236
  showTrackedChanges,
24596
25237
  renderTrackedChangeCard,
25238
+ showComments,
25239
+ renderCommentCard,
24597
25240
  renderTableContextMenu,
24598
25241
  renderContextMenu,
24599
25242
  onFormFieldDoubleClick,
@@ -24602,7 +25245,9 @@ function DocxEditorViewer({
24602
25245
  const pageSurfaceRegistryOwner = docxViewerPageSurfaceRegistryOwner(editor);
24603
25246
  const trackedChangesEnabled = showTrackedChanges ?? editor.showTrackedChanges;
24604
25247
  const hasTrackedChanges = editor.trackedChanges.length > 0;
24605
- const showTrackedChangeGutter = trackedChangesEnabled;
25248
+ const commentsEnabled = showComments ?? editor.showComments;
25249
+ const hasComments = editor.comments.length > 0;
25250
+ const showTrackedChangeGutter = trackedChangesEnabled || commentsEnabled;
24606
25251
  const isReadOnly = mode === "read-only" || trackedChangesEnabled;
24607
25252
  const isNightReaderMode = isReadOnly && editor.documentTheme === "dark";
24608
25253
  const documentContentTheme = isNightReaderMode ? "light" : editor.documentTheme;
@@ -24621,11 +25266,13 @@ function DocxEditorViewer({
24621
25266
  const paragraphRunRenderOptions = React.useMemo(
24622
25267
  () => ({
24623
25268
  showTrackedChanges: trackedChangesEnabled,
25269
+ showCommentHighlights: commentsEnabled,
24624
25270
  numberingDefinitions: editor.model.metadata.numberingDefinitions,
24625
25271
  tocLinkColorByLevel,
24626
25272
  imageFilterSuffix: documentContentFilter
24627
25273
  }),
24628
25274
  [
25275
+ commentsEnabled,
24629
25276
  documentContentFilter,
24630
25277
  editor.model.metadata.numberingDefinitions,
24631
25278
  tocLinkColorByLevel,
@@ -24668,7 +25315,6 @@ function DocxEditorViewer({
24668
25315
  /* @__PURE__ */ new Map()
24669
25316
  );
24670
25317
  const pageElementsRef = React.useRef(/* @__PURE__ */ new Map());
24671
- const pagePlaceholderRefCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
24672
25318
  const pageSurfaceRefCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
24673
25319
  const trackedChangeCardElementsRef = React.useRef(/* @__PURE__ */ new Map());
24674
25320
  const initialPaginationStableSignatureRef = React.useRef(
@@ -24736,26 +25382,6 @@ function DocxEditorViewer({
24736
25382
  measuredPageContentHeightByIndex,
24737
25383
  setMeasuredPageContentHeightByIndex
24738
25384
  ] = React.useState([]);
24739
- const pagePlaceholderRefForIndex = React.useCallback(
24740
- (pageIndex) => {
24741
- const normalizedPageIndex = Math.max(0, Math.round(pageIndex));
24742
- const cached = pagePlaceholderRefCallbacksRef.current.get(normalizedPageIndex);
24743
- if (cached) {
24744
- return cached;
24745
- }
24746
- const nextRef = (element) => {
24747
- if (element) {
24748
- pageElementsRef.current.set(normalizedPageIndex, element);
24749
- } else {
24750
- pageElementsRef.current.delete(normalizedPageIndex);
24751
- }
24752
- registerDocxViewerPageSurface(editor, normalizedPageIndex, void 0);
24753
- };
24754
- pagePlaceholderRefCallbacksRef.current.set(normalizedPageIndex, nextRef);
24755
- return nextRef;
24756
- },
24757
- [pageSurfaceRegistryOwner]
24758
- );
24759
25385
  const pageSurfaceRefForIndex = React.useCallback(
24760
25386
  (pageIndex) => {
24761
25387
  const normalizedPageIndex = Math.max(0, Math.round(pageIndex));
@@ -24777,7 +25403,6 @@ function DocxEditorViewer({
24777
25403
  [pageSurfaceRegistryOwner]
24778
25404
  );
24779
25405
  React.useEffect(() => {
24780
- pagePlaceholderRefCallbacksRef.current.clear();
24781
25406
  pageSurfaceRefCallbacksRef.current.clear();
24782
25407
  }, [pageSurfaceRegistryOwner]);
24783
25408
  const [
@@ -26051,6 +26676,26 @@ function DocxEditorViewer({
26051
26676
  nearestScrollableAncestor(viewerRootRef.current)
26052
26677
  );
26053
26678
  }, [editor.documentLoadNonce, pageCount, trackedChangesEnabled]);
26679
+ const [zoomProbeNonce, setZoomProbeNonce] = React.useState(0);
26680
+ React.useEffect(() => {
26681
+ if (typeof window === "undefined") {
26682
+ return;
26683
+ }
26684
+ const rootElement = viewerRootRef.current;
26685
+ if (!rootElement) {
26686
+ return;
26687
+ }
26688
+ const bumpZoomProbe = () => {
26689
+ setZoomProbeNonce((nonce) => nonce + 1);
26690
+ };
26691
+ const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(bumpZoomProbe) : void 0;
26692
+ resizeObserver?.observe(rootElement);
26693
+ window.addEventListener("resize", bumpZoomProbe);
26694
+ return () => {
26695
+ resizeObserver?.disconnect();
26696
+ window.removeEventListener("resize", bumpZoomProbe);
26697
+ };
26698
+ }, [editor.documentLoadNonce]);
26054
26699
  React.useLayoutEffect(() => {
26055
26700
  if (typeof window === "undefined") {
26056
26701
  return;
@@ -26063,7 +26708,7 @@ function DocxEditorViewer({
26063
26708
  setVirtualizerMeasurementScale(
26064
26709
  (current) => Math.abs(current - nextScale) < 5e-3 ? current : nextScale
26065
26710
  );
26066
- });
26711
+ }, [editor.documentLoadNonce, pageCount, zoomProbeNonce]);
26067
26712
  const internalPageVirtualizationEnabled = internalPageVirtualizationRequested && internalVirtualScrollElement !== null;
26068
26713
  const internalPageVirtualizationPending = typeof window !== "undefined" && internalPageVirtualizationRequested && internalVirtualScrollElement === null;
26069
26714
  const internalVirtualScrollUsesWindow = typeof document !== "undefined" && internalVirtualScrollElement !== null && (internalVirtualScrollElement === document.scrollingElement || internalVirtualScrollElement === document.documentElement || internalVirtualScrollElement === document.body);
@@ -26097,7 +26742,39 @@ function DocxEditorViewer({
26097
26742
  overscan: pageVirtualizationOverscan
26098
26743
  });
26099
26744
  const internalPageVirtualizer = internalVirtualScrollUsesWindow ? internalWindowPageVirtualizer : internalElementPageVirtualizer;
26745
+ React.useLayoutEffect(() => {
26746
+ internalElementPageVirtualizer.measure();
26747
+ internalWindowPageVirtualizer.measure();
26748
+ }, [
26749
+ estimateVirtualPageSize,
26750
+ internalElementPageVirtualizer,
26751
+ internalWindowPageVirtualizer
26752
+ ]);
26100
26753
  const internalVirtualItems = internalPageVirtualizer.getVirtualItems();
26754
+ const internalMostVisiblePageIndex = React.useMemo(() => {
26755
+ if (!internalPageVirtualizationEnabled || internalVirtualItems.length === 0) {
26756
+ return void 0;
26757
+ }
26758
+ const virtualizerMetrics = internalPageVirtualizer;
26759
+ const viewportStart = Number.isFinite(virtualizerMetrics.scrollOffset) ? virtualizerMetrics.scrollOffset : internalVirtualItems[0]?.start ?? 0;
26760
+ const viewportSize = virtualizerMetrics.scrollRect?.height;
26761
+ const viewportEnd = viewportStart + (Number.isFinite(viewportSize) && viewportSize > 0 ? viewportSize : internalVirtualItems[0]?.size ?? 0);
26762
+ let bestPageIndex;
26763
+ let bestVisibleSize = -1;
26764
+ internalVirtualItems.forEach((item) => {
26765
+ const visibleSize = Math.min(item.end, viewportEnd) - Math.max(item.start, viewportStart);
26766
+ if (visibleSize > bestVisibleSize) {
26767
+ bestVisibleSize = visibleSize;
26768
+ bestPageIndex = item.index;
26769
+ }
26770
+ });
26771
+ return bestPageIndex === void 0 ? void 0 : clampNumber(bestPageIndex, 0, pageCount - 1);
26772
+ }, [
26773
+ internalPageVirtualizationEnabled,
26774
+ internalPageVirtualizer,
26775
+ internalVirtualItems,
26776
+ pageCount
26777
+ ]);
26101
26778
  const internalVisiblePageRange = React.useMemo(() => {
26102
26779
  if (!internalPageVirtualizationEnabled) {
26103
26780
  return void 0;
@@ -26139,8 +26816,8 @@ function DocxEditorViewer({
26139
26816
  return internalVisiblePageRange;
26140
26817
  }
26141
26818
  const scrollDirection = internalPageVirtualizer.scrollDirection;
26142
- const renderPreviousPage = scrollDirection !== "backward";
26143
- const renderNextPage = scrollDirection === "backward";
26819
+ const renderPreviousPage = scrollDirection !== "forward";
26820
+ const renderNextPage = scrollDirection !== "backward";
26144
26821
  const startPageIndex = clampNumber(
26145
26822
  internalVisiblePageRange.startPageIndex - (renderPreviousPage ? LARGE_TABLE_PAGE_ADJACENT_RENDER_COUNT : 0),
26146
26823
  0,
@@ -26388,6 +27065,40 @@ function DocxEditorViewer({
26388
27065
  }
26389
27066
  return indexes;
26390
27067
  }, [pageCount, visiblePageEndIndex, visiblePageStartIndex]);
27068
+ const pageStackVirtualSpacers = React.useMemo(() => {
27069
+ const pageWrapperWidthPxForIndex = (pageIndex) => {
27070
+ const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
27071
+ return showTrackedChangeGutter ? pageLayout.pageWidthPx + TRACKED_CHANGE_GUTTER_WIDTH_PX : pageLayout.pageWidthPx;
27072
+ };
27073
+ const summarizeSkippedPages = (startPageIndex, endPageIndex) => {
27074
+ if (pageCount <= 0 || endPageIndex < startPageIndex || startPageIndex >= pageCount || endPageIndex < 0) {
27075
+ return { heightPx: 0, widthPx: 0 };
27076
+ }
27077
+ const start = clampNumber(startPageIndex, 0, pageCount - 1);
27078
+ const end = clampNumber(endPageIndex, start, pageCount - 1);
27079
+ let heightPx = 0;
27080
+ let widthPx = 0;
27081
+ for (let pageIndex = start; pageIndex <= end; pageIndex += 1) {
27082
+ const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
27083
+ heightPx += Math.max(1, Math.round(pageLayout.pageHeightPx));
27084
+ widthPx = Math.max(widthPx, pageWrapperWidthPxForIndex(pageIndex));
27085
+ }
27086
+ const skippedPageCount = end - start + 1;
27087
+ heightPx += Math.max(0, skippedPageCount - 1) * DOC_PAGE_BREAK_GAP;
27088
+ return { heightPx, widthPx };
27089
+ };
27090
+ return {
27091
+ before: summarizeSkippedPages(0, visiblePageStartIndex - 1),
27092
+ after: summarizeSkippedPages(visiblePageEndIndex + 1, pageCount - 1)
27093
+ };
27094
+ }, [
27095
+ documentLayout,
27096
+ pageCount,
27097
+ pageSectionInfoByIndex,
27098
+ showTrackedChangeGutter,
27099
+ visiblePageEndIndex,
27100
+ visiblePageStartIndex
27101
+ ]);
26391
27102
  React.useLayoutEffect(() => {
26392
27103
  if (typeof window === "undefined") {
26393
27104
  return;
@@ -26547,7 +27258,7 @@ function DocxEditorViewer({
26547
27258
  }, [onPageCountChange, stableReportedPageCount]);
26548
27259
  React.useEffect(() => {
26549
27260
  const nextCurrentPage = clampNumber(
26550
- visiblePageStartIndex + 1,
27261
+ (internalMostVisiblePageIndex ?? visiblePageStartIndex) + 1,
26551
27262
  1,
26552
27263
  Math.max(1, stableReportedPageCount)
26553
27264
  );
@@ -26557,6 +27268,7 @@ function DocxEditorViewer({
26557
27268
  });
26558
27269
  }, [
26559
27270
  editor.syncPaginationInfo,
27271
+ internalMostVisiblePageIndex,
26560
27272
  stableReportedPageCount,
26561
27273
  visiblePageStartIndex
26562
27274
  ]);
@@ -26564,20 +27276,38 @@ function DocxEditorViewer({
26564
27276
  const pageBuckets = pageNodeSegmentsByPage.map(
26565
27277
  () => []
26566
27278
  );
26567
- editor.trackedChanges.forEach((change) => {
26568
- const pageIndex = resolveTrackedChangePageIndex(
26569
- change,
27279
+ const placeAnnotation = (annotation) => {
27280
+ const pageIndex = resolveGutterAnnotationPageIndex(
27281
+ annotation.location,
26570
27282
  pageNodeSegmentsByPage
26571
27283
  );
26572
27284
  if (pageIndex < 0 || pageIndex >= pageBuckets.length) {
26573
27285
  return;
26574
27286
  }
26575
- pageBuckets[pageIndex].push(change);
26576
- });
26577
- pageBuckets.forEach((pageChanges) => {
26578
- pageChanges.sort((left, right) => {
26579
- const leftKey = trackedChangeSortTuple(left);
26580
- const rightKey = trackedChangeSortTuple(right);
27287
+ pageBuckets[pageIndex].push(annotation);
27288
+ };
27289
+ if (trackedChangesEnabled) {
27290
+ editor.trackedChanges.forEach((change) => {
27291
+ placeAnnotation({
27292
+ id: change.id,
27293
+ location: change.location,
27294
+ trackedChange: change
27295
+ });
27296
+ });
27297
+ }
27298
+ if (commentsEnabled) {
27299
+ editor.comments.forEach((comment) => {
27300
+ placeAnnotation({
27301
+ id: comment.id,
27302
+ location: comment.location,
27303
+ comment
27304
+ });
27305
+ });
27306
+ }
27307
+ pageBuckets.forEach((pageAnnotations) => {
27308
+ pageAnnotations.sort((left, right) => {
27309
+ const leftKey = gutterAnnotationSortTuple(left.location);
27310
+ const rightKey = gutterAnnotationSortTuple(right.location);
26581
27311
  for (let index = 0; index < leftKey.length; index += 1) {
26582
27312
  if (leftKey[index] === rightKey[index]) {
26583
27313
  continue;
@@ -26588,7 +27318,13 @@ function DocxEditorViewer({
26588
27318
  });
26589
27319
  });
26590
27320
  return pageBuckets;
26591
- }, [editor.trackedChanges, pageNodeSegmentsByPage]);
27321
+ }, [
27322
+ commentsEnabled,
27323
+ editor.comments,
27324
+ editor.trackedChanges,
27325
+ pageNodeSegmentsByPage,
27326
+ trackedChangesEnabled
27327
+ ]);
26592
27328
  const [trackedChangeAnchorByPage, setTrackedChangeAnchorByPage] = React.useState([]);
26593
27329
  const [headerBodyClearanceByPage, setHeaderBodyClearanceByPage] = React.useState({});
26594
27330
  React.useEffect(() => {
@@ -26602,18 +27338,18 @@ function DocxEditorViewer({
26602
27338
  );
26603
27339
  return;
26604
27340
  }
26605
- const nextAnchorMaps = trackedChangesByPage.map((changes, pageIndex) => {
27341
+ const nextAnchorMaps = trackedChangesByPage.map((annotations, pageIndex) => {
26606
27342
  const pageElement = pageElementsRef.current.get(pageIndex);
26607
27343
  const anchorsByChangeId = /* @__PURE__ */ new Map();
26608
- if (!pageElement || changes.length === 0) {
27344
+ if (!pageElement || annotations.length === 0) {
26609
27345
  return anchorsByChangeId;
26610
27346
  }
26611
27347
  const pageHeightPx = Math.max(1, pageElement.offsetHeight);
26612
27348
  const pageWidthPx = Math.max(1, pageElement.offsetWidth);
26613
- changes.forEach((change) => {
27349
+ annotations.forEach((annotation) => {
26614
27350
  const anchorElement = findTrackedChangeAnchorElementInPage(
26615
27351
  pageElement,
26616
- change.location
27352
+ annotation.location
26617
27353
  );
26618
27354
  if (!anchorElement) {
26619
27355
  return;
@@ -26637,7 +27373,7 @@ function DocxEditorViewer({
26637
27373
  10,
26638
27374
  Math.max(10, pageWidthPx - 10)
26639
27375
  );
26640
- anchorsByChangeId.set(change.id, { x: anchorX, y: anchorY });
27376
+ anchorsByChangeId.set(annotation.id, { x: anchorX, y: anchorY });
26641
27377
  });
26642
27378
  return anchorsByChangeId;
26643
27379
  });
@@ -26655,28 +27391,30 @@ function DocxEditorViewer({
26655
27391
  );
26656
27392
  return;
26657
27393
  }
26658
- const nextHeightsByPage = trackedChangesByPage.map((changes, pageIndex) => {
26659
- const pageHeights = /* @__PURE__ */ new Map();
26660
- changes.forEach((change) => {
26661
- const cardElement = trackedChangeCardElementsRef.current.get(
26662
- `${pageIndex}:${change.id}`
26663
- );
26664
- if (!cardElement) {
26665
- return;
26666
- }
26667
- const measuredHeight = Math.round(
26668
- cardElement.getBoundingClientRect().height
26669
- );
26670
- if (!Number.isFinite(measuredHeight) || measuredHeight <= 0) {
26671
- return;
26672
- }
26673
- pageHeights.set(
26674
- change.id,
26675
- Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, measuredHeight)
26676
- );
26677
- });
26678
- return pageHeights;
26679
- });
27394
+ const nextHeightsByPage = trackedChangesByPage.map(
27395
+ (annotations, pageIndex) => {
27396
+ const pageHeights = /* @__PURE__ */ new Map();
27397
+ annotations.forEach((annotation) => {
27398
+ const cardElement = trackedChangeCardElementsRef.current.get(
27399
+ `${pageIndex}:${annotation.id}`
27400
+ );
27401
+ if (!cardElement) {
27402
+ return;
27403
+ }
27404
+ const measuredHeight = Math.round(
27405
+ cardElement.getBoundingClientRect().height
27406
+ );
27407
+ if (!Number.isFinite(measuredHeight) || measuredHeight <= 0) {
27408
+ return;
27409
+ }
27410
+ pageHeights.set(
27411
+ annotation.id,
27412
+ Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, measuredHeight)
27413
+ );
27414
+ });
27415
+ return pageHeights;
27416
+ }
27417
+ );
26680
27418
  setTrackedChangeCardHeightsByPage((current) => {
26681
27419
  if (current.length === nextHeightsByPage.length) {
26682
27420
  let equal = true;
@@ -27175,9 +27913,14 @@ function DocxEditorViewer({
27175
27913
  },
27176
27914
  []
27177
27915
  );
27916
+ const storedDocumentPageCountForLatch = editor.model.metadata.documentPageCount;
27917
+ const latchTargetPageCount = Number.isFinite(storedDocumentPageCountForLatch) ? Math.max(
27918
+ collectDocxHardPageBreakStartNodeIndexes(editor.model).size + 1,
27919
+ Math.round(storedDocumentPageCountForLatch)
27920
+ ) : void 0;
27178
27921
  const nextMeasuredBodyFooterOverlapLatchState = resolveMeasuredBodyFooterOverlapLatchState({
27179
27922
  pageCount,
27180
- targetPageCount: editor.model.metadata.documentPageCount,
27923
+ targetPageCount: latchTargetPageCount,
27181
27924
  overlappingPageIndexes,
27182
27925
  previousSignature: measuredBodyFooterOverlapCandidateRef.current.signature,
27183
27926
  previousConsecutivePasses: measuredBodyFooterOverlapCandidateRef.current.consecutivePasses,
@@ -33948,7 +34691,10 @@ function DocxEditorViewer({
33948
34691
  Math.round(options?.pageFlowTopPx ?? 0)
33949
34692
  );
33950
34693
  const bodyParagraphOriginLeftPx = interactiveBodyFloatingPageOriginPx ? paragraphPageLayout.marginsPx.left : void 0;
33951
- const bodyParagraphOriginTopPx = interactiveBodyFloatingPageOriginPx ? paragraphPageLayout.marginsPx.top + paragraphPageFlowTopPx : void 0;
34694
+ const bodyParagraphOriginTopPx = interactiveBodyFloatingPageOriginPx ? paragraphActsAsPageAnchoredCoverOverlayHost(
34695
+ paragraph,
34696
+ paragraphPageLayout
34697
+ ) ? paragraphPageLayout.marginsPx.top + paragraphPageFlowTopPx : 0 : void 0;
33952
34698
  const resizedWidthPxByImageIndex = /* @__PURE__ */ new Map();
33953
34699
  const resizedHeightPxByImageIndex = /* @__PURE__ */ new Map();
33954
34700
  const movePreviewByImageIndex = /* @__PURE__ */ new Map();
@@ -34003,7 +34749,8 @@ function DocxEditorViewer({
34003
34749
  const hasFixedPositionWrappedImage = paragraph.children.some(
34004
34750
  (child) => child.type === "image" && isFixedPositionWrappedFloatingImage(child)
34005
34751
  );
34006
- if ((trackedChangesEnabled || useSpecialTabLayout) && !hasFixedPositionWrappedImage) {
34752
+ const paragraphHasCommentAnchors = commentsEnabled && /commentRange|commentReference/i.test(paragraph.sourceXml ?? "");
34753
+ if ((trackedChangesEnabled || useSpecialTabLayout || paragraphHasCommentAnchors) && !hasFixedPositionWrappedImage) {
34007
34754
  return renderParagraphRuns(
34008
34755
  paragraph,
34009
34756
  keyPrefix,
@@ -34016,6 +34763,7 @@ function DocxEditorViewer({
34016
34763
  void 0,
34017
34764
  {
34018
34765
  showTrackedChanges: trackedChangesEnabled,
34766
+ showCommentHighlights: commentsEnabled,
34019
34767
  numberingDefinitions: editor.model.metadata.numberingDefinitions,
34020
34768
  tocLinkColorByLevel,
34021
34769
  paragraphOriginLeftPx: bodyParagraphOriginLeftPx,
@@ -36835,9 +37583,10 @@ function DocxEditorViewer({
36835
37583
  marginTop: (typeof baseParagraphStyle.marginTop === "number" ? baseParagraphStyle.marginTop : 0) - (pageAnchoredCoverOverlayParagraph ? resolvedPageLayout.marginsPx.top : 0),
36836
37584
  marginLeft: -resolvedPageLayout.marginsPx.left,
36837
37585
  marginRight: -resolvedPageLayout.marginsPx.right,
36838
- minHeight: 0,
36839
- height: 0,
36840
- lineHeight: 0,
37586
+ // A cover-overlay host is remapped to the page surface and must
37587
+ // not displace flow; an ordinary anchor host still occupies its
37588
+ // one-line paragraph box (Word semantics).
37589
+ ...pageAnchoredCoverOverlayParagraph ? { minHeight: 0, height: 0, lineHeight: 0 } : void 0,
36841
37590
  overflow: "visible"
36842
37591
  } : requiresPageAbsoluteContext ? { position: "static" } : requiresLocalAbsoluteContext ? { position: "relative" } : hasDualWrappedFloatingImage ? { position: "relative" } : void 0,
36843
37592
  // Carry the paragraph's run font on the editable host so text typed into
@@ -40358,44 +41107,25 @@ ${currentText.slice(end)}`;
40358
41107
  }
40359
41108
  }
40360
41109
  ) : null,
40361
- pageNodeSegmentsByPage.map((pageNodeSegments, pageIndex) => {
41110
+ pageStackVirtualSpacers.before.heightPx > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41111
+ "div",
41112
+ {
41113
+ "aria-hidden": "true",
41114
+ "data-docx-page-window-spacer": "before",
41115
+ style: {
41116
+ height: pageStackVirtualSpacers.before.heightPx,
41117
+ width: pageStackVirtualSpacers.before.widthPx,
41118
+ margin: "0 auto",
41119
+ pointerEvents: "none",
41120
+ visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
41121
+ }
41122
+ }
41123
+ ) : null,
41124
+ visiblePageIndexes.map((pageIndex) => {
41125
+ const pageNodeSegments = pageNodeSegmentsByPage[pageIndex] ?? [];
40362
41126
  const pageInfo = pageSectionInfoByIndex[pageIndex];
40363
41127
  const pageLayout = pageInfo?.layout ?? documentLayout;
40364
- const pageVisible = isPageVisible(pageIndex);
40365
41128
  const pageWrapperWidthPx = showTrackedChangeGutter ? pageLayout.pageWidthPx + TRACKED_CHANGE_GUTTER_WIDTH_PX : pageLayout.pageWidthPx;
40366
- if (!pageVisible) {
40367
- const placeholderBackgroundColor = pageBackgroundColor ?? editor.model.metadata.documentBackgroundColor ?? pageSurfaceBaseStyle.backgroundColor;
40368
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
40369
- "div",
40370
- {
40371
- "data-docx-page-wrapper": "true",
40372
- "data-docx-page-index": pageIndex,
40373
- "data-index": pageIndex,
40374
- style: {
40375
- width: pageWrapperWidthPx,
40376
- margin: "0 auto",
40377
- visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
40378
- },
40379
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
40380
- "div",
40381
- {
40382
- "data-docx-page-placeholder": "true",
40383
- ref: pagePlaceholderRefForIndex(pageIndex),
40384
- style: {
40385
- ...pageSurfaceBaseStyle,
40386
- ...pageMarginPaddingStyle(pageLayout.marginsPx),
40387
- height: pageLayout.pageHeightPx,
40388
- minHeight: pageLayout.pageHeightPx,
40389
- width: pageLayout.pageWidthPx,
40390
- backgroundColor: placeholderBackgroundColor,
40391
- pointerEvents: "none"
40392
- }
40393
- }
40394
- )
40395
- },
40396
- `page-${pageIndex}`
40397
- );
40398
- }
40399
41129
  const pageContentWidthPx = Math.max(
40400
41130
  120,
40401
41131
  pageLayout.pageWidthPx - pageLayout.marginsPx.left - pageLayout.marginsPx.right
@@ -40567,6 +41297,10 @@ ${currentText.slice(end)}`;
40567
41297
  width: pageWrapperWidthPx,
40568
41298
  minHeight: pageLayout.pageHeightPx,
40569
41299
  margin: "0 auto",
41300
+ // Isolate per-page layout/style recalculation so scrolling and
41301
+ // edits on one page don't force whole-document layout passes.
41302
+ // (No paint containment: floats and gutter cards may overhang.)
41303
+ contain: "layout style",
40570
41304
  visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
40571
41305
  },
40572
41306
  children: [
@@ -40817,9 +41551,6 @@ ${currentText.slice(end)}`;
40817
41551
  segments: [segment]
40818
41552
  });
40819
41553
  });
40820
- if (typeof window !== "undefined" && window.__docxDebugGroups) {
40821
- console.log("[groups]", pageIndex, JSON.stringify(sectionGroups.map((g) => ({ s: g.sectionIndex, n: g.segments.map((x) => x.nodeIndex) }))));
40822
- }
40823
41554
  return sectionGroups.map((group, groupIndex) => {
40824
41555
  const sectionColumns = sectionColumnsBySectionIndex[group.sectionIndex];
40825
41556
  const isLastGroupOnPage = groupIndex === sectionGroups.length - 1;
@@ -41644,10 +42375,10 @@ ${currentText.slice(end)}`;
41644
42375
  overflow: "visible"
41645
42376
  },
41646
42377
  children: pageTrackedChanges.map((entry) => {
41647
- const accentColor = trackedChangeAccentColor(
41648
- entry.change.kind,
42378
+ const accentColor = entry.annotation.trackedChange ? trackedChangeAccentColor(
42379
+ entry.annotation.trackedChange.kind,
41649
42380
  editor.documentTheme
41650
- );
42381
+ ) : commentAccentColor(editor.documentTheme);
41651
42382
  const cardCenterY = clampNumber(
41652
42383
  Math.round(entry.top + entry.heightPx / 2),
41653
42384
  8,
@@ -41708,12 +42439,12 @@ ${currentText.slice(end)}`;
41708
42439
  )
41709
42440
  ]
41710
42441
  },
41711
- `tracked-connector-${pageIndex}-${entry.change.id}`
42442
+ `tracked-connector-${pageIndex}-${entry.annotation.id}`
41712
42443
  );
41713
42444
  })
41714
42445
  }
41715
42446
  ),
41716
- !hasTrackedChanges && pageIndex === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
42447
+ (!trackedChangesEnabled || !hasTrackedChanges) && (!commentsEnabled || !hasComments) && pageIndex === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41717
42448
  "p",
41718
42449
  {
41719
42450
  style: {
@@ -41726,19 +42457,21 @@ ${currentText.slice(end)}`;
41726
42457
  lineHeight: 1.35,
41727
42458
  color: "#94a3b8"
41728
42459
  },
41729
- children: "No edits found"
42460
+ children: trackedChangesEnabled && commentsEnabled ? "No edits or comments found" : commentsEnabled ? "No comments found" : "No edits found"
41730
42461
  }
41731
42462
  ) : null,
41732
42463
  pageTrackedChanges.map((entry) => {
41733
- const accentColor = trackedChangeAccentColor(
41734
- entry.change.kind,
42464
+ const trackedChange = entry.annotation.trackedChange;
42465
+ const comment = entry.annotation.comment;
42466
+ const accentColor = trackedChange ? trackedChangeAccentColor(
42467
+ trackedChange.kind,
41735
42468
  editor.documentTheme
41736
- );
42469
+ ) : commentAccentColor(editor.documentTheme);
41737
42470
  const formattedDate = formatTrackedChangeDate(
41738
- entry.change.date
42471
+ trackedChange?.date ?? comment?.date
41739
42472
  );
41740
- const kindLabel = trackedChangeKindLabel(entry.change.kind);
41741
- const snippet = normalizeTrackedChangeSnippet(entry.change.text) ?? (entry.change.kind === "format-change" || entry.change.kind === "paragraph-format-change" ? "Formatting" : "Change");
42473
+ const kindLabel = trackedChange ? trackedChangeKindLabel(trackedChange.kind) : comment?.resolved ? "Comment \xB7 Resolved" : comment?.parentId !== void 0 ? "Reply" : "Comment";
42474
+ const snippet = trackedChange ? normalizeTrackedChangeSnippet(trackedChange.text) ?? (trackedChange.kind === "format-change" || trackedChange.kind === "paragraph-format-change" ? "Formatting" : "Change") : comment?.text || "Comment";
41742
42475
  const cardWidthPx = Math.max(
41743
42476
  140,
41744
42477
  TRACKED_CHANGE_GUTTER_WIDTH_PX - TRACKED_CHANGE_GUTTER_CARD_LEFT_PX - TRACKED_CHANGE_GUTTER_CARD_RIGHT_PX
@@ -41790,7 +42523,7 @@ ${currentText.slice(end)}`;
41790
42523
  fontWeight: 700,
41791
42524
  lineHeight: 1.25
41792
42525
  },
41793
- children: entry.change.author?.trim() || "Unknown author"
42526
+ children: (trackedChange?.author ?? comment?.author)?.trim() || "Unknown author"
41794
42527
  }
41795
42528
  ),
41796
42529
  formattedDate ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -41809,6 +42542,23 @@ ${currentText.slice(end)}`;
41809
42542
  ]
41810
42543
  }
41811
42544
  ),
42545
+ comment?.anchorText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
42546
+ "p",
42547
+ {
42548
+ style: {
42549
+ margin: "2px 0 0",
42550
+ fontSize: 11,
42551
+ lineHeight: 1.3,
42552
+ fontStyle: "italic",
42553
+ color: editor.documentTheme === "dark" ? "#94a3b8" : "#6b7280"
42554
+ },
42555
+ children: [
42556
+ "\u201C",
42557
+ comment.anchorText,
42558
+ "\u201D"
42559
+ ]
42560
+ }
42561
+ ) : null,
41812
42562
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
41813
42563
  "p",
41814
42564
  {
@@ -41830,8 +42580,8 @@ ${currentText.slice(end)}`;
41830
42580
  ]
41831
42581
  }
41832
42582
  );
41833
- const renderedCard = renderTrackedChangeCard ? renderTrackedChangeCard({
41834
- change: entry.change,
42583
+ const renderedCard = trackedChange ? renderTrackedChangeCard ? renderTrackedChangeCard({
42584
+ change: trackedChange,
41835
42585
  kindLabel,
41836
42586
  snippet,
41837
42587
  formattedDate,
@@ -41839,12 +42589,21 @@ ${currentText.slice(end)}`;
41839
42589
  documentTheme: editor.documentTheme,
41840
42590
  pageIndex,
41841
42591
  style: cardStyle
42592
+ }) : defaultCard : comment && renderCommentCard ? renderCommentCard({
42593
+ comment,
42594
+ snippet,
42595
+ formattedDate,
42596
+ accentColor,
42597
+ documentTheme: editor.documentTheme,
42598
+ pageIndex,
42599
+ style: cardStyle
41842
42600
  }) : defaultCard;
41843
42601
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41844
42602
  "div",
41845
42603
  {
42604
+ "data-docx-gutter-annotation": trackedChange ? "tracked-change" : "comment",
41846
42605
  ref: (element) => {
41847
- const elementKey = `${pageIndex}:${entry.change.id}`;
42606
+ const elementKey = `${pageIndex}:${entry.annotation.id}`;
41848
42607
  if (element) {
41849
42608
  trackedChangeCardElementsRef.current.set(
41850
42609
  elementKey,
@@ -41859,7 +42618,7 @@ ${currentText.slice(end)}`;
41859
42618
  style: cardContainerStyle,
41860
42619
  children: renderedCard
41861
42620
  },
41862
- `tracked-card-${pageIndex}-${entry.change.id}`
42621
+ `tracked-card-${pageIndex}-${entry.annotation.id}`
41863
42622
  );
41864
42623
  })
41865
42624
  ]
@@ -41870,6 +42629,20 @@ ${currentText.slice(end)}`;
41870
42629
  `page-${pageIndex}`
41871
42630
  );
41872
42631
  }),
42632
+ pageStackVirtualSpacers.after.heightPx > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
42633
+ "div",
42634
+ {
42635
+ "aria-hidden": "true",
42636
+ "data-docx-page-window-spacer": "after",
42637
+ style: {
42638
+ height: pageStackVirtualSpacers.after.heightPx,
42639
+ width: pageStackVirtualSpacers.after.widthPx,
42640
+ margin: "0 auto",
42641
+ pointerEvents: "none",
42642
+ visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
42643
+ }
42644
+ }
42645
+ ) : null,
41873
42646
  !isReadOnly ? (() => {
41874
42647
  const hasCustomContextMenuState = Boolean(contextMenuState);
41875
42648
  const hasTableContextMenuState = Boolean(tableContextMenuState);
@@ -42226,6 +42999,7 @@ ${currentText.slice(end)}`;
42226
42999
 
42227
43000
  // src/index.tsx
42228
43001
  init_src2();
43002
+ init_src3();
42229
43003
 
42230
43004
  // ../layout-core/src/index.ts
42231
43005
  init_cjs_shims();
@@ -43773,16 +44547,20 @@ function useDocxModel(file) {
43773
44547
  }
43774
44548
  const docxFile = file;
43775
44549
  let isCurrent = true;
44550
+ const abortController = new AbortController();
43776
44551
  async function load() {
43777
44552
  setState({ isLoading: true });
43778
44553
  try {
43779
- const pkg = await parseDocx(docxFile);
44554
+ const { model } = await importDocxBuffer(docxFile, {
44555
+ signal: abortController.signal,
44556
+ transferBuffer: false
44557
+ });
43780
44558
  if (!isCurrent) {
43781
44559
  return;
43782
44560
  }
43783
44561
  setState({
43784
44562
  isLoading: false,
43785
- model: await buildDocModel(pkg)
44563
+ model
43786
44564
  });
43787
44565
  } catch (error) {
43788
44566
  if (!isCurrent) {
@@ -43797,6 +44575,7 @@ function useDocxModel(file) {
43797
44575
  void load();
43798
44576
  return () => {
43799
44577
  isCurrent = false;
44578
+ abortController.abort();
43800
44579
  };
43801
44580
  }, [file]);
43802
44581
  return state;
@@ -44137,6 +44916,7 @@ function ReactDocxViewer({
44137
44916
  updateTableCellParagraphTextRecursive,
44138
44917
  updateTableCellText,
44139
44918
  useDocxBorders,
44919
+ useDocxComments,
44140
44920
  useDocxDocumentTheme,
44141
44921
  useDocxEditor,
44142
44922
  useDocxFormFields,