@extend-ai/react-docx 0.7.0-alpha.4 → 0.7.0-alpha.6

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
@@ -713,327 +713,7 @@ var init_src2 = __esm({
713
713
  }
714
714
  });
715
715
 
716
- // src/index.tsx
717
- var index_exports = {};
718
- __export(index_exports, {
719
- DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX: () => DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX,
720
- DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX: () => DEFAULT_PAGE_OVERFLOW_TOLERANCE_PX,
721
- DocxEditorViewer: () => DocxEditorViewer,
722
- ReactDocxViewer: () => ReactDocxViewer,
723
- applyRunStyle: () => applyRunStyle,
724
- buildDocModel: () => buildDocModel,
725
- buildDocModelFromBytes: () => buildDocModelFromBytes,
726
- buildDocumentPageNodeSegments: () => buildDocumentPageNodeSegments2,
727
- buildDocumentPageRanges: () => buildDocumentPageRanges,
728
- buildLayoutSnapshot: () => buildLayoutSnapshot,
729
- cloneDocModel: () => cloneDocModel,
730
- collectDocxEstimatedOverflowBreakStartNodeIndexes: () => collectDocxEstimatedOverflowBreakStartNodeIndexes,
731
- collectDocxHardPageBreakStartNodeIndexes: () => collectDocxHardPageBreakStartNodeIndexes2,
732
- collectDocxLastRenderedPageBreakStartNodeIndexes: () => collectDocxLastRenderedPageBreakStartNodeIndexes,
733
- collectTableExplicitPageBreakInfo: () => collectTableExplicitPageBreakInfo2,
734
- collectTopLevelExplicitPageBreakStartNodeIndexes: () => collectTopLevelExplicitPageBreakStartNodeIndexes2,
735
- copyParagraphs: () => copyParagraphs,
736
- createMinimalDocxPackage: () => createMinimalDocxPackage,
737
- defaultStarterModel: () => defaultStarterModel,
738
- duplicateParagraph: () => duplicateParagraph,
739
- getPart: () => getPart,
740
- initWasm: () => initWasm,
741
- insertParagraph: () => insertParagraph,
742
- layoutDocument: () => layoutDocument,
743
- modelToDocumentXml: () => modelToDocumentXml,
744
- normalizeDocModel: () => normalizeDocModel,
745
- packageToArrayBuffer: () => packageToArrayBuffer,
746
- paragraphAfterSpacingPx: () => paragraphAfterSpacingPx2,
747
- paragraphBeforeSpacingPx: () => paragraphBeforeSpacingPx2,
748
- paragraphHasExplicitPageBreak: () => paragraphHasExplicitPageBreak3,
749
- paragraphHasLastRenderedPageBreak: () => paragraphHasLastRenderedPageBreak2,
750
- paragraphHasPageBreakBefore: () => paragraphHasPageBreakBefore3,
751
- paragraphLetterheadColumnGroupAtSegmentOffset: () => paragraphLetterheadColumnGroupAtSegmentOffset2,
752
- paragraphLetterheadFloatSideAtNodeIndex: () => paragraphLetterheadFloatSideAtNodeIndex,
753
- paragraphStartsWithLastRenderedPageBreak: () => paragraphStartsWithLastRenderedPageBreak2,
754
- parseDocx: () => parseDocx,
755
- parseParagraphsFromClipboard: () => parseParagraphsFromClipboard,
756
- parseSectionLayout: () => parseSectionLayout,
757
- pasteParagraphs: () => pasteParagraphs,
758
- removeParagraph: () => removeParagraph,
759
- replaceText: () => replaceText,
760
- resolveDocumentForLayout: () => resolveDocumentForLayout,
761
- resolveDocumentLayout: () => resolveDocumentLayout,
762
- resolveDocumentPageSegmentStartNodeIndex: () => resolveDocumentPageSegmentStartNodeIndex,
763
- resolveDocumentSectionsFromMetadata: () => resolveDocumentSectionsFromMetadata2,
764
- resolveDocxPageThumbnailResolution: () => resolveDocxPageThumbnailResolution,
765
- resolvePaginationSectionMetricsIndexForNodeIndex: () => resolvePaginationSectionMetricsIndexForNodeIndex2,
766
- resolveParagraphBeforeSpacingPx: () => resolveParagraphBeforeSpacingPx2,
767
- resolveSectionIndexForNodeIndex: () => resolveSectionIndexForNodeIndex2,
768
- resolveSectionPropertiesXmlForNodeIndex: () => resolveSectionPropertiesXmlForNodeIndex,
769
- scalePaginationSectionMetricsHeights: () => scalePaginationSectionMetricsHeights2,
770
- scorePaginationAgainstStoredPageBreaks: () => scorePaginationAgainstStoredPageBreaks,
771
- sectionBreakAfterParagraphStartsNewPage: () => sectionBreakAfterParagraphStartsNewPage2,
772
- sectionBreakPropertiesStartNewPage: () => sectionBreakPropertiesStartNewPage2,
773
- sectionTitlePageEnabled: () => sectionTitlePageEnabled2,
774
- selectSectionVariantForPage: () => selectSectionVariantForPage2,
775
- serializeDocModel: () => serializeDocModel,
776
- serializeDocx: () => serializeDocx,
777
- serializeParagraphsForClipboard: () => serializeParagraphsForClipboard,
778
- setParagraphAlignment: () => setParagraphAlignment,
779
- setParagraphHeading: () => setParagraphHeading,
780
- setRunColor: () => setRunColor,
781
- setRunHighlight: () => setRunHighlight,
782
- setWasmSource: () => setWasmSource,
783
- splitParagraphChildrenAtTextOffsets: () => splitParagraphChildrenAtTextOffsets,
784
- toggleRunStyleFlag: () => toggleRunStyleFlag,
785
- updateParagraphText: () => updateParagraphText,
786
- updateTableCellParagraphText: () => updateTableCellParagraphText,
787
- updateTableCellParagraphTextRecursive: () => updateTableCellParagraphTextRecursive,
788
- updateTableCellText: () => updateTableCellText,
789
- useDocxBorders: () => useDocxBorders,
790
- useDocxDocumentTheme: () => useDocxDocumentTheme,
791
- useDocxEditor: () => useDocxEditor,
792
- useDocxFormFields: () => useDocxFormFields,
793
- useDocxImageWrapMenu: () => useDocxImageWrapMenu,
794
- useDocxLineSpacing: () => useDocxLineSpacing,
795
- useDocxModel: () => useDocxModel,
796
- useDocxPageLayout: () => useDocxPageLayout,
797
- useDocxPageThumbnails: () => useDocxPageThumbnails,
798
- useDocxPagination: () => useDocxPagination,
799
- useDocxParagraphStyles: () => useDocxParagraphStyles,
800
- useDocxTrackChanges: () => useDocxTrackChanges,
801
- useDocxViewerThumbnails: () => useDocxViewerThumbnails,
802
- withPart: () => withPart
803
- });
804
- module.exports = __toCommonJS(index_exports);
805
- init_cjs_shims();
806
- var React2 = __toESM(require("react"), 1);
807
-
808
- // ../layout-engine/src/index.ts
809
- init_cjs_shims();
810
- var DEFAULT_OPTIONS = {
811
- pageWidth: 816,
812
- pageHeight: 1056,
813
- margin: 72,
814
- minLineHeight: 22,
815
- paragraphSpacing: 8,
816
- tableCellPadding: 8
817
- };
818
- function headingScale(level) {
819
- if (!level) {
820
- return 1;
821
- }
822
- switch (level) {
823
- case 1:
824
- return 2.15;
825
- case 2:
826
- return 1.75;
827
- case 3:
828
- return 1.45;
829
- case 4:
830
- return 1.28;
831
- case 5:
832
- return 1.15;
833
- case 6:
834
- return 1.05;
835
- default:
836
- return 1;
837
- }
838
- }
839
- function runHeightPx(run) {
840
- if (run.kind === "image") {
841
- if (run.floating) {
842
- return 0;
843
- }
844
- return run.heightPx ?? 96;
845
- }
846
- const fontSizePt = run.style?.fontSizePt ?? 12;
847
- return Math.round(fontSizePt * 1.6);
848
- }
849
- function lineHeightFromRuns(runs, minLineHeight, headingLevel) {
850
- const base = runs.reduce((largest, run) => {
851
- return Math.max(largest, runHeightPx(run));
852
- }, 12) * headingScale(headingLevel);
853
- return Math.max(minLineHeight, Math.round(base));
854
- }
855
- function spacingForBlock(baseSpacing, headingLevel) {
856
- if (!headingLevel) {
857
- return baseSpacing;
858
- }
859
- return baseSpacing + Math.max(4, (7 - headingLevel) * 2);
860
- }
861
- function formFieldDisplayText(field) {
862
- switch (field.fieldType) {
863
- case "checkbox":
864
- return field.checked ? field.checkedSymbol ?? "\u2612" : field.uncheckedSymbol ?? "\u2610";
865
- case "dropdown":
866
- case "date":
867
- case "text":
868
- default:
869
- return field.value ?? "";
870
- }
871
- }
872
- function paragraphToLayout(paragraph, idPrefix, x, y, width, minLineHeight) {
873
- const runs = paragraph.children.map((child, runIndex) => {
874
- if (child.type === "text") {
875
- return {
876
- kind: "text",
877
- id: `${idPrefix}-run-${runIndex}`,
878
- text: child.text,
879
- style: child.style,
880
- link: child.link
881
- };
882
- }
883
- if (child.type === "form-field") {
884
- return {
885
- kind: "text",
886
- id: `${idPrefix}-run-${runIndex}`,
887
- text: formFieldDisplayText(child),
888
- style: child.style,
889
- link: child.link
890
- };
891
- }
892
- return {
893
- kind: "image",
894
- id: `${idPrefix}-run-${runIndex}`,
895
- src: child.src,
896
- alt: child.alt,
897
- widthPx: child.widthPx,
898
- heightPx: child.heightPx,
899
- contentType: child.contentType,
900
- data: child.data ? new Uint8Array(child.data) : void 0,
901
- floating: Boolean(child.floating)
902
- };
903
- });
904
- return {
905
- kind: "paragraph",
906
- id: idPrefix,
907
- runs,
908
- align: paragraph.style?.align ?? "left",
909
- headingLevel: paragraph.style?.headingLevel,
910
- x,
911
- y,
912
- width,
913
- height: lineHeightFromRuns(runs, minLineHeight, paragraph.style?.headingLevel)
914
- };
915
- }
916
- function paragraphsForTableCellNodes(nodes) {
917
- const paragraphs = [];
918
- const walk = (items) => {
919
- for (const item of items) {
920
- if (item.type === "paragraph") {
921
- paragraphs.push(item);
922
- continue;
923
- }
924
- for (const row of item.rows) {
925
- for (const cell of row.cells) {
926
- walk(cell.nodes);
927
- }
928
- }
929
- }
930
- };
931
- walk(nodes);
932
- return paragraphs;
933
- }
934
- function tableToLayout(table, idPrefix, x, y, width, options) {
935
- const columnCount = Math.max(
936
- 1,
937
- ...table.rows.map(
938
- (row) => row.cells.reduce(
939
- (sum, cell) => sum + (cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1),
940
- 0
941
- )
942
- )
943
- );
944
- const baseCellWidth = width / columnCount;
945
- let tableHeight = 0;
946
- const rows = table.rows.map((row, rowIndex) => {
947
- let rowHeight = options.minLineHeight + options.tableCellPadding * 2;
948
- let columnCursor = 0;
949
- const cells = row.cells.map((cell, cellIndex) => {
950
- const colSpan = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
951
- const cellWidth = baseCellWidth * colSpan;
952
- const cellParagraphs = paragraphsForTableCellNodes(cell.nodes);
953
- const paragraphBlocks = cellParagraphs.map(
954
- (paragraph, paragraphIndex) => paragraphToLayout(
955
- paragraph,
956
- `${idPrefix}-r${rowIndex}-c${cellIndex}-p${paragraphIndex}`,
957
- x + columnCursor * baseCellWidth,
958
- y,
959
- cellWidth,
960
- options.minLineHeight
961
- )
962
- );
963
- const paragraphsHeight = paragraphBlocks.reduce((sum, block) => sum + block.height, 0);
964
- rowHeight = Math.max(rowHeight, paragraphsHeight + options.tableCellPadding * 2);
965
- columnCursor += colSpan;
966
- return {
967
- id: `${idPrefix}-r${rowIndex}-c${cellIndex}`,
968
- colSpan,
969
- backgroundColor: cell.style?.backgroundColor ?? row.style?.backgroundColor,
970
- paragraphs: paragraphBlocks
971
- };
972
- });
973
- tableHeight += rowHeight;
974
- return {
975
- id: `${idPrefix}-row-${rowIndex}`,
976
- backgroundColor: row.style?.backgroundColor,
977
- cells
978
- };
979
- });
980
- return {
981
- kind: "table",
982
- id: idPrefix,
983
- x,
984
- y,
985
- width,
986
- height: Math.max(tableHeight, options.minLineHeight * 2),
987
- rows
988
- };
989
- }
990
- function estimateBlockHeight(block) {
991
- if (block.kind === "paragraph") {
992
- return block.height;
993
- }
994
- return block.height;
995
- }
996
- function layoutDocument(model, options = {}) {
997
- const resolved = { ...DEFAULT_OPTIONS, ...options };
998
- const pages = [{ number: 1, blocks: [] }];
999
- const contentWidth = resolved.pageWidth - resolved.margin * 2;
1000
- const pageBottom = resolved.pageHeight - resolved.margin;
1001
- let cursorY = resolved.margin;
1002
- for (const [index, node] of model.nodes.entries()) {
1003
- const block = node.type === "paragraph" ? paragraphToLayout(
1004
- node,
1005
- `paragraph-${index}`,
1006
- resolved.margin,
1007
- cursorY,
1008
- contentWidth,
1009
- resolved.minLineHeight
1010
- ) : tableToLayout(node, `table-${index}`, resolved.margin, cursorY, contentWidth, resolved);
1011
- const blockHeight = estimateBlockHeight(block);
1012
- const currentPage = pages[pages.length - 1];
1013
- if (cursorY + blockHeight > pageBottom && currentPage.blocks.length > 0) {
1014
- pages.push({
1015
- number: pages.length + 1,
1016
- blocks: []
1017
- });
1018
- cursorY = resolved.margin;
1019
- if (block.kind === "paragraph") {
1020
- block.y = cursorY;
1021
- } else {
1022
- block.y = cursorY;
1023
- }
1024
- }
1025
- pages[pages.length - 1].blocks.push(block);
1026
- cursorY += blockHeight + (block.kind === "paragraph" ? spacingForBlock(resolved.paragraphSpacing, block.headingLevel) : resolved.paragraphSpacing + 10);
1027
- }
1028
- return pages;
1029
- }
1030
-
1031
- // ../doc-model/src/index.ts
1032
- init_cjs_shims();
1033
- init_src();
1034
-
1035
716
  // ../doc-model/src/normalize.ts
1036
- init_cjs_shims();
1037
717
  function normalizeUint8Array(value) {
1038
718
  if (value instanceof Uint8Array) {
1039
719
  return value;
@@ -1120,12 +800,22 @@ function normalizeDocModel(model) {
1120
800
  }
1121
801
  };
1122
802
  }
803
+ var init_normalize = __esm({
804
+ "../doc-model/src/normalize.ts"() {
805
+ "use strict";
806
+ init_cjs_shims();
807
+ }
808
+ });
1123
809
 
1124
810
  // ../doc-model/src/types.ts
1125
- init_cjs_shims();
811
+ var init_types = __esm({
812
+ "../doc-model/src/types.ts"() {
813
+ "use strict";
814
+ init_cjs_shims();
815
+ }
816
+ });
1126
817
 
1127
818
  // ../doc-model/src/clone.ts
1128
- init_cjs_shims();
1129
819
  function isParagraphCellContent(node) {
1130
820
  return node.type === "paragraph";
1131
821
  }
@@ -1423,12 +1113,26 @@ function cloneDocModel(model) {
1423
1113
  endnotes: model.metadata.endnotes?.map((note) => ({
1424
1114
  ...note,
1425
1115
  nodes: note.nodes?.map(cloneDocNode)
1426
- }))
1116
+ })),
1117
+ comments: model.metadata.comments?.map((comment) => ({ ...comment }))
1427
1118
  }
1428
1119
  };
1429
1120
  }
1121
+ var init_clone = __esm({
1122
+ "../doc-model/src/clone.ts"() {
1123
+ "use strict";
1124
+ init_cjs_shims();
1125
+ }
1126
+ });
1430
1127
 
1431
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
+ });
1432
1136
  async function buildDocModel(pkg) {
1433
1137
  const wasmPackage = mapsToWasmPackage({
1434
1138
  parts: pkg.parts,
@@ -1445,9 +1149,474 @@ async function buildDocModelFromBytes(bytes) {
1445
1149
  const model = await buildDocModel(pkg);
1446
1150
  return { package: pkg, model };
1447
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
+ });
1448
1163
 
1449
1164
  // src/index.tsx
1450
- 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
+ }
1451
1620
 
1452
1621
  // src/section-layout.ts
1453
1622
  init_cjs_shims();
@@ -1819,9 +1988,11 @@ var React = __toESM(require("react"), 1);
1819
1988
  var import_react_dom = require("react-dom");
1820
1989
  var import_server = require("react-dom/server");
1821
1990
  var import_react_virtual = require("@tanstack/react-virtual");
1991
+ init_src3();
1822
1992
 
1823
1993
  // ../editor-ops/src/index.ts
1824
1994
  init_cjs_shims();
1995
+ init_src3();
1825
1996
  function paragraphFromText(text, options) {
1826
1997
  return {
1827
1998
  type: "paragraph",
@@ -2804,9 +2975,6 @@ function parseParagraphsFromClipboard(input) {
2804
2975
  }
2805
2976
  }
2806
2977
 
2807
- // src/editor.tsx
2808
- init_src2();
2809
-
2810
2978
  // ../serializer/src/index.ts
2811
2979
  init_cjs_shims();
2812
2980
  init_src();
@@ -3183,6 +3351,13 @@ function reconcilePageCountCandidateToTargetCountByScalingHeight(options) {
3183
3351
  previousScale = scale;
3184
3352
  previousPageCount = candidate.pageCount;
3185
3353
  }
3354
+ if (!needMorePages && selectedCandidate.pageCount !== safeTargetPageCount) {
3355
+ return {
3356
+ pageCount: initialPageCount,
3357
+ pages: initialPages,
3358
+ scale: 1
3359
+ };
3360
+ }
3186
3361
  return selectedCandidate;
3187
3362
  }
3188
3363
 
@@ -4457,6 +4632,20 @@ var SerialIdleTaskQueue = class {
4457
4632
  this.schedulePump();
4458
4633
  });
4459
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
+ }
4460
4649
  /** Drops all queued tasks, resolving their waiters without running them. */
4461
4650
  clear() {
4462
4651
  const dropped = this.pending.splice(0, this.pending.length);
@@ -4641,6 +4830,29 @@ var MEASURED_BODY_FOOTER_OVERLAP_STABILITY_THRESHOLD = 1;
4641
4830
  var WORD_TABLE_CELL_PARAGRAPH_AUTO_LINE_TWIPS = 240;
4642
4831
  var WORD_TABLE_CELL_PARAGRAPH_BEFORE_TWIPS = 0;
4643
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
+ }
4644
4856
  var TABLE_ROW_SLICE_VISUAL_BLEED_PX = 1;
4645
4857
  var TABLE_CELL_SLICE_FULLY_VISIBLE_BOTTOM_BUFFER_PX = 4;
4646
4858
  var DEFAULT_SPLIT_PARAGRAPH_LINE_TWIPS = 259;
@@ -4728,6 +4940,7 @@ var tableEstimatedRowHeightsByNode = /* @__PURE__ */ new WeakMap();
4728
4940
  var paragraphExplicitIndentBySourceXml = /* @__PURE__ */ new Map();
4729
4941
  var paragraphDropCapBySourceXml = /* @__PURE__ */ new Map();
4730
4942
  var paragraphTrackedMarkupBySourceXml = /* @__PURE__ */ new Map();
4943
+ var paragraphCommentMarkupBySourceXml = /* @__PURE__ */ new Map();
4731
4944
  var paragraphMeasureCanvasContext;
4732
4945
  var textWidthByFontAndValue = /* @__PURE__ */ new Map();
4733
4946
  var estimatedTextAdvanceWidthByFontAndValue = /* @__PURE__ */ new Map();
@@ -5022,6 +5235,10 @@ function resolveEffectiveZoomScale(element) {
5022
5235
  }
5023
5236
  return Number.isFinite(scale) && scale > 0 ? scale : 1;
5024
5237
  }
5238
+ function normalizePageVirtualizationZoomScale(value) {
5239
+ const scale = Number(value);
5240
+ return Number.isFinite(scale) && scale > 0 ? scale : void 0;
5241
+ }
5025
5242
  var DOC_SURFACE_STYLE_BY_THEME = {
5026
5243
  light: {
5027
5244
  backgroundColor: "#ffffff",
@@ -9729,9 +9946,7 @@ function estimateTabLeaderWrappedLineCountForParagraph(paragraph, maxLineWidthPx
9729
9946
  leadingSegments,
9730
9947
  paragraphBaseFontPx
9731
9948
  );
9732
- const tabStopPositionsPx = (paragraph.style?.tabStops ?? []).map((tabStop) => twipsToPixels(tabStop.positionTwips)).filter(
9733
- (positionPx) => Number.isFinite(positionPx) && positionPx > 0
9734
- ).sort((left, right) => left - right);
9949
+ const tabStopPositionsPx = resolveParagraphFirstLineLeftTabStopsPx(paragraph);
9735
9950
  const explicitLeadingTabStopPx = tableOfContentsLeadingLeftTabStopPx(paragraph);
9736
9951
  const leadingReservationWidthPx = leadingSegments.length === 0 ? 0 : Number.isFinite(explicitLeadingTabStopPx) && explicitLeadingTabStopPx > 0 ? Math.max(
9737
9952
  leadingTextWidthPx,
@@ -13597,10 +13812,7 @@ function tableOfContentsLeadingLeftTabStopPx(paragraph) {
13597
13812
  if (!isTableOfContentsParagraph(paragraph)) {
13598
13813
  return void 0;
13599
13814
  }
13600
- const leftTabStopPositionsPx = (paragraph.style?.tabStops ?? []).filter((tabStop) => tabStop.alignment === "left").map((tabStop) => twipsToPixels(tabStop.positionTwips)).filter(
13601
- (positionPx) => Number.isFinite(positionPx) && positionPx > 0
13602
- ).sort((left, right) => left - right);
13603
- return leftTabStopPositionsPx[0];
13815
+ return resolveParagraphFirstLineLeftTabStopsPx(paragraph)[0];
13604
13816
  }
13605
13817
  function paragraphContainsTabCharacter(paragraph) {
13606
13818
  return paragraph.children.some((child) => {
@@ -14650,6 +14862,81 @@ function resolveParagraphTrackedMarkup(paragraph) {
14650
14862
  setCacheEntry(paragraphTrackedMarkupBySourceXml, sourceXml, resolved);
14651
14863
  return resolved;
14652
14864
  }
14865
+ function resolveParagraphCommentMarkup(paragraph) {
14866
+ const sourceXml = paragraph.sourceXml ?? "";
14867
+ if (!sourceXml || !/commentRange|commentReference/i.test(sourceXml)) {
14868
+ return void 0;
14869
+ }
14870
+ const cached = paragraphCommentMarkupBySourceXml.get(sourceXml);
14871
+ if (cached !== void 0) {
14872
+ return cached ?? void 0;
14873
+ }
14874
+ const rangeStartById = /* @__PURE__ */ new Map();
14875
+ const rangeEndById = /* @__PURE__ */ new Map();
14876
+ for (const match of sourceXml.matchAll(
14877
+ /<w:commentRangeStart\b[^>]*w:id="(-?\d+)"[^>]*\/?>/gi
14878
+ )) {
14879
+ const commentId = Number.parseInt(match[1] ?? "", 10);
14880
+ if (Number.isFinite(commentId) && match.index !== void 0) {
14881
+ rangeStartById.set(commentId, match.index + match[0].length);
14882
+ }
14883
+ }
14884
+ for (const match of sourceXml.matchAll(
14885
+ /<w:commentRangeEnd\b[^>]*w:id="(-?\d+)"[^>]*\/?>/gi
14886
+ )) {
14887
+ const commentId = Number.parseInt(match[1] ?? "", 10);
14888
+ if (Number.isFinite(commentId) && match.index !== void 0) {
14889
+ rangeEndById.set(commentId, match.index);
14890
+ }
14891
+ }
14892
+ const ranges = [];
14893
+ const rangeIds = /* @__PURE__ */ new Set([
14894
+ ...rangeStartById.keys(),
14895
+ ...rangeEndById.keys()
14896
+ ]);
14897
+ rangeIds.forEach((commentId) => {
14898
+ const start = rangeStartById.get(commentId) ?? 0;
14899
+ const end = rangeEndById.get(commentId) ?? sourceXml.length;
14900
+ if (end > start) {
14901
+ ranges.push({ commentId, start, end });
14902
+ }
14903
+ });
14904
+ if (ranges.length === 0) {
14905
+ setCacheEntry(paragraphCommentMarkupBySourceXml, sourceXml, null);
14906
+ return void 0;
14907
+ }
14908
+ const commentIdsByVisibleChildIndex = [];
14909
+ let visibleChildIndex = 0;
14910
+ const runPattern = /<w:r\b[\s\S]*?<\/w:r>/gi;
14911
+ for (const runMatch of sourceXml.matchAll(runPattern)) {
14912
+ const runXml = runMatch[0] ?? "";
14913
+ if (!runXml) {
14914
+ continue;
14915
+ }
14916
+ const runStart = runMatch.index ?? 0;
14917
+ const contentRunXml = stripTextBoxContentFromRunXml(runXml);
14918
+ const visibleTokens = parseTrackedRunTokens(contentRunXml, false);
14919
+ const hasImage = /<w:(?:drawing|pict)\b/i.test(runXml);
14920
+ const visibleChildCount = visibleTokens.filter((token) => token.text.length > 0 || token.isNote).length + (hasImage ? 1 : 0);
14921
+ if (visibleChildCount === 0) {
14922
+ continue;
14923
+ }
14924
+ const activeCommentIds = ranges.filter((range) => runStart >= range.start && runStart < range.end).map((range) => range.commentId);
14925
+ if (activeCommentIds.length > 0) {
14926
+ for (let index = 0; index < visibleChildCount; index += 1) {
14927
+ commentIdsByVisibleChildIndex[visibleChildIndex + index] = activeCommentIds;
14928
+ }
14929
+ }
14930
+ visibleChildIndex += visibleChildCount;
14931
+ }
14932
+ if (commentIdsByVisibleChildIndex.length === 0) {
14933
+ setCacheEntry(paragraphCommentMarkupBySourceXml, sourceXml, null);
14934
+ return void 0;
14935
+ }
14936
+ const resolved = { commentIdsByVisibleChildIndex };
14937
+ setCacheEntry(paragraphCommentMarkupBySourceXml, sourceXml, resolved);
14938
+ return resolved;
14939
+ }
14653
14940
  function instructionTextToPageFieldKind(rawInstruction) {
14654
14941
  const normalized = decodeXmlText(rawInstruction).replace(/\s+/g, " ").trim().toUpperCase();
14655
14942
  if (!normalized || normalized.includes("PAGEREF")) {
@@ -14696,11 +14983,16 @@ function paragraphPageFieldSequence(paragraph) {
14696
14983
  }
14697
14984
  return fields;
14698
14985
  }
14986
+ var pageFieldValueSequenceBySourceXml = /* @__PURE__ */ new Map();
14699
14987
  function paragraphPageFieldValueSequence(paragraph) {
14700
14988
  const xml = paragraph.sourceXml ?? "";
14701
14989
  if (!xml) {
14702
14990
  return [];
14703
14991
  }
14992
+ const cached = pageFieldValueSequenceBySourceXml.get(xml);
14993
+ if (cached) {
14994
+ return cached;
14995
+ }
14704
14996
  const values = [];
14705
14997
  const fieldStack = [];
14706
14998
  const tokenPattern = /<w:fldSimple\b[^>]*\bw:instr="([^"]+)"[^>]*>[\s\S]*?<\/w:fldSimple>|<w:r\b[\s\S]*?<\/w:r>/gi;
@@ -14780,13 +15072,19 @@ function paragraphPageFieldValueSequence(paragraph) {
14780
15072
  fieldStack.pop();
14781
15073
  }
14782
15074
  }
15075
+ setCacheEntry(pageFieldValueSequenceBySourceXml, xml, values);
14783
15076
  return values;
14784
15077
  }
15078
+ var styleRefFieldValueSequenceBySourceXml = /* @__PURE__ */ new Map();
14785
15079
  function paragraphStyleRefFieldValueSequence(paragraph) {
14786
15080
  const xml = paragraph.sourceXml ?? "";
14787
15081
  if (!xml) {
14788
15082
  return [];
14789
15083
  }
15084
+ const cached = styleRefFieldValueSequenceBySourceXml.get(xml);
15085
+ if (cached) {
15086
+ return cached;
15087
+ }
14790
15088
  const values = [];
14791
15089
  const fieldStack = [];
14792
15090
  const tokenPattern = /<w:fldSimple\b[^>]*\bw:instr="([^"]+)"[^>]*>[\s\S]*?<\/w:fldSimple>|<w:r\b[\s\S]*?<\/w:r>/gi;
@@ -14866,6 +15164,7 @@ function paragraphStyleRefFieldValueSequence(paragraph) {
14866
15164
  fieldStack.pop();
14867
15165
  }
14868
15166
  }
15167
+ setCacheEntry(styleRefFieldValueSequenceBySourceXml, xml, values);
14869
15168
  return values;
14870
15169
  }
14871
15170
  function normalizeStyleRefTarget(value) {
@@ -15000,6 +15299,7 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15000
15299
  const showTrackedChanges = options?.showTrackedChanges === true;
15001
15300
  const showTrackedInlineMarkup = showTrackedChanges && options?.trackedMarkupMode !== "gutter";
15002
15301
  const trackedMarkup = showTrackedInlineMarkup ? resolveParagraphTrackedMarkup(paragraph) : void 0;
15302
+ const commentMarkup = options?.showCommentHighlights === true ? resolveParagraphCommentMarkup(paragraph) : void 0;
15003
15303
  const tocParagraphLevel = tableOfContentsLevel(paragraph);
15004
15304
  const tocLinkColor = tocParagraphLevel ? options?.tocLinkColorByLevel?.[tocParagraphLevel] : void 0;
15005
15305
  const floatingAnchorOriginCorrectionXPx = Number.isFinite(
@@ -15041,8 +15341,19 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15041
15341
  });
15042
15342
  };
15043
15343
  const currentTrackedInlineChange = () => trackedMarkup?.inlineChangeByVisibleChildIndex[trackedVisibleChildCursor];
15344
+ const currentCommentHighlightStyle = () => {
15345
+ const commentIds = commentMarkup?.commentIdsByVisibleChildIndex[trackedVisibleChildCursor];
15346
+ if (!commentIds || commentIds.length === 0) {
15347
+ return void 0;
15348
+ }
15349
+ const accent = commentAccentColor(documentTheme);
15350
+ return {
15351
+ backgroundColor: documentTheme === "dark" ? "rgba(251, 191, 36, 0.24)" : "rgba(251, 191, 36, 0.3)",
15352
+ borderBottom: `2px solid ${accent}`
15353
+ };
15354
+ };
15044
15355
  const consumeTrackedVisibleChild = (child) => {
15045
- if (!trackedMarkup) {
15356
+ if (!trackedMarkup && !commentMarkup) {
15046
15357
  return;
15047
15358
  }
15048
15359
  if (child.type === "form-field") {
@@ -15211,20 +15522,26 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15211
15522
  const resolveFieldText = (value, preferredZone) => resolvePageFieldText(resolveStyleRefFieldText(value), preferredZone);
15212
15523
  const trackedLinkStyle = (style, trackedInlineChange) => {
15213
15524
  if (!isTableOfContentsParagraph(paragraph)) {
15214
- return trackedInlineStyle(
15215
- linkStyleToCss(style, documentTheme),
15216
- trackedInlineChange
15217
- );
15525
+ return {
15526
+ ...trackedInlineStyle(
15527
+ linkStyleToCss(style, documentTheme),
15528
+ trackedInlineChange
15529
+ ),
15530
+ ...currentCommentHighlightStyle()
15531
+ };
15218
15532
  }
15219
15533
  const base = runStyleToCss(style, documentTheme);
15220
- return trackedInlineStyle(
15221
- {
15222
- ...base,
15223
- color: tocLinkColor ? themedRunColor(tocLinkColor, documentTheme) : "inherit",
15224
- textDecoration: "none"
15225
- },
15226
- trackedInlineChange
15227
- );
15534
+ return {
15535
+ ...trackedInlineStyle(
15536
+ {
15537
+ ...base,
15538
+ color: tocLinkColor ? themedRunColor(tocLinkColor, documentTheme) : "inherit",
15539
+ textDecoration: "none"
15540
+ },
15541
+ trackedInlineChange
15542
+ ),
15543
+ ...currentCommentHighlightStyle()
15544
+ };
15228
15545
  };
15229
15546
  const usesExternalHorizontalAnchorOrigin = (image) => {
15230
15547
  const horizontalRelativeTo = image.floating?.horizontalRelativeTo?.trim().toLowerCase();
@@ -15271,10 +15588,13 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15271
15588
  trackTextAdvance(text, child.style);
15272
15589
  return;
15273
15590
  }
15274
- const trackedStyle = trackedInlineStyle(
15275
- runStyleToCss(child.style, documentTheme),
15276
- trackedInlineChange
15277
- );
15591
+ const trackedStyle = {
15592
+ ...trackedInlineStyle(
15593
+ runStyleToCss(child.style, documentTheme),
15594
+ trackedInlineChange
15595
+ ),
15596
+ ...currentCommentHighlightStyle()
15597
+ };
15278
15598
  if (text === " " && !useTabLeaderLayout && !useAnchoredTabLayout) {
15279
15599
  target.push(
15280
15600
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: tabTextStyle(child.style, trackedStyle), children: "\xA0" }, key)
@@ -15530,10 +15850,13 @@ function renderParagraphRuns(paragraph, keyPrefix, documentTheme = "light", numb
15530
15850
  }
15531
15851
  return;
15532
15852
  }
15533
- const textStyle = trackedInlineStyle(
15534
- runStyleToCss(child.style, documentTheme),
15535
- trackedInlineChange
15536
- );
15853
+ const textStyle = {
15854
+ ...trackedInlineStyle(
15855
+ runStyleToCss(child.style, documentTheme),
15856
+ trackedInlineChange
15857
+ ),
15858
+ ...currentCommentHighlightStyle()
15859
+ };
15537
15860
  const noteLabel = noteMarkerLabel(
15538
15861
  child.noteReference,
15539
15862
  safeNoteMarkerIndexes.footnote,
@@ -16822,11 +17145,22 @@ function parseEmbeddedTableRuntimeKey(tableRuntimeKey) {
16822
17145
  descendants
16823
17146
  };
16824
17147
  }
17148
+ var columnWidthsByTable = /* @__PURE__ */ new WeakMap();
16825
17149
  function columnWidthsFromTableDefinition(table, columnCount) {
17150
+ const cachedByCount = columnWidthsByTable.get(table);
17151
+ if (cachedByCount?.has(columnCount)) {
17152
+ return cachedByCount.get(columnCount);
17153
+ }
17154
+ const resolved = computeColumnWidthsFromTableDefinition(table, columnCount);
17155
+ const cache = cachedByCount ?? /* @__PURE__ */ new Map();
17156
+ cache.set(columnCount, resolved);
17157
+ columnWidthsByTable.set(table, cache);
17158
+ return resolved;
17159
+ }
17160
+ function computeColumnWidthsFromTableDefinition(table, columnCount) {
16826
17161
  const gridWidths = table.style?.columnWidthsTwips;
16827
17162
  const rowDerivedWidths = deriveColumnWidthsFromTableRows(table, columnCount);
16828
17163
  if (gridWidths && gridWidths.length === columnCount) {
16829
- console.log("[colw]", columnCount, gridWidths.length, !!rowDerivedWidths, gridConflictsWithRowWidths(table, gridWidths));
16830
17164
  if (rowDerivedWidths && rowDerivedWidths.length > 0 && gridConflictsWithRowWidths(table, gridWidths)) {
16831
17165
  return rowDerivedWidths;
16832
17166
  }
@@ -18367,6 +18701,127 @@ function collectTrackedChangesFromModel(model) {
18367
18701
  });
18368
18702
  return trackedChanges;
18369
18703
  }
18704
+ function decodeCommentRangeText(rangeXml) {
18705
+ const texts = [];
18706
+ for (const match of rangeXml.matchAll(
18707
+ /<w:t\b[^>]*>([\s\S]*?)<\/w:t>/gi
18708
+ )) {
18709
+ texts.push(decodeXmlText(match[1] ?? ""));
18710
+ }
18711
+ const combined = texts.join("").replace(/\s+/g, " ").trim();
18712
+ if (!combined) {
18713
+ return void 0;
18714
+ }
18715
+ return combined.length > 120 ? `${combined.slice(0, 119)}\u2026` : combined;
18716
+ }
18717
+ function resolveCommentAnchorText(sourceXml, commentId) {
18718
+ const startMatch = sourceXml.match(
18719
+ new RegExp(`<w:commentRangeStart\\b[^>]*w:id="${commentId}"[^>]*/?>`, "i")
18720
+ );
18721
+ const endMatch = sourceXml.match(
18722
+ new RegExp(`<w:commentRangeEnd\\b[^>]*w:id="${commentId}"[^>]*/?>`, "i")
18723
+ );
18724
+ const startIndex = startMatch?.index !== void 0 ? startMatch.index + startMatch[0].length : (
18725
+ // Range opened in an earlier paragraph: take from the paragraph start.
18726
+ endMatch?.index !== void 0 ? 0 : void 0
18727
+ );
18728
+ if (startIndex === void 0) {
18729
+ return void 0;
18730
+ }
18731
+ const endIndex = endMatch?.index !== void 0 ? endMatch.index : sourceXml.length;
18732
+ if (endIndex <= startIndex) {
18733
+ return void 0;
18734
+ }
18735
+ return decodeCommentRangeText(sourceXml.slice(startIndex, endIndex));
18736
+ }
18737
+ function collectCommentsFromModel(model) {
18738
+ const definitions = model.metadata.comments ?? [];
18739
+ if (definitions.length === 0) {
18740
+ return [];
18741
+ }
18742
+ const definitionById = new Map(
18743
+ definitions.map((definition) => [definition.id, definition])
18744
+ );
18745
+ const comments = [];
18746
+ const appendParagraphComments = (paragraph, nodeIndex, location) => {
18747
+ const sourceXml = paragraph.sourceXml ?? "";
18748
+ if (!sourceXml || !/commentReference/i.test(sourceXml)) {
18749
+ return;
18750
+ }
18751
+ for (const match of sourceXml.matchAll(
18752
+ /<w:commentReference\b[^>]*w:id="(-?\d+)"/gi
18753
+ )) {
18754
+ const commentId = Number.parseInt(match[1] ?? "", 10);
18755
+ const definition = Number.isFinite(commentId) ? definitionById.get(commentId) : void 0;
18756
+ if (!definition) {
18757
+ continue;
18758
+ }
18759
+ comments.push({
18760
+ id: `${paragraphLocationKey(location)}:comment:${commentId}`,
18761
+ commentId,
18762
+ author: definition.author,
18763
+ initials: definition.initials,
18764
+ date: definition.date,
18765
+ text: definition.text,
18766
+ parentId: definition.parentId,
18767
+ resolved: definition.resolved,
18768
+ anchorText: resolveCommentAnchorText(sourceXml, commentId),
18769
+ nodeIndex,
18770
+ location: location.kind === "paragraph" ? { kind: "paragraph", nodeIndex: location.nodeIndex } : {
18771
+ kind: "table-cell",
18772
+ tableIndex: location.tableIndex,
18773
+ rowIndex: location.rowIndex,
18774
+ cellIndex: location.cellIndex,
18775
+ paragraphIndex: location.paragraphIndex
18776
+ }
18777
+ });
18778
+ }
18779
+ };
18780
+ model.nodes.forEach((node, nodeIndex) => {
18781
+ if (node.type === "paragraph") {
18782
+ appendParagraphComments(node, nodeIndex, {
18783
+ kind: "paragraph",
18784
+ nodeIndex
18785
+ });
18786
+ return;
18787
+ }
18788
+ node.rows.forEach((row, rowIndex) => {
18789
+ row.cells.forEach((cell, cellIndex) => {
18790
+ const directParagraphs = tableCellParagraphs(cell.nodes);
18791
+ directParagraphs.forEach((paragraph, paragraphIndex) => {
18792
+ appendParagraphComments(paragraph, nodeIndex, {
18793
+ kind: "table-cell",
18794
+ tableIndex: nodeIndex,
18795
+ rowIndex,
18796
+ cellIndex,
18797
+ paragraphIndex
18798
+ });
18799
+ });
18800
+ const nestedParagraphs = tableCellParagraphsRecursively(
18801
+ cell.nodes
18802
+ ).filter((paragraph) => !directParagraphs.includes(paragraph));
18803
+ nestedParagraphs.forEach((paragraph, nestedParagraphIndex) => {
18804
+ appendParagraphComments(paragraph, nodeIndex, {
18805
+ kind: "table-cell",
18806
+ tableIndex: nodeIndex,
18807
+ rowIndex,
18808
+ cellIndex,
18809
+ paragraphIndex: -(nestedParagraphIndex + 1)
18810
+ });
18811
+ });
18812
+ });
18813
+ });
18814
+ });
18815
+ return comments;
18816
+ }
18817
+ function commentAccentColor(documentTheme) {
18818
+ return documentTheme === "dark" ? "#fbbf24" : "#d97706";
18819
+ }
18820
+ function estimateCommentCardHeight(comment) {
18821
+ const snippet = comment.text || "Comment";
18822
+ const lines = Math.max(1, Math.ceil(snippet.length / 30));
18823
+ return Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, 34 + lines * 14);
18824
+ }
18370
18825
  function trackedChangeKindLabel(kind) {
18371
18826
  switch (kind) {
18372
18827
  case "insertion":
@@ -18415,15 +18870,15 @@ function trackedChangeAccentColor(kind, documentTheme) {
18415
18870
  return palette.format;
18416
18871
  }
18417
18872
  }
18418
- function trackedChangeSortTuple(change) {
18419
- if (change.location.kind === "paragraph") {
18420
- return [change.location.nodeIndex, 0, 0, 0];
18873
+ function gutterAnnotationSortTuple(location) {
18874
+ if (location.kind === "paragraph") {
18875
+ return [location.nodeIndex, 0, 0, 0];
18421
18876
  }
18422
18877
  return [
18423
- change.location.tableIndex,
18424
- change.location.rowIndex,
18425
- change.location.cellIndex,
18426
- change.location.paragraphIndex
18878
+ location.tableIndex,
18879
+ location.rowIndex,
18880
+ location.cellIndex,
18881
+ location.paragraphIndex
18427
18882
  ];
18428
18883
  }
18429
18884
  function trackedChangeBelongsToPageSegments(location, pageSegments) {
@@ -18442,10 +18897,10 @@ function trackedChangeBelongsToPageSegments(location, pageSegments) {
18442
18897
  return location.rowIndex >= segment.tableRowRange.startRowIndex && location.rowIndex < segment.tableRowRange.endRowIndex;
18443
18898
  });
18444
18899
  }
18445
- function resolveTrackedChangePageIndex(change, pageNodeSegmentsByPage) {
18900
+ function resolveGutterAnnotationPageIndex(location, pageNodeSegmentsByPage) {
18446
18901
  for (let pageIndex = 0; pageIndex < pageNodeSegmentsByPage.length; pageIndex += 1) {
18447
18902
  if (trackedChangeBelongsToPageSegments(
18448
- change.location,
18903
+ location,
18449
18904
  pageNodeSegmentsByPage[pageIndex] ?? []
18450
18905
  )) {
18451
18906
  return pageIndex;
@@ -18500,30 +18955,30 @@ function estimateTrackedChangeCardHeight(change) {
18500
18955
  const lines = Math.max(1, Math.ceil(snippet.length / 30));
18501
18956
  return Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, 34 + lines * 14);
18502
18957
  }
18503
- function layoutTrackedChangesForPage(changes, anchorByChangeId, cardHeightsByChangeId, pageWidthPx, pageHeightPx) {
18504
- if (changes.length === 0) {
18958
+ function layoutTrackedChangesForPage(annotations, anchorByChangeId, cardHeightsByChangeId, pageWidthPx, pageHeightPx) {
18959
+ if (annotations.length === 0) {
18505
18960
  return [];
18506
18961
  }
18507
18962
  const fallbackStride = Math.max(
18508
18963
  18,
18509
- pageHeightPx / Math.max(1, changes.length + 1)
18964
+ pageHeightPx / Math.max(1, annotations.length + 1)
18510
18965
  );
18511
- const withAnchors = changes.map((change, index) => {
18966
+ const withAnchors = annotations.map((annotation, index) => {
18512
18967
  const defaultAnchor = Math.min(
18513
18968
  Math.max(10, Math.round((index + 1) * fallbackStride)),
18514
18969
  Math.max(10, pageHeightPx - 10)
18515
18970
  );
18516
- const anchorPoint = anchorByChangeId.get(change.id);
18971
+ const anchorPoint = anchorByChangeId.get(annotation.id);
18517
18972
  const anchorY = anchorPoint?.y ?? defaultAnchor;
18518
18973
  const anchorX = anchorPoint?.x ?? Math.max(10, pageWidthPx - 10);
18519
- const measuredHeightPx = cardHeightsByChangeId?.get(change.id);
18520
- const estimatedHeightPx = estimateTrackedChangeCardHeight(change);
18974
+ const measuredHeightPx = cardHeightsByChangeId?.get(annotation.id);
18975
+ const estimatedHeightPx = annotation.trackedChange ? estimateTrackedChangeCardHeight(annotation.trackedChange) : annotation.comment ? estimateCommentCardHeight(annotation.comment) : TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX;
18521
18976
  const heightPx = Number.isFinite(measuredHeightPx) && measuredHeightPx > 0 ? Math.max(
18522
18977
  TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX,
18523
18978
  Math.round(measuredHeightPx)
18524
18979
  ) : estimatedHeightPx;
18525
18980
  return {
18526
- change,
18981
+ annotation,
18527
18982
  anchorX: clampNumber(
18528
18983
  Math.round(anchorX),
18529
18984
  10,
@@ -19554,10 +20009,14 @@ function useDocxEditor(options = {}) {
19554
20009
  const [isImporting, setIsImporting] = React.useState(false);
19555
20010
  const [documentTheme, setDocumentThemeState] = React.useState(options.initialDocumentTheme ?? "light");
19556
20011
  const [showTrackedChanges, setShowTrackedChangesState] = React.useState(options.initialShowTrackedChanges ?? false);
20012
+ const [showComments, setShowCommentsState] = React.useState(
20013
+ options.initialShowComments ?? false
20014
+ );
19557
20015
  const [paginationInfo, setPaginationInfo] = React.useState({
19558
20016
  currentPage: 1,
19559
20017
  totalPages: 1
19560
20018
  });
20019
+ const activeImportAbortControllerRef = React.useRef(void 0);
19561
20020
  const [history, setHistory] = React.useState({
19562
20021
  past: [],
19563
20022
  future: []
@@ -19870,6 +20329,9 @@ function useDocxEditor(options = {}) {
19870
20329
  () => collectTrackedChangesFromModel(model),
19871
20330
  [model]
19872
20331
  );
20332
+ const comments = React.useMemo(() => collectCommentsFromModel(model), [
20333
+ model
20334
+ ]);
19873
20335
  const hasUnorderedList = selectedListType === "unordered";
19874
20336
  const hasOrderedList = selectedListType === "ordered";
19875
20337
  const canUndo = history.past.length > 0;
@@ -19890,6 +20352,15 @@ function useDocxEditor(options = {}) {
19890
20352
  const toggleShowTrackedChanges = React.useCallback(() => {
19891
20353
  setShowTrackedChangesState((current) => !current);
19892
20354
  }, []);
20355
+ const setShowComments = React.useCallback(
20356
+ (nextShowComments) => {
20357
+ setShowCommentsState(nextShowComments);
20358
+ },
20359
+ []
20360
+ );
20361
+ const toggleShowComments = React.useCallback(() => {
20362
+ setShowCommentsState((current) => !current);
20363
+ }, []);
19893
20364
  const registerPendingExportModelTransformer = React.useCallback(
19894
20365
  (transformer) => {
19895
20366
  pendingExportModelTransformerRef.current = transformer;
@@ -19953,6 +20424,7 @@ function useDocxEditor(options = {}) {
19953
20424
  );
19954
20425
  React.useEffect(() => {
19955
20426
  return () => {
20427
+ activeImportAbortControllerRef.current?.abort();
19956
20428
  unloadEmbeddedFonts();
19957
20429
  };
19958
20430
  }, [unloadEmbeddedFonts]);
@@ -20088,6 +20560,8 @@ function useDocxEditor(options = {}) {
20088
20560
  );
20089
20561
  const importDocxFile = React.useCallback(
20090
20562
  async (file) => {
20563
+ activeImportAbortControllerRef.current?.abort();
20564
+ activeImportAbortControllerRef.current = void 0;
20091
20565
  if (!/\.docx?$/i.test(file.name)) {
20092
20566
  replaceDocumentWithImportError(
20093
20567
  file.name,
@@ -20098,11 +20572,50 @@ function useDocxEditor(options = {}) {
20098
20572
  setIsImporting(true);
20099
20573
  setImportError(void 0);
20100
20574
  setStatus(`Loading ${file.name}...`);
20575
+ const importAbortController = new AbortController();
20576
+ activeImportAbortControllerRef.current = importAbortController;
20577
+ const traceName = createDocxImportPerformanceTraceName(file.name);
20578
+ const startMark = `${traceName}:start`;
20579
+ const bufferStartMark = `${traceName}:arrayBuffer:start`;
20580
+ const bufferEndMark = `${traceName}:arrayBuffer:end`;
20581
+ const workerStartMark = `${traceName}:worker:start`;
20582
+ const workerEndMark = `${traceName}:worker:end`;
20583
+ const fontsStartMark = `${traceName}:fonts:start`;
20584
+ const fontsEndMark = `${traceName}:fonts:end`;
20585
+ const stateStartMark = `${traceName}:state:start`;
20586
+ const stateEndMark = `${traceName}:state:end`;
20587
+ markDocxImportPerformance(startMark);
20101
20588
  try {
20589
+ markDocxImportPerformance(bufferStartMark);
20102
20590
  const buffer = await file.arrayBuffer();
20103
- const pkg = await parseDocx(buffer);
20591
+ markDocxImportPerformance(bufferEndMark);
20592
+ measureDocxImportPerformance(
20593
+ `${traceName}:arrayBuffer`,
20594
+ bufferStartMark,
20595
+ bufferEndMark
20596
+ );
20597
+ markDocxImportPerformance(workerStartMark);
20598
+ const importResult = await importDocxBuffer(buffer, {
20599
+ signal: importAbortController.signal,
20600
+ transferBuffer: true
20601
+ });
20602
+ markDocxImportPerformance(workerEndMark);
20603
+ measureDocxImportPerformance(
20604
+ `${traceName}:${importResult.source}`,
20605
+ workerStartMark,
20606
+ workerEndMark
20607
+ );
20608
+ const pkg = importResult.package;
20609
+ const nextModel = importResult.model;
20610
+ markDocxImportPerformance(fontsStartMark);
20104
20611
  await loadEmbeddedFontsFromPackage(pkg);
20105
- const nextModel = await buildDocModel(pkg);
20612
+ markDocxImportPerformance(fontsEndMark);
20613
+ measureDocxImportPerformance(
20614
+ `${traceName}:fonts`,
20615
+ fontsStartMark,
20616
+ fontsEndMark
20617
+ );
20618
+ markDocxImportPerformance(stateStartMark);
20106
20619
  setModel(nextModel);
20107
20620
  setDocumentLoadNonce((current) => current + 1);
20108
20621
  setHistory({ past: [], future: [] });
@@ -20115,16 +20628,31 @@ function useDocxEditor(options = {}) {
20115
20628
  setSelectedFormFieldLocation(void 0);
20116
20629
  setImportError(void 0);
20117
20630
  setStatus(`Loaded ${file.name}`);
20631
+ markDocxImportPerformance(stateEndMark);
20632
+ measureDocxImportPerformance(
20633
+ `${traceName}:state-dispatch`,
20634
+ stateStartMark,
20635
+ stateEndMark
20636
+ );
20637
+ measureDocxImportPerformance(`${traceName}:total`, startMark, stateEndMark);
20118
20638
  } catch (error) {
20639
+ if (error instanceof Error && error.name === "AbortError" && activeImportAbortControllerRef.current !== importAbortController) {
20640
+ return;
20641
+ }
20119
20642
  const nextError = error instanceof Error ? error : new Error("Unknown error");
20120
20643
  replaceDocumentWithImportError(file.name, nextError);
20121
20644
  } finally {
20122
- setIsImporting(false);
20645
+ if (activeImportAbortControllerRef.current === importAbortController) {
20646
+ activeImportAbortControllerRef.current = void 0;
20647
+ setIsImporting(false);
20648
+ }
20123
20649
  }
20124
20650
  },
20125
20651
  [loadEmbeddedFontsFromPackage, replaceDocumentWithImportError]
20126
20652
  );
20127
20653
  const newDocument = React.useCallback(() => {
20654
+ activeImportAbortControllerRef.current?.abort();
20655
+ activeImportAbortControllerRef.current = void 0;
20128
20656
  unloadEmbeddedFonts();
20129
20657
  setModel(cloneDocModel(starterTemplateRef.current));
20130
20658
  setDocumentLoadNonce((current) => current + 1);
@@ -23050,6 +23578,8 @@ function useDocxEditor(options = {}) {
23050
23578
  documentTheme,
23051
23579
  trackedChanges,
23052
23580
  showTrackedChanges,
23581
+ comments,
23582
+ showComments,
23053
23583
  currentPage: paginationInfo.currentPage,
23054
23584
  totalPages: paginationInfo.totalPages,
23055
23585
  selection,
@@ -23077,8 +23607,10 @@ function useDocxEditor(options = {}) {
23077
23607
  setStatus,
23078
23608
  setDocumentTheme,
23079
23609
  setShowTrackedChanges,
23610
+ setShowComments,
23080
23611
  syncPaginationInfo,
23081
23612
  toggleShowTrackedChanges,
23613
+ toggleShowComments,
23082
23614
  importDocxFile,
23083
23615
  newDocument,
23084
23616
  exportDocx,
@@ -23365,6 +23897,7 @@ function useDocxPageThumbnails(editor, options = {}) {
23365
23897
  if (!targetCanvas) {
23366
23898
  return;
23367
23899
  }
23900
+ const requiresAttachedTarget = canvas === void 0;
23368
23901
  const pageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
23369
23902
  if (!pageElement || !pageElement.isConnected) {
23370
23903
  updatePageThumbnailState(pageIndex, "unavailable");
@@ -23378,6 +23911,9 @@ function useDocxPageThumbnails(editor, options = {}) {
23378
23911
  }
23379
23912
  updatePageThumbnailState(pageIndex, "rendering");
23380
23913
  await ensureThumbnailRasterQueue().enqueue(targetCanvas, async () => {
23914
+ if (requiresAttachedTarget && attachedCanvasByPageRef.current.get(pageIndex) !== targetCanvas) {
23915
+ return;
23916
+ }
23381
23917
  const livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
23382
23918
  if (!livePageElement || !livePageElement.isConnected) {
23383
23919
  updatePageThumbnailState(pageIndex, "unavailable");
@@ -23524,6 +24060,10 @@ function useDocxPageThumbnails(editor, options = {}) {
23524
24060
  void renderPageThumbnailToCanvasRef.current(pageIndex, canvas);
23525
24061
  return;
23526
24062
  }
24063
+ const previousCanvas = attachedCanvasByPageRef.current.get(pageIndex);
24064
+ if (previousCanvas) {
24065
+ thumbnailRasterQueueRef.current?.cancel(previousCanvas);
24066
+ }
23527
24067
  attachedCanvasByPageRef.current.delete(pageIndex);
23528
24068
  };
23529
24069
  canvasRefCallbacksRef.current.set(pageIndex, nextCanvasRef);
@@ -23791,6 +24331,42 @@ function useDocxTrackChanges(editor) {
23791
24331
  ]
23792
24332
  );
23793
24333
  }
24334
+ function useDocxComments(editor) {
24335
+ const commentsByLocation = React.useMemo(() => {
24336
+ const grouped = /* @__PURE__ */ new Map();
24337
+ editor.comments.forEach((comment) => {
24338
+ const key = paragraphLocationKey(comment.location);
24339
+ const bucket = grouped.get(key) ?? [];
24340
+ bucket.push(comment);
24341
+ grouped.set(key, bucket);
24342
+ });
24343
+ return grouped;
24344
+ }, [editor.comments]);
24345
+ const getCommentsForLocation = React.useCallback(
24346
+ (location) => {
24347
+ return commentsByLocation.get(paragraphLocationKey(location)) ?? [];
24348
+ },
24349
+ [commentsByLocation]
24350
+ );
24351
+ return React.useMemo(
24352
+ () => ({
24353
+ comments: editor.comments,
24354
+ showComments: editor.showComments,
24355
+ setShowComments: editor.setShowComments,
24356
+ toggleShowComments: editor.toggleShowComments,
24357
+ commentsByLocation,
24358
+ getCommentsForLocation
24359
+ }),
24360
+ [
24361
+ editor.comments,
24362
+ editor.showComments,
24363
+ editor.setShowComments,
24364
+ editor.toggleShowComments,
24365
+ commentsByLocation,
24366
+ getCommentsForLocation
24367
+ ]
24368
+ );
24369
+ }
23794
24370
  function useDocxPageLayout(editor) {
23795
24371
  const primarySectionPropertiesXml = editor.model.metadata.sections?.[0]?.sectionPropertiesXml ?? editor.model.metadata.sectionPropertiesXml;
23796
24372
  const layout = React.useMemo(() => {
@@ -24663,6 +25239,8 @@ function DocxEditorViewer({
24663
25239
  headingStyles,
24664
25240
  showTrackedChanges,
24665
25241
  renderTrackedChangeCard,
25242
+ showComments,
25243
+ renderCommentCard,
24666
25244
  renderTableContextMenu,
24667
25245
  renderContextMenu,
24668
25246
  onFormFieldDoubleClick,
@@ -24671,7 +25249,9 @@ function DocxEditorViewer({
24671
25249
  const pageSurfaceRegistryOwner = docxViewerPageSurfaceRegistryOwner(editor);
24672
25250
  const trackedChangesEnabled = showTrackedChanges ?? editor.showTrackedChanges;
24673
25251
  const hasTrackedChanges = editor.trackedChanges.length > 0;
24674
- const showTrackedChangeGutter = trackedChangesEnabled;
25252
+ const commentsEnabled = showComments ?? editor.showComments;
25253
+ const hasComments = editor.comments.length > 0;
25254
+ const showTrackedChangeGutter = trackedChangesEnabled || commentsEnabled;
24675
25255
  const isReadOnly = mode === "read-only" || trackedChangesEnabled;
24676
25256
  const isNightReaderMode = isReadOnly && editor.documentTheme === "dark";
24677
25257
  const documentContentTheme = isNightReaderMode ? "light" : editor.documentTheme;
@@ -24690,11 +25270,13 @@ function DocxEditorViewer({
24690
25270
  const paragraphRunRenderOptions = React.useMemo(
24691
25271
  () => ({
24692
25272
  showTrackedChanges: trackedChangesEnabled,
25273
+ showCommentHighlights: commentsEnabled,
24693
25274
  numberingDefinitions: editor.model.metadata.numberingDefinitions,
24694
25275
  tocLinkColorByLevel,
24695
25276
  imageFilterSuffix: documentContentFilter
24696
25277
  }),
24697
25278
  [
25279
+ commentsEnabled,
24698
25280
  documentContentFilter,
24699
25281
  editor.model.metadata.numberingDefinitions,
24700
25282
  tocLinkColorByLevel,
@@ -24737,7 +25319,6 @@ function DocxEditorViewer({
24737
25319
  /* @__PURE__ */ new Map()
24738
25320
  );
24739
25321
  const pageElementsRef = React.useRef(/* @__PURE__ */ new Map());
24740
- const pagePlaceholderRefCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
24741
25322
  const pageSurfaceRefCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
24742
25323
  const trackedChangeCardElementsRef = React.useRef(/* @__PURE__ */ new Map());
24743
25324
  const initialPaginationStableSignatureRef = React.useRef(
@@ -24805,26 +25386,6 @@ function DocxEditorViewer({
24805
25386
  measuredPageContentHeightByIndex,
24806
25387
  setMeasuredPageContentHeightByIndex
24807
25388
  ] = React.useState([]);
24808
- const pagePlaceholderRefForIndex = React.useCallback(
24809
- (pageIndex) => {
24810
- const normalizedPageIndex = Math.max(0, Math.round(pageIndex));
24811
- const cached = pagePlaceholderRefCallbacksRef.current.get(normalizedPageIndex);
24812
- if (cached) {
24813
- return cached;
24814
- }
24815
- const nextRef = (element) => {
24816
- if (element) {
24817
- pageElementsRef.current.set(normalizedPageIndex, element);
24818
- } else {
24819
- pageElementsRef.current.delete(normalizedPageIndex);
24820
- }
24821
- registerDocxViewerPageSurface(editor, normalizedPageIndex, void 0);
24822
- };
24823
- pagePlaceholderRefCallbacksRef.current.set(normalizedPageIndex, nextRef);
24824
- return nextRef;
24825
- },
24826
- [pageSurfaceRegistryOwner]
24827
- );
24828
25389
  const pageSurfaceRefForIndex = React.useCallback(
24829
25390
  (pageIndex) => {
24830
25391
  const normalizedPageIndex = Math.max(0, Math.round(pageIndex));
@@ -24846,7 +25407,6 @@ function DocxEditorViewer({
24846
25407
  [pageSurfaceRegistryOwner]
24847
25408
  );
24848
25409
  React.useEffect(() => {
24849
- pagePlaceholderRefCallbacksRef.current.clear();
24850
25410
  pageSurfaceRefCallbacksRef.current.clear();
24851
25411
  }, [pageSurfaceRegistryOwner]);
24852
25412
  const [
@@ -26087,6 +26647,17 @@ function DocxEditorViewer({
26087
26647
  const pageVirtualizationOverscan = hasLargeTableLayoutSurface && !Number.isFinite(pageVirtualization?.overscan) ? LARGE_TABLE_PAGE_VIRTUALIZATION_OVERSCAN : rawPageVirtualizationOverscan;
26088
26648
  const webdriverActive = typeof navigator !== "undefined" && navigator.webdriver === true;
26089
26649
  const internalPageVirtualizationRequested = pageVirtualization?.enabled !== false && !hasExternalVisiblePageRange && !hideDocumentUntilPaginationSettled && isInitialPaginationSettled && !deferInternalPageVirtualization && !webdriverActive && pageCount > 1;
26650
+ const explicitPageVirtualizationScrollElement = pageVirtualization?.scrollElement ?? null;
26651
+ const explicitPageVirtualizationZoomScale = normalizePageVirtualizationZoomScale(pageVirtualization?.zoomScale);
26652
+ const resolveViewerMeasurementZoomScale = React.useCallback(
26653
+ (rootElement, fallback = 1) => {
26654
+ if (explicitPageVirtualizationZoomScale !== void 0) {
26655
+ return explicitPageVirtualizationZoomScale;
26656
+ }
26657
+ return rootElement ? resolveEffectiveZoomScale(rootElement) : fallback;
26658
+ },
26659
+ [explicitPageVirtualizationZoomScale]
26660
+ );
26090
26661
  React.useEffect(() => {
26091
26662
  setDeferInternalPageVirtualization(!hasLargeTableLayoutSurface);
26092
26663
  }, [editor.documentLoadNonce, hasLargeTableLayoutSurface]);
@@ -26117,9 +26688,34 @@ function DocxEditorViewer({
26117
26688
  return;
26118
26689
  }
26119
26690
  setInternalVirtualScrollElement(
26120
- nearestScrollableAncestor(viewerRootRef.current)
26691
+ explicitPageVirtualizationScrollElement instanceof HTMLElement ? explicitPageVirtualizationScrollElement : nearestScrollableAncestor(viewerRootRef.current)
26121
26692
  );
26122
- }, [editor.documentLoadNonce, pageCount, trackedChangesEnabled]);
26693
+ }, [
26694
+ editor.documentLoadNonce,
26695
+ explicitPageVirtualizationScrollElement,
26696
+ pageCount,
26697
+ trackedChangesEnabled
26698
+ ]);
26699
+ const [zoomProbeNonce, setZoomProbeNonce] = React.useState(0);
26700
+ React.useEffect(() => {
26701
+ if (typeof window === "undefined") {
26702
+ return;
26703
+ }
26704
+ const rootElement = viewerRootRef.current;
26705
+ if (!rootElement) {
26706
+ return;
26707
+ }
26708
+ const bumpZoomProbe = () => {
26709
+ setZoomProbeNonce((nonce) => nonce + 1);
26710
+ };
26711
+ const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(bumpZoomProbe) : void 0;
26712
+ resizeObserver?.observe(rootElement);
26713
+ window.addEventListener("resize", bumpZoomProbe);
26714
+ return () => {
26715
+ resizeObserver?.disconnect();
26716
+ window.removeEventListener("resize", bumpZoomProbe);
26717
+ };
26718
+ }, [editor.documentLoadNonce]);
26123
26719
  React.useLayoutEffect(() => {
26124
26720
  if (typeof window === "undefined") {
26125
26721
  return;
@@ -26128,11 +26724,22 @@ function DocxEditorViewer({
26128
26724
  if (!rootElement) {
26129
26725
  return;
26130
26726
  }
26131
- const nextScale = Math.round(resolveEffectiveZoomScale(rootElement) * 100) / 100;
26727
+ const nextScale = Math.round(
26728
+ resolveViewerMeasurementZoomScale(
26729
+ rootElement,
26730
+ virtualizerMeasurementScale
26731
+ ) * 100
26732
+ ) / 100;
26132
26733
  setVirtualizerMeasurementScale(
26133
26734
  (current) => Math.abs(current - nextScale) < 5e-3 ? current : nextScale
26134
26735
  );
26135
- });
26736
+ }, [
26737
+ editor.documentLoadNonce,
26738
+ pageCount,
26739
+ resolveViewerMeasurementZoomScale,
26740
+ virtualizerMeasurementScale,
26741
+ zoomProbeNonce
26742
+ ]);
26136
26743
  const internalPageVirtualizationEnabled = internalPageVirtualizationRequested && internalVirtualScrollElement !== null;
26137
26744
  const internalPageVirtualizationPending = typeof window !== "undefined" && internalPageVirtualizationRequested && internalVirtualScrollElement === null;
26138
26745
  const internalVirtualScrollUsesWindow = typeof document !== "undefined" && internalVirtualScrollElement !== null && (internalVirtualScrollElement === document.scrollingElement || internalVirtualScrollElement === document.documentElement || internalVirtualScrollElement === document.body);
@@ -26175,6 +26782,30 @@ function DocxEditorViewer({
26175
26782
  internalWindowPageVirtualizer
26176
26783
  ]);
26177
26784
  const internalVirtualItems = internalPageVirtualizer.getVirtualItems();
26785
+ const internalMostVisiblePageIndex = React.useMemo(() => {
26786
+ if (!internalPageVirtualizationEnabled || internalVirtualItems.length === 0) {
26787
+ return void 0;
26788
+ }
26789
+ const virtualizerMetrics = internalPageVirtualizer;
26790
+ const viewportStart = Number.isFinite(virtualizerMetrics.scrollOffset) ? virtualizerMetrics.scrollOffset : internalVirtualItems[0]?.start ?? 0;
26791
+ const viewportSize = virtualizerMetrics.scrollRect?.height;
26792
+ const viewportEnd = viewportStart + (Number.isFinite(viewportSize) && viewportSize > 0 ? viewportSize : internalVirtualItems[0]?.size ?? 0);
26793
+ let bestPageIndex;
26794
+ let bestVisibleSize = -1;
26795
+ internalVirtualItems.forEach((item) => {
26796
+ const visibleSize = Math.min(item.end, viewportEnd) - Math.max(item.start, viewportStart);
26797
+ if (visibleSize > bestVisibleSize) {
26798
+ bestVisibleSize = visibleSize;
26799
+ bestPageIndex = item.index;
26800
+ }
26801
+ });
26802
+ return bestPageIndex === void 0 ? void 0 : clampNumber(bestPageIndex, 0, pageCount - 1);
26803
+ }, [
26804
+ internalPageVirtualizationEnabled,
26805
+ internalPageVirtualizer,
26806
+ internalVirtualItems,
26807
+ pageCount
26808
+ ]);
26178
26809
  const internalVisiblePageRange = React.useMemo(() => {
26179
26810
  if (!internalPageVirtualizationEnabled) {
26180
26811
  return void 0;
@@ -26465,6 +27096,40 @@ function DocxEditorViewer({
26465
27096
  }
26466
27097
  return indexes;
26467
27098
  }, [pageCount, visiblePageEndIndex, visiblePageStartIndex]);
27099
+ const pageStackVirtualSpacers = React.useMemo(() => {
27100
+ const pageWrapperWidthPxForIndex = (pageIndex) => {
27101
+ const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
27102
+ return showTrackedChangeGutter ? pageLayout.pageWidthPx + TRACKED_CHANGE_GUTTER_WIDTH_PX : pageLayout.pageWidthPx;
27103
+ };
27104
+ const summarizeSkippedPages = (startPageIndex, endPageIndex) => {
27105
+ if (pageCount <= 0 || endPageIndex < startPageIndex || startPageIndex >= pageCount || endPageIndex < 0) {
27106
+ return { heightPx: 0, widthPx: 0 };
27107
+ }
27108
+ const start = clampNumber(startPageIndex, 0, pageCount - 1);
27109
+ const end = clampNumber(endPageIndex, start, pageCount - 1);
27110
+ let heightPx = 0;
27111
+ let widthPx = 0;
27112
+ for (let pageIndex = start; pageIndex <= end; pageIndex += 1) {
27113
+ const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
27114
+ heightPx += Math.max(1, Math.round(pageLayout.pageHeightPx));
27115
+ widthPx = Math.max(widthPx, pageWrapperWidthPxForIndex(pageIndex));
27116
+ }
27117
+ const skippedPageCount = end - start + 1;
27118
+ heightPx += Math.max(0, skippedPageCount - 1) * DOC_PAGE_BREAK_GAP;
27119
+ return { heightPx, widthPx };
27120
+ };
27121
+ return {
27122
+ before: summarizeSkippedPages(0, visiblePageStartIndex - 1),
27123
+ after: summarizeSkippedPages(visiblePageEndIndex + 1, pageCount - 1)
27124
+ };
27125
+ }, [
27126
+ documentLayout,
27127
+ pageCount,
27128
+ pageSectionInfoByIndex,
27129
+ showTrackedChangeGutter,
27130
+ visiblePageEndIndex,
27131
+ visiblePageStartIndex
27132
+ ]);
26468
27133
  React.useLayoutEffect(() => {
26469
27134
  if (typeof window === "undefined") {
26470
27135
  return;
@@ -26476,7 +27141,7 @@ function DocxEditorViewer({
26476
27141
  const next = new Map(current);
26477
27142
  let changed = false;
26478
27143
  const rootElement = viewerRootRef.current;
26479
- const zoomScale = rootElement ? resolveEffectiveZoomScale(rootElement) : 1;
27144
+ const zoomScale = resolveViewerMeasurementZoomScale(rootElement, 1);
26480
27145
  paragraphElementsRef.current.forEach((element, nodeIndex) => {
26481
27146
  if (!element.isConnected || element.dataset.docxParagraphPartialLineRange === "true" || element.closest('[data-docx-header-footer-region="footer"]') || element.closest('[data-docx-header-footer-region="header"]')) {
26482
27147
  return;
@@ -26505,6 +27170,7 @@ function DocxEditorViewer({
26505
27170
  }, [
26506
27171
  editor.documentLoadNonce,
26507
27172
  pageNodeSegmentIdentityKeysByPage,
27173
+ resolveViewerMeasurementZoomScale,
26508
27174
  visiblePageEndIndex,
26509
27175
  visiblePageStartIndex
26510
27176
  ]);
@@ -26624,7 +27290,7 @@ function DocxEditorViewer({
26624
27290
  }, [onPageCountChange, stableReportedPageCount]);
26625
27291
  React.useEffect(() => {
26626
27292
  const nextCurrentPage = clampNumber(
26627
- visiblePageStartIndex + 1,
27293
+ (internalMostVisiblePageIndex ?? visiblePageStartIndex) + 1,
26628
27294
  1,
26629
27295
  Math.max(1, stableReportedPageCount)
26630
27296
  );
@@ -26634,6 +27300,7 @@ function DocxEditorViewer({
26634
27300
  });
26635
27301
  }, [
26636
27302
  editor.syncPaginationInfo,
27303
+ internalMostVisiblePageIndex,
26637
27304
  stableReportedPageCount,
26638
27305
  visiblePageStartIndex
26639
27306
  ]);
@@ -26641,20 +27308,38 @@ function DocxEditorViewer({
26641
27308
  const pageBuckets = pageNodeSegmentsByPage.map(
26642
27309
  () => []
26643
27310
  );
26644
- editor.trackedChanges.forEach((change) => {
26645
- const pageIndex = resolveTrackedChangePageIndex(
26646
- change,
27311
+ const placeAnnotation = (annotation) => {
27312
+ const pageIndex = resolveGutterAnnotationPageIndex(
27313
+ annotation.location,
26647
27314
  pageNodeSegmentsByPage
26648
27315
  );
26649
27316
  if (pageIndex < 0 || pageIndex >= pageBuckets.length) {
26650
27317
  return;
26651
27318
  }
26652
- pageBuckets[pageIndex].push(change);
26653
- });
26654
- pageBuckets.forEach((pageChanges) => {
26655
- pageChanges.sort((left, right) => {
26656
- const leftKey = trackedChangeSortTuple(left);
26657
- const rightKey = trackedChangeSortTuple(right);
27319
+ pageBuckets[pageIndex].push(annotation);
27320
+ };
27321
+ if (trackedChangesEnabled) {
27322
+ editor.trackedChanges.forEach((change) => {
27323
+ placeAnnotation({
27324
+ id: change.id,
27325
+ location: change.location,
27326
+ trackedChange: change
27327
+ });
27328
+ });
27329
+ }
27330
+ if (commentsEnabled) {
27331
+ editor.comments.forEach((comment) => {
27332
+ placeAnnotation({
27333
+ id: comment.id,
27334
+ location: comment.location,
27335
+ comment
27336
+ });
27337
+ });
27338
+ }
27339
+ pageBuckets.forEach((pageAnnotations) => {
27340
+ pageAnnotations.sort((left, right) => {
27341
+ const leftKey = gutterAnnotationSortTuple(left.location);
27342
+ const rightKey = gutterAnnotationSortTuple(right.location);
26658
27343
  for (let index = 0; index < leftKey.length; index += 1) {
26659
27344
  if (leftKey[index] === rightKey[index]) {
26660
27345
  continue;
@@ -26665,7 +27350,13 @@ function DocxEditorViewer({
26665
27350
  });
26666
27351
  });
26667
27352
  return pageBuckets;
26668
- }, [editor.trackedChanges, pageNodeSegmentsByPage]);
27353
+ }, [
27354
+ commentsEnabled,
27355
+ editor.comments,
27356
+ editor.trackedChanges,
27357
+ pageNodeSegmentsByPage,
27358
+ trackedChangesEnabled
27359
+ ]);
26669
27360
  const [trackedChangeAnchorByPage, setTrackedChangeAnchorByPage] = React.useState([]);
26670
27361
  const [headerBodyClearanceByPage, setHeaderBodyClearanceByPage] = React.useState({});
26671
27362
  React.useEffect(() => {
@@ -26679,18 +27370,18 @@ function DocxEditorViewer({
26679
27370
  );
26680
27371
  return;
26681
27372
  }
26682
- const nextAnchorMaps = trackedChangesByPage.map((changes, pageIndex) => {
27373
+ const nextAnchorMaps = trackedChangesByPage.map((annotations, pageIndex) => {
26683
27374
  const pageElement = pageElementsRef.current.get(pageIndex);
26684
27375
  const anchorsByChangeId = /* @__PURE__ */ new Map();
26685
- if (!pageElement || changes.length === 0) {
27376
+ if (!pageElement || annotations.length === 0) {
26686
27377
  return anchorsByChangeId;
26687
27378
  }
26688
27379
  const pageHeightPx = Math.max(1, pageElement.offsetHeight);
26689
27380
  const pageWidthPx = Math.max(1, pageElement.offsetWidth);
26690
- changes.forEach((change) => {
27381
+ annotations.forEach((annotation) => {
26691
27382
  const anchorElement = findTrackedChangeAnchorElementInPage(
26692
27383
  pageElement,
26693
- change.location
27384
+ annotation.location
26694
27385
  );
26695
27386
  if (!anchorElement) {
26696
27387
  return;
@@ -26714,7 +27405,7 @@ function DocxEditorViewer({
26714
27405
  10,
26715
27406
  Math.max(10, pageWidthPx - 10)
26716
27407
  );
26717
- anchorsByChangeId.set(change.id, { x: anchorX, y: anchorY });
27408
+ anchorsByChangeId.set(annotation.id, { x: anchorX, y: anchorY });
26718
27409
  });
26719
27410
  return anchorsByChangeId;
26720
27411
  });
@@ -26732,28 +27423,30 @@ function DocxEditorViewer({
26732
27423
  );
26733
27424
  return;
26734
27425
  }
26735
- const nextHeightsByPage = trackedChangesByPage.map((changes, pageIndex) => {
26736
- const pageHeights = /* @__PURE__ */ new Map();
26737
- changes.forEach((change) => {
26738
- const cardElement = trackedChangeCardElementsRef.current.get(
26739
- `${pageIndex}:${change.id}`
26740
- );
26741
- if (!cardElement) {
26742
- return;
26743
- }
26744
- const measuredHeight = Math.round(
26745
- cardElement.getBoundingClientRect().height
26746
- );
26747
- if (!Number.isFinite(measuredHeight) || measuredHeight <= 0) {
26748
- return;
26749
- }
26750
- pageHeights.set(
26751
- change.id,
26752
- Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, measuredHeight)
26753
- );
26754
- });
26755
- return pageHeights;
26756
- });
27426
+ const nextHeightsByPage = trackedChangesByPage.map(
27427
+ (annotations, pageIndex) => {
27428
+ const pageHeights = /* @__PURE__ */ new Map();
27429
+ annotations.forEach((annotation) => {
27430
+ const cardElement = trackedChangeCardElementsRef.current.get(
27431
+ `${pageIndex}:${annotation.id}`
27432
+ );
27433
+ if (!cardElement) {
27434
+ return;
27435
+ }
27436
+ const measuredHeight = Math.round(
27437
+ cardElement.getBoundingClientRect().height
27438
+ );
27439
+ if (!Number.isFinite(measuredHeight) || measuredHeight <= 0) {
27440
+ return;
27441
+ }
27442
+ pageHeights.set(
27443
+ annotation.id,
27444
+ Math.max(TRACKED_CHANGE_GUTTER_CARD_MIN_HEIGHT_PX, measuredHeight)
27445
+ );
27446
+ });
27447
+ return pageHeights;
27448
+ }
27449
+ );
26757
27450
  setTrackedChangeCardHeightsByPage((current) => {
26758
27451
  if (current.length === nextHeightsByPage.length) {
26759
27452
  let equal = true;
@@ -26999,7 +27692,7 @@ function DocxEditorViewer({
26999
27692
  );
27000
27693
  return;
27001
27694
  }
27002
- const zoomScale = resolveEffectiveZoomScale(rootElement);
27695
+ const zoomScale = resolveViewerMeasurementZoomScale(rootElement, 1);
27003
27696
  const next = {};
27004
27697
  for (let pageIndex = 0; pageIndex < pageCount; pageIndex += 1) {
27005
27698
  if (!isPageVisible(pageIndex)) {
@@ -27086,6 +27779,7 @@ function DocxEditorViewer({
27086
27779
  pageCount,
27087
27780
  pageHeaderAndFooterNodes,
27088
27781
  pageSectionInfoByIndex,
27782
+ resolveViewerMeasurementZoomScale,
27089
27783
  visiblePageEndIndex,
27090
27784
  visiblePageStartIndex
27091
27785
  ]);
@@ -27115,7 +27809,7 @@ function DocxEditorViewer({
27115
27809
  if (Date.now() < paginationMeasurementSuspendUntilRef.current) {
27116
27810
  return;
27117
27811
  }
27118
- const zoomScale = resolveEffectiveZoomScale(rootElement);
27812
+ const zoomScale = resolveViewerMeasurementZoomScale(rootElement, 1);
27119
27813
  const nextMeasuredPageIdentityKeys = pageNodeSegmentIdentityKeysByPage;
27120
27814
  const nextMeasuredPageDiagnostics = pageNodeSegmentsByPage.map(
27121
27815
  (_, pageIndex) => {
@@ -27252,9 +27946,14 @@ function DocxEditorViewer({
27252
27946
  },
27253
27947
  []
27254
27948
  );
27949
+ const storedDocumentPageCountForLatch = editor.model.metadata.documentPageCount;
27950
+ const latchTargetPageCount = Number.isFinite(storedDocumentPageCountForLatch) ? Math.max(
27951
+ collectDocxHardPageBreakStartNodeIndexes(editor.model).size + 1,
27952
+ Math.round(storedDocumentPageCountForLatch)
27953
+ ) : void 0;
27255
27954
  const nextMeasuredBodyFooterOverlapLatchState = resolveMeasuredBodyFooterOverlapLatchState({
27256
27955
  pageCount,
27257
- targetPageCount: editor.model.metadata.documentPageCount,
27956
+ targetPageCount: latchTargetPageCount,
27258
27957
  overlappingPageIndexes,
27259
27958
  previousSignature: measuredBodyFooterOverlapCandidateRef.current.signature,
27260
27959
  previousConsecutivePasses: measuredBodyFooterOverlapCandidateRef.current.consecutivePasses,
@@ -27325,6 +28024,7 @@ function DocxEditorViewer({
27325
28024
  pageNodeSegmentIdentityKeysByPage,
27326
28025
  pageSectionInfoByIndex,
27327
28026
  pageHeaderAndFooterNodes,
28027
+ resolveViewerMeasurementZoomScale,
27328
28028
  visiblePageEndIndex,
27329
28029
  visiblePageStartIndex
27330
28030
  ]);
@@ -31759,7 +32459,10 @@ function DocxEditorViewer({
31759
32459
  return;
31760
32460
  }
31761
32461
  const rootElement = viewerRootRef.current;
31762
- const zoomScale = rootElement ? resolveEffectiveZoomScale(rootElement) : virtualizerMeasurementScale;
32462
+ const zoomScale = resolveViewerMeasurementZoomScale(
32463
+ rootElement,
32464
+ virtualizerMeasurementScale
32465
+ );
31763
32466
  const nextMeasuredHeights = {};
31764
32467
  editor.model.nodes.forEach((node, nodeIndex) => {
31765
32468
  if (node.type !== "table") {
@@ -31901,6 +32604,7 @@ function DocxEditorViewer({
31901
32604
  pageContentWidthPxByNodeIndex,
31902
32605
  paginationMeasurementEnabled,
31903
32606
  paginationMeasurementEpoch,
32607
+ resolveViewerMeasurementZoomScale,
31904
32608
  tableMeasuredRowHeights,
31905
32609
  tableColumnWidths,
31906
32610
  tableRowHeights,
@@ -34083,7 +34787,8 @@ function DocxEditorViewer({
34083
34787
  const hasFixedPositionWrappedImage = paragraph.children.some(
34084
34788
  (child) => child.type === "image" && isFixedPositionWrappedFloatingImage(child)
34085
34789
  );
34086
- if ((trackedChangesEnabled || useSpecialTabLayout) && !hasFixedPositionWrappedImage) {
34790
+ const paragraphHasCommentAnchors = commentsEnabled && /commentRange|commentReference/i.test(paragraph.sourceXml ?? "");
34791
+ if ((trackedChangesEnabled || useSpecialTabLayout || paragraphHasCommentAnchors) && !hasFixedPositionWrappedImage) {
34087
34792
  return renderParagraphRuns(
34088
34793
  paragraph,
34089
34794
  keyPrefix,
@@ -34096,6 +34801,7 @@ function DocxEditorViewer({
34096
34801
  void 0,
34097
34802
  {
34098
34803
  showTrackedChanges: trackedChangesEnabled,
34804
+ showCommentHighlights: commentsEnabled,
34099
34805
  numberingDefinitions: editor.model.metadata.numberingDefinitions,
34100
34806
  tocLinkColorByLevel,
34101
34807
  paragraphOriginLeftPx: bodyParagraphOriginLeftPx,
@@ -40439,44 +41145,25 @@ ${currentText.slice(end)}`;
40439
41145
  }
40440
41146
  }
40441
41147
  ) : null,
40442
- pageNodeSegmentsByPage.map((pageNodeSegments, pageIndex) => {
41148
+ pageStackVirtualSpacers.before.heightPx > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41149
+ "div",
41150
+ {
41151
+ "aria-hidden": "true",
41152
+ "data-docx-page-window-spacer": "before",
41153
+ style: {
41154
+ height: pageStackVirtualSpacers.before.heightPx,
41155
+ width: pageStackVirtualSpacers.before.widthPx,
41156
+ margin: "0 auto",
41157
+ pointerEvents: "none",
41158
+ visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
41159
+ }
41160
+ }
41161
+ ) : null,
41162
+ visiblePageIndexes.map((pageIndex) => {
41163
+ const pageNodeSegments = pageNodeSegmentsByPage[pageIndex] ?? [];
40443
41164
  const pageInfo = pageSectionInfoByIndex[pageIndex];
40444
41165
  const pageLayout = pageInfo?.layout ?? documentLayout;
40445
- const pageVisible = isPageVisible(pageIndex);
40446
41166
  const pageWrapperWidthPx = showTrackedChangeGutter ? pageLayout.pageWidthPx + TRACKED_CHANGE_GUTTER_WIDTH_PX : pageLayout.pageWidthPx;
40447
- if (!pageVisible) {
40448
- const placeholderBackgroundColor = pageBackgroundColor ?? editor.model.metadata.documentBackgroundColor ?? pageSurfaceBaseStyle.backgroundColor;
40449
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
40450
- "div",
40451
- {
40452
- "data-docx-page-wrapper": "true",
40453
- "data-docx-page-index": pageIndex,
40454
- "data-index": pageIndex,
40455
- style: {
40456
- width: pageWrapperWidthPx,
40457
- margin: "0 auto",
40458
- visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
40459
- },
40460
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
40461
- "div",
40462
- {
40463
- "data-docx-page-placeholder": "true",
40464
- ref: pagePlaceholderRefForIndex(pageIndex),
40465
- style: {
40466
- ...pageSurfaceBaseStyle,
40467
- ...pageMarginPaddingStyle(pageLayout.marginsPx),
40468
- height: pageLayout.pageHeightPx,
40469
- minHeight: pageLayout.pageHeightPx,
40470
- width: pageLayout.pageWidthPx,
40471
- backgroundColor: placeholderBackgroundColor,
40472
- pointerEvents: "none"
40473
- }
40474
- }
40475
- )
40476
- },
40477
- `page-${pageIndex}`
40478
- );
40479
- }
40480
41167
  const pageContentWidthPx = Math.max(
40481
41168
  120,
40482
41169
  pageLayout.pageWidthPx - pageLayout.marginsPx.left - pageLayout.marginsPx.right
@@ -40648,6 +41335,10 @@ ${currentText.slice(end)}`;
40648
41335
  width: pageWrapperWidthPx,
40649
41336
  minHeight: pageLayout.pageHeightPx,
40650
41337
  margin: "0 auto",
41338
+ // Isolate per-page layout/style recalculation so scrolling and
41339
+ // edits on one page don't force whole-document layout passes.
41340
+ // (No paint containment: floats and gutter cards may overhang.)
41341
+ contain: "layout style",
40651
41342
  visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
40652
41343
  },
40653
41344
  children: [
@@ -40898,9 +41589,6 @@ ${currentText.slice(end)}`;
40898
41589
  segments: [segment]
40899
41590
  });
40900
41591
  });
40901
- if (typeof window !== "undefined" && window.__docxDebugGroups) {
40902
- console.log("[groups]", pageIndex, JSON.stringify(sectionGroups.map((g) => ({ s: g.sectionIndex, n: g.segments.map((x) => x.nodeIndex) }))));
40903
- }
40904
41592
  return sectionGroups.map((group, groupIndex) => {
40905
41593
  const sectionColumns = sectionColumnsBySectionIndex[group.sectionIndex];
40906
41594
  const isLastGroupOnPage = groupIndex === sectionGroups.length - 1;
@@ -41725,10 +42413,10 @@ ${currentText.slice(end)}`;
41725
42413
  overflow: "visible"
41726
42414
  },
41727
42415
  children: pageTrackedChanges.map((entry) => {
41728
- const accentColor = trackedChangeAccentColor(
41729
- entry.change.kind,
42416
+ const accentColor = entry.annotation.trackedChange ? trackedChangeAccentColor(
42417
+ entry.annotation.trackedChange.kind,
41730
42418
  editor.documentTheme
41731
- );
42419
+ ) : commentAccentColor(editor.documentTheme);
41732
42420
  const cardCenterY = clampNumber(
41733
42421
  Math.round(entry.top + entry.heightPx / 2),
41734
42422
  8,
@@ -41789,12 +42477,12 @@ ${currentText.slice(end)}`;
41789
42477
  )
41790
42478
  ]
41791
42479
  },
41792
- `tracked-connector-${pageIndex}-${entry.change.id}`
42480
+ `tracked-connector-${pageIndex}-${entry.annotation.id}`
41793
42481
  );
41794
42482
  })
41795
42483
  }
41796
42484
  ),
41797
- !hasTrackedChanges && pageIndex === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
42485
+ (!trackedChangesEnabled || !hasTrackedChanges) && (!commentsEnabled || !hasComments) && pageIndex === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41798
42486
  "p",
41799
42487
  {
41800
42488
  style: {
@@ -41807,19 +42495,21 @@ ${currentText.slice(end)}`;
41807
42495
  lineHeight: 1.35,
41808
42496
  color: "#94a3b8"
41809
42497
  },
41810
- children: "No edits found"
42498
+ children: trackedChangesEnabled && commentsEnabled ? "No edits or comments found" : commentsEnabled ? "No comments found" : "No edits found"
41811
42499
  }
41812
42500
  ) : null,
41813
42501
  pageTrackedChanges.map((entry) => {
41814
- const accentColor = trackedChangeAccentColor(
41815
- entry.change.kind,
42502
+ const trackedChange = entry.annotation.trackedChange;
42503
+ const comment = entry.annotation.comment;
42504
+ const accentColor = trackedChange ? trackedChangeAccentColor(
42505
+ trackedChange.kind,
41816
42506
  editor.documentTheme
41817
- );
42507
+ ) : commentAccentColor(editor.documentTheme);
41818
42508
  const formattedDate = formatTrackedChangeDate(
41819
- entry.change.date
42509
+ trackedChange?.date ?? comment?.date
41820
42510
  );
41821
- const kindLabel = trackedChangeKindLabel(entry.change.kind);
41822
- const snippet = normalizeTrackedChangeSnippet(entry.change.text) ?? (entry.change.kind === "format-change" || entry.change.kind === "paragraph-format-change" ? "Formatting" : "Change");
42511
+ const kindLabel = trackedChange ? trackedChangeKindLabel(trackedChange.kind) : comment?.resolved ? "Comment \xB7 Resolved" : comment?.parentId !== void 0 ? "Reply" : "Comment";
42512
+ const snippet = trackedChange ? normalizeTrackedChangeSnippet(trackedChange.text) ?? (trackedChange.kind === "format-change" || trackedChange.kind === "paragraph-format-change" ? "Formatting" : "Change") : comment?.text || "Comment";
41823
42513
  const cardWidthPx = Math.max(
41824
42514
  140,
41825
42515
  TRACKED_CHANGE_GUTTER_WIDTH_PX - TRACKED_CHANGE_GUTTER_CARD_LEFT_PX - TRACKED_CHANGE_GUTTER_CARD_RIGHT_PX
@@ -41871,7 +42561,7 @@ ${currentText.slice(end)}`;
41871
42561
  fontWeight: 700,
41872
42562
  lineHeight: 1.25
41873
42563
  },
41874
- children: entry.change.author?.trim() || "Unknown author"
42564
+ children: (trackedChange?.author ?? comment?.author)?.trim() || "Unknown author"
41875
42565
  }
41876
42566
  ),
41877
42567
  formattedDate ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -41890,6 +42580,23 @@ ${currentText.slice(end)}`;
41890
42580
  ]
41891
42581
  }
41892
42582
  ),
42583
+ comment?.anchorText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
42584
+ "p",
42585
+ {
42586
+ style: {
42587
+ margin: "2px 0 0",
42588
+ fontSize: 11,
42589
+ lineHeight: 1.3,
42590
+ fontStyle: "italic",
42591
+ color: editor.documentTheme === "dark" ? "#94a3b8" : "#6b7280"
42592
+ },
42593
+ children: [
42594
+ "\u201C",
42595
+ comment.anchorText,
42596
+ "\u201D"
42597
+ ]
42598
+ }
42599
+ ) : null,
41893
42600
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
41894
42601
  "p",
41895
42602
  {
@@ -41911,8 +42618,8 @@ ${currentText.slice(end)}`;
41911
42618
  ]
41912
42619
  }
41913
42620
  );
41914
- const renderedCard = renderTrackedChangeCard ? renderTrackedChangeCard({
41915
- change: entry.change,
42621
+ const renderedCard = trackedChange ? renderTrackedChangeCard ? renderTrackedChangeCard({
42622
+ change: trackedChange,
41916
42623
  kindLabel,
41917
42624
  snippet,
41918
42625
  formattedDate,
@@ -41920,12 +42627,21 @@ ${currentText.slice(end)}`;
41920
42627
  documentTheme: editor.documentTheme,
41921
42628
  pageIndex,
41922
42629
  style: cardStyle
42630
+ }) : defaultCard : comment && renderCommentCard ? renderCommentCard({
42631
+ comment,
42632
+ snippet,
42633
+ formattedDate,
42634
+ accentColor,
42635
+ documentTheme: editor.documentTheme,
42636
+ pageIndex,
42637
+ style: cardStyle
41923
42638
  }) : defaultCard;
41924
42639
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41925
42640
  "div",
41926
42641
  {
42642
+ "data-docx-gutter-annotation": trackedChange ? "tracked-change" : "comment",
41927
42643
  ref: (element) => {
41928
- const elementKey = `${pageIndex}:${entry.change.id}`;
42644
+ const elementKey = `${pageIndex}:${entry.annotation.id}`;
41929
42645
  if (element) {
41930
42646
  trackedChangeCardElementsRef.current.set(
41931
42647
  elementKey,
@@ -41940,7 +42656,7 @@ ${currentText.slice(end)}`;
41940
42656
  style: cardContainerStyle,
41941
42657
  children: renderedCard
41942
42658
  },
41943
- `tracked-card-${pageIndex}-${entry.change.id}`
42659
+ `tracked-card-${pageIndex}-${entry.annotation.id}`
41944
42660
  );
41945
42661
  })
41946
42662
  ]
@@ -41951,6 +42667,20 @@ ${currentText.slice(end)}`;
41951
42667
  `page-${pageIndex}`
41952
42668
  );
41953
42669
  }),
42670
+ pageStackVirtualSpacers.after.heightPx > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
42671
+ "div",
42672
+ {
42673
+ "aria-hidden": "true",
42674
+ "data-docx-page-window-spacer": "after",
42675
+ style: {
42676
+ height: pageStackVirtualSpacers.after.heightPx,
42677
+ width: pageStackVirtualSpacers.after.widthPx,
42678
+ margin: "0 auto",
42679
+ pointerEvents: "none",
42680
+ visibility: hideDocumentUntilPaginationSettled ? "hidden" : void 0
42681
+ }
42682
+ }
42683
+ ) : null,
41954
42684
  !isReadOnly ? (() => {
41955
42685
  const hasCustomContextMenuState = Boolean(contextMenuState);
41956
42686
  const hasTableContextMenuState = Boolean(tableContextMenuState);
@@ -42307,6 +43037,7 @@ ${currentText.slice(end)}`;
42307
43037
 
42308
43038
  // src/index.tsx
42309
43039
  init_src2();
43040
+ init_src3();
42310
43041
 
42311
43042
  // ../layout-core/src/index.ts
42312
43043
  init_cjs_shims();
@@ -43854,16 +44585,20 @@ function useDocxModel(file) {
43854
44585
  }
43855
44586
  const docxFile = file;
43856
44587
  let isCurrent = true;
44588
+ const abortController = new AbortController();
43857
44589
  async function load() {
43858
44590
  setState({ isLoading: true });
43859
44591
  try {
43860
- const pkg = await parseDocx(docxFile);
44592
+ const { model } = await importDocxBuffer(docxFile, {
44593
+ signal: abortController.signal,
44594
+ transferBuffer: false
44595
+ });
43861
44596
  if (!isCurrent) {
43862
44597
  return;
43863
44598
  }
43864
44599
  setState({
43865
44600
  isLoading: false,
43866
- model: await buildDocModel(pkg)
44601
+ model
43867
44602
  });
43868
44603
  } catch (error) {
43869
44604
  if (!isCurrent) {
@@ -43878,6 +44613,7 @@ function useDocxModel(file) {
43878
44613
  void load();
43879
44614
  return () => {
43880
44615
  isCurrent = false;
44616
+ abortController.abort();
43881
44617
  };
43882
44618
  }, [file]);
43883
44619
  return state;
@@ -44218,6 +44954,7 @@ function ReactDocxViewer({
44218
44954
  updateTableCellParagraphTextRecursive,
44219
44955
  updateTableCellText,
44220
44956
  useDocxBorders,
44957
+ useDocxComments,
44221
44958
  useDocxDocumentTheme,
44222
44959
  useDocxEditor,
44223
44960
  useDocxFormFields,