@a3s-lab/office 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +99 -6
  2. package/dist/0~1403.js +20 -12
  3. package/dist/0~2805.js +241 -241
  4. package/dist/0~4980.js +1 -1
  5. package/dist/0~5050.js +1 -20
  6. package/dist/0~5093.js +547 -547
  7. package/dist/0~7048.js +31 -29
  8. package/dist/0~document-editor.js +694 -90
  9. package/dist/0~pdf-viewer.js +41 -10
  10. package/dist/0~presentation-editor.js +8 -6
  11. package/dist/0~spreadsheet-editor.js +11528 -10094
  12. package/dist/0~work-document-import-worker-client.js +237 -0
  13. package/dist/0~work-docx-export.js +1 -1
  14. package/dist/0~work-docx-import.js +1 -1
  15. package/dist/0~work-docx-large-document-import.js +559 -0
  16. package/dist/0~work-office-diagnostics.js +46 -32
  17. package/dist/4104.js +4092 -3210
  18. package/dist/432.js +51 -7
  19. package/dist/4476.js +201 -7
  20. package/dist/5184.js +24 -2
  21. package/dist/{8928.js → 6282.js} +2338 -93
  22. package/dist/8715.js +895 -888
  23. package/dist/9356.js +3 -1
  24. package/dist/core.js +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/internal/features/work/editors/document-editor-support.d.ts +1 -9
  27. package/dist/internal/features/work/editors/document-external-content.d.ts +1 -1
  28. package/dist/internal/features/work/editors/presentation-slide-canvas.d.ts +3 -1
  29. package/dist/internal/features/work/editors/presentation-slide-thumbnail.d.ts +3 -2
  30. package/dist/internal/features/work/editors/presentation-thumbnail-rail.d.ts +2 -1
  31. package/dist/internal/features/work/editors/presentation-workspace.d.ts +2 -1
  32. package/dist/internal/features/work/editors/spreadsheet-border-ribbon.d.ts +5 -0
  33. package/dist/internal/features/work/editors/spreadsheet-calculation-projection.d.ts +10 -0
  34. package/dist/internal/features/work/editors/spreadsheet-cell-border-command.d.ts +3 -0
  35. package/dist/internal/features/work/editors/spreadsheet-cell-border.d.ts +14 -0
  36. package/dist/internal/features/work/editors/spreadsheet-cell-fill-command.d.ts +3 -0
  37. package/dist/internal/features/work/editors/spreadsheet-cell-fill.d.ts +12 -0
  38. package/dist/internal/features/work/editors/spreadsheet-cell-range.d.ts +14 -0
  39. package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +159 -0
  40. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +8 -4
  41. package/dist/internal/features/work/editors/spreadsheet-editor-support.d.ts +8 -2
  42. package/dist/internal/features/work/editors/spreadsheet-home-format-ribbon.d.ts +10 -0
  43. package/dist/internal/features/work/editors/spreadsheet-in-place-workbook-sync.d.ts +10 -0
  44. package/dist/internal/features/work/editors/spreadsheet-operation-projection.d.ts +14 -0
  45. package/dist/internal/features/work/editors/spreadsheet-structure-selection.d.ts +7 -0
  46. package/dist/internal/features/work/editors/use-document-pagination.d.ts +5 -0
  47. package/dist/internal/features/work/editors/use-presentation-design-commands.d.ts +2 -1
  48. package/dist/internal/features/work/editors/use-spreadsheet-workbook-sync.d.ts +2 -1
  49. package/dist/internal/features/work/spreadsheet-history-value.d.ts +1 -0
  50. package/dist/internal/features/work/spreadsheet-sparse.d.ts +6 -1
  51. package/dist/internal/features/work/work-document-chunk-geometry.d.ts +28 -0
  52. package/dist/internal/features/work/work-document-chunk-node.d.ts +23 -0
  53. package/dist/internal/features/work/work-document-extensions.d.ts +1 -0
  54. package/dist/internal/features/work/work-document-html-fingerprint.d.ts +15 -0
  55. package/dist/internal/features/work/work-document-import-worker-client.d.ts +13 -0
  56. package/dist/internal/features/work/work-document-import-worker-protocol.d.ts +36 -0
  57. package/dist/internal/features/work/work-document-import.worker.d.ts +1 -0
  58. package/dist/internal/features/work/work-document-incremental-layout.d.ts +1 -1
  59. package/dist/internal/features/work/work-document-integrity-index.d.ts +14 -0
  60. package/dist/internal/features/work/work-document-lazy-block.d.ts +3 -0
  61. package/dist/internal/features/work/work-document-lazy-html.d.ts +21 -0
  62. package/dist/internal/features/work/work-document-lazy-model.d.ts +29 -0
  63. package/dist/internal/features/work/work-document-lazy-pagination-measurement.d.ts +3 -0
  64. package/dist/internal/features/work/work-document-lazy-preview.d.ts +21 -0
  65. package/dist/internal/features/work/work-document-lazy-update.d.ts +14 -0
  66. package/dist/internal/features/work/work-document-model.d.ts +18 -2
  67. package/dist/internal/features/work/work-document-page-surface-registry.d.ts +16 -0
  68. package/dist/internal/features/work/work-document-pagination-dom.d.ts +1 -0
  69. package/dist/internal/features/work/work-document-pagination-types.d.ts +1 -0
  70. package/dist/internal/features/work/work-document-pagination.d.ts +1 -1
  71. package/dist/internal/features/work/work-document-text-statistics.d.ts +25 -0
  72. package/dist/internal/features/work/work-document-windowing.d.ts +23 -0
  73. package/dist/internal/features/work/work-docx-large-document-import.d.ts +35 -0
  74. package/dist/internal/features/work/work-docx-large-document-parser.d.ts +29 -0
  75. package/dist/internal/features/work/work-file-import.d.ts +5 -0
  76. package/dist/internal/features/work/work-file-io.d.ts +3 -3
  77. package/dist/internal/features/work/work-file-kind.d.ts +5 -0
  78. package/dist/internal/features/work/work-office-diagnostics.d.ts +10 -1
  79. package/dist/internal/features/work/work-ooxml-package.d.ts +8 -0
  80. package/dist/internal/features/work/work-presentation-layouts.d.ts +7 -1
  81. package/dist/internal/features/work/work-repository.d.ts +1 -0
  82. package/dist/internal/features/work/work-spreadsheet-compatibility-summary.d.ts +10 -0
  83. package/dist/internal/features/work/work-spreadsheet-file-export.d.ts +2 -0
  84. package/dist/internal/features/work/work-spreadsheet-file-import.d.ts +3 -0
  85. package/dist/internal/features/work/work-spreadsheet-import-diagnostics.d.ts +2 -0
  86. package/dist/internal/features/work/work-spreadsheet-import-worker-client.d.ts +6 -0
  87. package/dist/internal/features/work/work-spreadsheet-import-worker-protocol.d.ts +32 -0
  88. package/dist/internal/features/work/work-spreadsheet-import.worker.d.ts +1 -0
  89. package/dist/internal/features/work/work-spreadsheet-matrix-profile.d.ts +64 -0
  90. package/dist/internal/features/work/work-spreadsheet-package-scan-worker-client.d.ts +6 -0
  91. package/dist/internal/features/work/work-spreadsheet-package-scan-worker-protocol.d.ts +49 -0
  92. package/dist/internal/features/work/work-spreadsheet-package-scan.worker.d.ts +1 -0
  93. package/dist/internal/features/work/work-xlsx-formula-diagnostics.d.ts +3 -1
  94. package/dist/internal/features/work/work-xlsx-formulas.d.ts +2 -1
  95. package/dist/internal/features/work/work-xlsx-interop.d.ts +6 -5
  96. package/dist/internal/features/work/work-xlsx-pivot-diagnostics.d.ts +2 -1
  97. package/dist/internal/features/work/work-xlsx-plain-fast-path.d.ts +54 -0
  98. package/dist/internal/features/work/work-xlsx-style-gate.d.ts +1 -0
  99. package/dist/internal/features/work/work-xlsx-worksheet-scan.d.ts +12 -0
  100. package/dist/internal/features/work/work-xlsx-worksheet.d.ts +12 -0
  101. package/dist/office-kernel.wasm +0 -0
  102. package/dist/office-kernel.worker.js +31 -29
  103. package/dist/react.d.ts +7 -1
  104. package/dist/styles.css +440 -3
  105. package/dist/work-document-import.worker.js +558 -0
  106. package/dist/work-spreadsheet-import.worker.js +24745 -0
  107. package/dist/work-spreadsheet-import.worker.js.LICENSE.txt +3 -0
  108. package/dist/work-spreadsheet-package-scan.worker.js +4157 -0
  109. package/dist/work-spreadsheet-package-scan.worker.js.LICENSE.txt +11 -0
  110. package/docs/latest/en/browser-editor-architecture.md +351 -15
  111. package/package.json +19 -1
@@ -16,15 +16,15 @@ import extension_underline from "@tiptap/extension-underline";
16
16
  import starter_kit from "@tiptap/starter-kit";
17
17
  import { BubbleMenu } from "@tiptap/react/menus";
18
18
  import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
19
+ import { documentTableSizing, transferChangedDocumentTextStatistics, documentPageBordersVisible, DOCUMENT_PAGE_BORDER_EDGES, documentTableRowOptions, normalizeDocumentColumns, clampDocumentMargin, materializeLazyDocumentEditorRoot, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, documentCitationCount, nextDocumentTabAlignment, normalizedTabPosition, isDocumentParagraphArtBorderStyle, resolveDocumentPageBorders, documentLazyHtmlChunkFragment, DOCUMENT_CHUNK_VISIBLE_IDS_META, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, retainAnchoredDocumentComments, DocumentTableRowIdentity, work_document_page_margins_twipsToMillimeters, DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, resolveWorkDocumentEditorInput, collectDocumentTextLayoutParagraphs, documentBulletListStyle, readOfficeDocumentCollaboration as readWorkOfficeDocumentCollaboration, documentOrderedListState, normalizeDocumentPageChrome, documentTextStatistics, documentPageMarginsForLayout, invalidateDocumentLazyHtmlProjection, documentTableCellFormat, normalizeDocumentPageGeometry, normalizeDocumentImageLayer, documentImageProperties, isValidDocumentCitationTag, sanitizeDocumentPageChromeHtml, pageTwipsToMillimeters, normalizeDocumentPageBorders, activeDocumentSection, DocumentParagraphFormatting, normalizeDocumentHtml, documentInitialSectionLayout, documentModelHasTrustedInitialIntegrityFeatures, documentModelUsesWindowing, documentParagraphDirection, documentParagraphPagination, documentPageChromeLegacyFields, documentChunkMountedIds, collectDocumentCommentAnchors, canChangeDocumentIndent, DocumentSuperscript, documentSectionById, activeDocumentBookmark, DocumentEquation, documentLazyHtmlProjectionFingerprint, documentLazyHtmlProjection, normalizeDocumentParagraphIndent, updateDocumentGutterPosition, mountWorkLiveDocumentCapture, registerDocumentPageSurfaceGeometry, syncDocumentContentFromHtml, editorDocumentCaptionTargets, resolveDocumentPageChrome, documentImageLayoutOptions, MAX_DOCUMENT_NUMBERING_START, resolveDocumentPageSize, editorDocumentBookmarkReferenceTargets, serializeWorkDocumentNode, DOCUMENT_CHUNK_PAGINATION_META, createOfficeDocumentCollaborationBinding as createWorkOfficeDocumentCollaborationBinding, documentModelForContent, selectedDocumentChunkId, documentCommentViews, documentParagraphSpacing, normalizeDocumentTabStops, patchDocumentLazyHtmlProjection, documentBookmarkNameExists, collectDocumentChanges, DocumentImage, resolveDocumentPageMargins, updateDocumentPageMarginMode, canSetDocumentTableRowRepeatHeader, millimetersToPixels as work_document_layout_millimetersToPixels, DOCUMENT_CHUNK_HYDRATION_META, documentTabLeaderLabel, createSchemaDerivedWorkDocumentModel, updateDocumentCustomPageMillimeters, documentCommentDraftRange, documentParagraphTabStops, documentTableHorizontalAlignment, documentParagraphIndent, canInsertDocumentComment, documentTextLayoutBatches, normalizeDocumentImageWrapSide, updateDocumentPageOrientation, documentCitationStyleDetails, validateDocumentBookmarkName, setCustomDocumentColumns, updateDocumentPageMarginMillimeters, documentCitationStyle, documentTransactionsOnlyHydrateChunks, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DOCUMENT_TABLE_STYLE_OPTIONS, updateDocumentColumnWidth, updateDocumentPaperSizePreset, documentPageMetrics, createDocumentBibliography, DocumentSubscript, DocumentParagraphIdentity, updateDocumentPageChromeVariant, updateDocumentMirrorMargins, activeDocumentTableStyle, measureDocumentLayoutBlocksIncrementally, createWorkDocumentExtensions } from "./6282.js";
19
20
  import { useOfficeTaskPaneEscape, normalizeOfficeFontFamily, OfficeCheckbox, useOfficeDialog, useOfficeTaskPaneModal, CommittedOfficeNumberField, officeFontFamilyLabel, officeFontFamilies, CollectionState, createOfficeKernelClient, OfficeNumberField } from "./0~7048.js";
20
21
  import { office_text_field_OfficeTextArea, Popover, officeOverlayPortalRoot, button_Button, useOfficePublishPresenceLocation, OfficeTiptapPresenceLayer, icon_button_IconButton, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom, office_text_field_OfficeFileInput } from "./0~6090.js";
21
22
  import { WorkOfficePreviewBar, isWorkspaceContextMenuKeyboardEvent, Tabs, WorkOfficeZoomControls, WorkOfficeStatusBar, Dialog, WorkOfficeRibbon, workspaceContextMenuPosition, OfficeSelect, WorkspaceContextMenu, WorkOfficeRibbonGroup, WorkOfficeRibbonButton } from "./0~4595.js";
22
- import { documentTableSizing, documentTableRowOptions, documentCommentViews, documentParagraphSpacing, documentPageBordersVisible, DOCUMENT_PAGE_BORDER_EDGES, normalizeDocumentColumns, clampDocumentMargin, normalizeDocumentTabStops, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, createWorkDocumentModel, nextDocumentTabAlignment, documentBookmarkNameExists, normalizedTabPosition, DocumentImage, collectDocumentChanges, documentCitationCount, isDocumentParagraphArtBorderStyle, resolveDocumentPageMargins, updateDocumentPageMarginMode, resolveDocumentPageBorders, canSetDocumentTableRowRepeatHeader, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, retainAnchoredDocumentComments, DocumentTableRowIdentity, work_document_page_margins_twipsToMillimeters, DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, resolveWorkDocumentEditorInput, collectDocumentTextLayoutParagraphs, millimetersToPixels as work_document_layout_millimetersToPixels, documentBulletListStyle, readOfficeDocumentCollaboration as readWorkOfficeDocumentCollaboration, documentTabLeaderLabel, documentOrderedListState, normalizeDocumentPageChrome, documentPageMarginsForLayout, documentTableCellFormat, updateDocumentCustomPageMillimeters, documentCommentDraftRange, normalizeDocumentPageGeometry, documentParagraphTabStops, normalizeDocumentImageLayer, documentImageProperties, documentParagraphIndent, documentTableHorizontalAlignment, isValidDocumentCitationTag, canInsertDocumentComment, sanitizeDocumentPageChromeHtml, pageTwipsToMillimeters, normalizeDocumentPageBorders, DocumentParagraphFormatting, activeDocumentSection, documentTextLayoutBatches, normalizeDocumentImageWrapSide, normalizeDocumentHtml, documentParagraphDirection, documentParagraphPagination, updateDocumentPageOrientation, documentCitationStyleDetails, documentInitialSectionLayout, documentPageChromeLegacyFields, setCustomDocumentColumns, collectDocumentCommentAnchors, documentCitationStyle, updateDocumentPageMarginMillimeters, canChangeDocumentIndent, validateDocumentBookmarkName, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DocumentSuperscript, documentSectionById, DOCUMENT_TABLE_STYLE_OPTIONS, updateDocumentColumnWidth, updateDocumentPaperSizePreset, DocumentEquation, documentPageMetrics, normalizeDocumentParagraphIndent, updateDocumentGutterPosition, mountWorkLiveDocumentCapture, activeDocumentBookmark, createDocumentBibliography, DocumentSubscript, DocumentParagraphIdentity, syncDocumentContentFromHtml, updateDocumentPageChromeVariant, editorDocumentCaptionTargets, resolveDocumentPageChrome, updateDocumentMirrorMargins, documentImageLayoutOptions, MAX_DOCUMENT_NUMBERING_START, resolveDocumentPageSize, activeDocumentTableStyle, editorDocumentBookmarkReferenceTargets, createOfficeDocumentCollaborationBinding as createWorkOfficeDocumentCollaborationBinding, measureDocumentLayoutBlocksIncrementally, createWorkDocumentExtensions } from "./8928.js";
23
23
  import { createOfficeId as createWorkId } from "./5184.js";
24
24
  import { normalizeDocumentHref, DOCUMENT_LINK_VALIDATION_MESSAGE } from "./0~work-document-links.js";
25
25
  import { OfficeColorPicker, isOfficeShortcutBlocked } from "./0~3635.js";
26
26
  import { OfficeTableInsertPopover, readOfficeFileAsDataUrl } from "./0~9445.js";
27
- import { mergeOfficeTiptapExtensions, documentTextStatistics, documentCurrentPage, documentPageCount, documentAgentMenuItems, createWorkDocumentSelectionSnapshot, documentPlainTextAsHtml, createWorkDocumentSelectionAction, documentCustomSelectionMenuItems } from "./0~5050.js";
27
+ import { mergeOfficeTiptapExtensions, documentCurrentPage, documentPageCount, documentAgentMenuItems, createWorkDocumentSelectionSnapshot, documentPlainTextAsHtml, documentCustomSelectionMenuItems, createWorkDocumentSelectionAction } from "./0~5050.js";
28
28
  import { WorkEditorLoadingState, documentLayoutFontKey, useOfficeCollaborationLocationNavigator, OFFICE_DOCUMENT_LAYOUT_HEBREW_FONT_ID, useOfficeEditorInitialFocus, OFFICE_DOCUMENT_LAYOUT_FONT_ID, OFFICE_DOCUMENT_LAYOUT_ARABIC_FONT_ID, OFFICE_DOCUMENT_LAYOUT_LATIN_FONT_ID } from "./432.js";
29
29
  import { useOfficeDraft, InlineNotice } from "./0~345.js";
30
30
  import { documentPageColor, normalizeDocumentPageColor } from "./0~work-document-page-color.js";
@@ -33,6 +33,128 @@ __webpack_require__.r(document_editor_namespaceObject);
33
33
  __webpack_require__.d(document_editor_namespaceObject, {
34
34
  DocumentEditor: ()=>DocumentEditor
35
35
  });
36
+ function materializeLazyDocumentUpdate(previousDocument, nextDocument, compactRoot, model) {
37
+ const root = materializeLazyDocumentEditorRoot(compactRoot, model);
38
+ const projection = documentLazyHtmlProjection(model);
39
+ const changed = changedLazyDocumentChunks(previousDocument, nextDocument);
40
+ if (!projection || !changed?.length || changed.some(({ after, before })=>!documentChunkOnlyChangesText(before, after))) {
41
+ invalidateDocumentLazyHtmlProjection(model);
42
+ return {
43
+ html: null,
44
+ htmlFingerprint: null,
45
+ root
46
+ };
47
+ }
48
+ try {
49
+ const replacements = new Map();
50
+ for (const { id } of changed){
51
+ const range = projection.ranges.get(id);
52
+ const isolated = isolatedDocumentChunk(root, id);
53
+ if (!range || !isolated) throw new Error('Lazy chunk is not indexed.');
54
+ const serialized = serializeWorkDocumentNode(isolated);
55
+ const sectionOpen = serialized.indexOf('>') + 1;
56
+ const sectionClose = serialized.lastIndexOf('</section>');
57
+ if (sectionOpen <= 0 || sectionClose < sectionOpen) throw new Error('Lazy chunk serialization has no section boundary.');
58
+ const fragment = documentLazyHtmlChunkFragment(serialized.slice(sectionOpen, sectionClose), range.tablePart);
59
+ if (null === fragment) throw new Error('Lazy table chunk serialization is malformed.');
60
+ replacements.set(id, fragment);
61
+ }
62
+ const html = patchDocumentLazyHtmlProjection(projection, replacements);
63
+ if (null === html) throw new Error('Lazy HTML patch could not be applied.');
64
+ const htmlFingerprint = documentLazyHtmlProjectionFingerprint(projection);
65
+ if (!htmlFingerprint) throw new Error('Lazy HTML fingerprint could not be updated.');
66
+ return {
67
+ html,
68
+ htmlFingerprint,
69
+ root
70
+ };
71
+ } catch {
72
+ invalidateDocumentLazyHtmlProjection(model);
73
+ return {
74
+ html: null,
75
+ htmlFingerprint: null,
76
+ root
77
+ };
78
+ }
79
+ }
80
+ function transferLazyDocumentTextStatistics(previousDocument, nextDocument) {
81
+ const changed = changedLazyDocumentChunks(previousDocument, nextDocument);
82
+ if (!changed?.length || changed.some(({ after, before })=>!documentChunkOnlyChangesText(before, after))) return false;
83
+ return transferChangedDocumentTextStatistics(previousDocument, nextDocument, changed);
84
+ }
85
+ function changedLazyDocumentChunks(before, after) {
86
+ const changed = [];
87
+ const visit = (previous, next)=>{
88
+ if (previous === next || previous.eq(next)) return true;
89
+ if (previous.type !== next.type) return false;
90
+ if ('documentChunk' === previous.type.name && true !== previous.attrs.windowContainer && true !== next.attrs.windowContainer) {
91
+ const previousId = documentChunkId(previous);
92
+ const nextId = documentChunkId(next);
93
+ if (!previousId || previousId !== nextId) return false;
94
+ changed.push({
95
+ after: next,
96
+ before: previous,
97
+ id: nextId
98
+ });
99
+ return true;
100
+ }
101
+ if (!previous.sameMarkup(next) || previous.childCount !== next.childCount) return false;
102
+ for(let index = 0; index < previous.childCount; index += 1){
103
+ const previousChild = previous.child(index);
104
+ const nextChild = next.child(index);
105
+ if (!visit(previousChild, nextChild)) return false;
106
+ }
107
+ return true;
108
+ };
109
+ return visit(before, after) ? changed : null;
110
+ }
111
+ function documentChunkOnlyChangesText(before, after) {
112
+ let textChanged = false;
113
+ const visit = (previous, next)=>{
114
+ if (previous.type !== next.type || !previous.sameMarkup(next) || previous.childCount !== next.childCount) return false;
115
+ if (previous.isText || next.isText) {
116
+ if (!previous.isText || !next.isText) return false;
117
+ if (previous.text !== next.text) textChanged = true;
118
+ return true;
119
+ }
120
+ for(let index = 0; index < previous.childCount; index += 1)if (!visit(previous.child(index), next.child(index))) return false;
121
+ return true;
122
+ };
123
+ return visit(before, after) && textChanged;
124
+ }
125
+ function isolatedDocumentChunk(root, id) {
126
+ let section = null;
127
+ let chunk = null;
128
+ const visit = (node, activeSection)=>{
129
+ if (chunk) return;
130
+ const nextSection = 'documentSection' === node.type ? node : activeSection;
131
+ if ('documentChunk' === node.type && node.attrs?.windowContainer !== true && node.attrs?.id === id) {
132
+ section = nextSection;
133
+ chunk = node;
134
+ return;
135
+ }
136
+ for (const child of node.content ?? [])visit(child, nextSection);
137
+ };
138
+ visit(root, null);
139
+ const foundSection = section;
140
+ const foundChunk = chunk;
141
+ if (!foundSection || !foundChunk) return null;
142
+ return {
143
+ type: 'doc',
144
+ content: [
145
+ {
146
+ ...foundSection,
147
+ content: [
148
+ foundChunk
149
+ ]
150
+ }
151
+ ]
152
+ };
153
+ }
154
+ function documentChunkId(node) {
155
+ const id = node.attrs.id;
156
+ return 'string' == typeof id && id ? id : null;
157
+ }
36
158
  function documentPageSurfaceGeometry(pages, fallback, requestedPageCount = pages.length) {
37
159
  const pageCount = Math.max(1, Math.trunc(requestedPageCount));
38
160
  const metrics = Array.from({
@@ -217,10 +339,14 @@ const DocumentPagination = Extension.create({
217
339
  name: 'documentPagination',
218
340
  addCommands () {
219
341
  return {
220
- applyDocumentPagination: (revision, breaks)=>({ tr })=>{
342
+ applyDocumentPagination: (revision, breaks)=>({ state, tr })=>{
221
343
  tr.setMeta(documentPaginationPluginKey, {
222
344
  kind: 'apply',
223
345
  revision,
346
+ breaks,
347
+ visibleIds: documentChunkMountedIds(state) ?? []
348
+ });
349
+ tr.setMeta(DOCUMENT_CHUNK_PAGINATION_META, {
224
350
  breaks
225
351
  });
226
352
  tr.setMeta('addToHistory', false);
@@ -228,11 +354,14 @@ const DocumentPagination = Extension.create({
228
354
  },
229
355
  clearDocumentPagination: (revision)=>({ state, tr })=>{
230
356
  const current = documentPaginationState(state);
231
- if (!current.decorations.find().length && current.revision === revision) return false;
357
+ if (!current.breaks.length && current.revision === revision) return false;
232
358
  tr.setMeta(documentPaginationPluginKey, {
233
359
  kind: 'clear',
234
360
  revision
235
361
  });
362
+ tr.setMeta(DOCUMENT_CHUNK_PAGINATION_META, {
363
+ breaks: []
364
+ });
236
365
  tr.setMeta('addToHistory', false);
237
366
  return true;
238
367
  }
@@ -244,34 +373,54 @@ const DocumentPagination = Extension.create({
244
373
  key: documentPaginationPluginKey,
245
374
  state: {
246
375
  init: ()=>({
376
+ breakIndex: emptyDocumentPaginationBreakIndex(),
377
+ breaks: [],
247
378
  decorations: DecorationSet.empty,
248
- revision: 0
379
+ revision: 0,
380
+ visibleIds: []
249
381
  }),
250
382
  apply: (transaction, current, _previous, next)=>{
251
383
  const meta = transaction.getMeta(documentPaginationPluginKey);
384
+ const visibleMeta = transaction.getMeta(DOCUMENT_CHUNK_VISIBLE_IDS_META);
385
+ const hydrationMeta = transaction.getMeta(DOCUMENT_CHUNK_HYDRATION_META);
252
386
  if (meta?.kind === 'clear') return {
387
+ breakIndex: emptyDocumentPaginationBreakIndex(),
388
+ breaks: [],
253
389
  decorations: DecorationSet.empty,
254
- revision: meta.revision
255
- };
256
- if (meta?.kind === 'apply') return {
257
- decorations: DecorationSet.create(next.doc, (meta.breaks ?? []).flatMap(pageBreakDecorations)),
258
- revision: meta.revision
390
+ revision: meta.revision,
391
+ visibleIds: documentChunkMountedIds(next) ?? []
259
392
  };
393
+ if (meta?.kind === 'apply') return createDocumentPaginationPluginState(next, meta.breaks ?? [], meta.revision, meta.visibleIds);
394
+ if (transaction.docChanged && hydrationMeta) {
395
+ const visibleIds = visibleMeta?.visibleIds ?? documentChunkMountedIds(next) ?? current.visibleIds;
396
+ return {
397
+ ...current,
398
+ decorations: documentPaginationDecorationSet(next.doc, current.breakIndex, visibleIds),
399
+ visibleIds: [
400
+ ...visibleIds
401
+ ]
402
+ };
403
+ }
260
404
  if (transaction.docChanged) {
261
405
  const appendedTo = transaction.getMeta('appendedTransaction');
262
406
  const sourceMeta = appendedTo?.getMeta(documentPaginationPluginKey);
263
- if (sourceMeta?.kind === 'apply') return {
264
- ...current,
265
- decorations: current.decorations.map(transaction.mapping, next.doc)
266
- };
407
+ if (sourceMeta?.kind === 'apply') return createDocumentPaginationPluginState(next, mapDocumentPaginationBreaks(current.breaks, transaction.mapping), current.revision);
267
408
  return {
409
+ breakIndex: emptyDocumentPaginationBreakIndex(),
410
+ breaks: [],
268
411
  decorations: DecorationSet.empty,
269
- revision: current.revision
412
+ revision: current.revision,
413
+ visibleIds: documentChunkMountedIds(next) ?? []
270
414
  };
271
415
  }
416
+ const visibleIds = visibleMeta?.visibleIds ?? (transaction.selectionSet ? withSelectedDocumentChunk(current.visibleIds, next) : current.visibleIds);
417
+ if (arraysEqual(visibleIds, current.visibleIds)) return current;
272
418
  return {
273
419
  ...current,
274
- decorations: current.decorations.map(transaction.mapping, next.doc)
420
+ decorations: documentPaginationDecorationSet(next.doc, current.breakIndex, visibleIds),
421
+ visibleIds: [
422
+ ...visibleIds
423
+ ]
275
424
  };
276
425
  }
277
426
  },
@@ -279,6 +428,21 @@ const DocumentPagination = Extension.create({
279
428
  decorations (state) {
280
429
  return documentPaginationState(state).decorations;
281
430
  }
431
+ },
432
+ view: (initialView)=>{
433
+ const publishDiagnostics = (state)=>{
434
+ const pagination = documentPaginationState(state);
435
+ initialView.dom.dataset.paginationVisualBreaks = String(pagination.breaks.length);
436
+ initialView.dom.dataset.paginationVisibleBreaks = String(visibleDocumentPaginationBreakCount(pagination.breakIndex, pagination.visibleIds));
437
+ initialView.dom.dataset.paginationVisibleDecorations = String(pagination.decorations.find().length);
438
+ initialView.dom.dataset.paginationIndexedChunks = String(pagination.breakIndex.byChunkId.size);
439
+ };
440
+ publishDiagnostics(initialView.state);
441
+ return {
442
+ update (nextView) {
443
+ publishDiagnostics(nextView.state);
444
+ }
445
+ };
282
446
  }
283
447
  })
284
448
  ];
@@ -286,10 +450,117 @@ const DocumentPagination = Extension.create({
286
450
  });
287
451
  function documentPaginationState(state) {
288
452
  return documentPaginationPluginKey.getState(state) ?? {
453
+ breakIndex: emptyDocumentPaginationBreakIndex(),
454
+ breaks: [],
289
455
  decorations: DecorationSet.empty,
290
- revision: 0
456
+ revision: 0,
457
+ visibleIds: []
458
+ };
459
+ }
460
+ function createDocumentPaginationPluginState(state, breaks, revision, requestedVisibleIds) {
461
+ const visibleIds = requestedVisibleIds ?? documentChunkMountedIds(state) ?? [];
462
+ const breakIndex = indexDocumentPaginationBreaks(state.doc, breaks);
463
+ return {
464
+ breakIndex,
465
+ breaks: [
466
+ ...breaks
467
+ ],
468
+ decorations: documentPaginationDecorationSet(state.doc, breakIndex, visibleIds),
469
+ revision,
470
+ visibleIds
291
471
  };
292
472
  }
473
+ function indexDocumentPaginationBreaks(document1, breaks) {
474
+ if (!breaks.length) return emptyDocumentPaginationBreakIndex();
475
+ const chunks = [];
476
+ document1.descendants((node, position)=>{
477
+ if ('documentChunk' !== node.type.name) return true;
478
+ if (true === node.attrs.windowContainer) return true;
479
+ chunks.push({
480
+ from: position,
481
+ id: 'string' == typeof node.attrs.id ? node.attrs.id : '',
482
+ to: position + node.nodeSize
483
+ });
484
+ return false;
485
+ });
486
+ if (!chunks.length) return {
487
+ byChunkId: new Map(),
488
+ outsideChunks: [
489
+ ...breaks
490
+ ]
491
+ };
492
+ const byChunkId = new Map();
493
+ const outsideChunks = [];
494
+ const orderedBreaks = [
495
+ ...breaks
496
+ ].sort(compareDocumentPaginationBreaks);
497
+ let chunkIndex = 0;
498
+ for (const pageBreak of orderedBreaks){
499
+ while(chunkIndex < chunks.length && pageBreak.position >= (chunks[chunkIndex]?.to ?? 1 / 0))chunkIndex += 1;
500
+ const chunk = chunks[chunkIndex];
501
+ if (chunk && pageBreak.position > chunk.from && pageBreak.position < chunk.to) {
502
+ const chunkBreaks = byChunkId.get(chunk.id) ?? [];
503
+ chunkBreaks.push(pageBreak);
504
+ byChunkId.set(chunk.id, chunkBreaks);
505
+ } else outsideChunks.push(pageBreak);
506
+ }
507
+ return {
508
+ byChunkId,
509
+ outsideChunks
510
+ };
511
+ }
512
+ function documentPaginationDecorationSet(document1, breakIndex, visibleIds) {
513
+ const visibleBreaks = [
514
+ ...breakIndex.outsideChunks
515
+ ];
516
+ for (const id of visibleIds){
517
+ const chunkBreaks = breakIndex.byChunkId.get(id);
518
+ if (chunkBreaks) visibleBreaks.push(...chunkBreaks);
519
+ }
520
+ visibleBreaks.sort(compareDocumentPaginationBreaks);
521
+ return DecorationSet.create(document1, visibleBreaks.flatMap(pageBreakDecorations));
522
+ }
523
+ function visibleDocumentPaginationBreakCount(breakIndex, visibleIds) {
524
+ let count = breakIndex.outsideChunks.length;
525
+ for (const id of visibleIds)count += breakIndex.byChunkId.get(id)?.length ?? 0;
526
+ return count;
527
+ }
528
+ function emptyDocumentPaginationBreakIndex() {
529
+ return {
530
+ byChunkId: new Map(),
531
+ outsideChunks: []
532
+ };
533
+ }
534
+ function compareDocumentPaginationBreaks(left, right) {
535
+ return left.position - right.position || left.pageIndex - right.pageIndex;
536
+ }
537
+ function mapDocumentPaginationBreaks(breaks, mapping) {
538
+ return breaks.map((pageBreak)=>({
539
+ ...pageBreak,
540
+ position: mapping.map(pageBreak.position, -1),
541
+ ...pageBreak.tableBreak?.cellBreaks ? {
542
+ tableBreak: {
543
+ ...pageBreak.tableBreak,
544
+ cellBreaks: pageBreak.tableBreak.cellBreaks.map((cellBreak)=>({
545
+ ...cellBreak,
546
+ position: mapping.map(cellBreak.position, -1)
547
+ }))
548
+ }
549
+ } : {}
550
+ }));
551
+ }
552
+ function arraysEqual(left, right) {
553
+ if (left.length !== right.length) return false;
554
+ for(let index = 0; index < left.length; index += 1)if (left[index] !== right[index]) return false;
555
+ return true;
556
+ }
557
+ function withSelectedDocumentChunk(visibleIds, state) {
558
+ const selected = selectedDocumentChunkId(state);
559
+ return selected && !visibleIds.includes(selected) ? [
560
+ ...visibleIds,
561
+ selected
562
+ ] : visibleIds;
563
+ }
293
564
  const DOCUMENT_NAVIGATION_COLLECTION_WINDOW_THRESHOLD = 48;
294
565
  const DOCUMENT_NAVIGATION_COLLECTION_WINDOW_LIMIT = 32;
295
566
  const DOCUMENT_NAVIGATION_COLLECTION_WINDOW_OVERSCAN = 4;
@@ -2753,10 +3024,28 @@ function fallbackPaginationPageDescriptor(sectionId, sectionIndex, layout, physi
2753
3024
  page: documentPageMetrics(layout)
2754
3025
  };
2755
3026
  }
2756
- function shouldPublishDocumentUpdate(transaction) {
2757
- return !transaction.getMeta('preventUpdate') && false !== transaction.getMeta('addToHistory');
3027
+ function shouldPublishDocumentUpdate(transaction, appendedTransactions = []) {
3028
+ return [
3029
+ transaction,
3030
+ ...appendedTransactions
3031
+ ].some((candidate)=>candidate.docChanged && !candidate.getMeta('preventUpdate') && false !== candidate.getMeta('addToHistory'));
2758
3032
  }
2759
3033
  function applyExternalDocumentContent(editor, content) {
3034
+ const startedAt = externalContentNow();
3035
+ const finish = (result)=>{
3036
+ const finishedAt = externalContentNow();
3037
+ editor.view.dom.dataset.documentExternalApplyMs = String(Math.round((finishedAt - startedAt) * 10) / 10);
3038
+ try {
3039
+ globalThis.performance?.measure('a3s-office.document.external-content-apply', {
3040
+ detail: {
3041
+ result
3042
+ },
3043
+ end: finishedAt,
3044
+ start: startedAt
3045
+ });
3046
+ } catch {}
3047
+ return result;
3048
+ };
2760
3049
  let nextDocument;
2761
3050
  try {
2762
3051
  nextDocument = createNodeFromContent(content, editor.schema, {
@@ -2764,12 +3053,12 @@ function applyExternalDocumentContent(editor, content) {
2764
3053
  slice: false
2765
3054
  });
2766
3055
  } catch {
2767
- return 'unsupported';
3056
+ return finish('unsupported');
2768
3057
  }
2769
- if (!(nextDocument instanceof model_Node)) return 'unsupported';
3058
+ if (!(nextDocument instanceof model_Node)) return finish('unsupported');
2770
3059
  const currentDocument = editor.state.doc;
2771
3060
  const start = currentDocument.content.findDiffStart(nextDocument.content);
2772
- if (null === start) return 'unchanged';
3061
+ if (null === start) return finish('unchanged');
2773
3062
  const end = currentDocument.content.findDiffEnd(nextDocument.content);
2774
3063
  let currentEnd = end?.a ?? currentDocument.content.size;
2775
3064
  let nextEnd = end?.b ?? nextDocument.content.size;
@@ -2781,11 +3070,14 @@ function applyExternalDocumentContent(editor, content) {
2781
3070
  try {
2782
3071
  const transaction = editor.state.tr.replace(start, currentEnd, nextDocument.slice(start, nextEnd)).setMeta('addToHistory', false).setMeta('preventUpdate', true);
2783
3072
  editor.view.dispatch(transaction);
2784
- return 'applied';
3073
+ return finish('applied');
2785
3074
  } catch {
2786
- return 'unsupported';
3075
+ return finish('unsupported');
2787
3076
  }
2788
3077
  }
3078
+ function externalContentNow() {
3079
+ return globalThis.performance?.now?.() ?? Date.now();
3080
+ }
2789
3081
  const SEARCH_CONTEXT_LENGTH = 34;
2790
3082
  function documentTextMatches(document1, rawQuery) {
2791
3083
  const query = rawQuery.toLocaleLowerCase();
@@ -5501,33 +5793,120 @@ function WorkDocumentPageBorder({ layout, physicalPage = 1, sectionPage }) {
5501
5793
  function formatPixels(value) {
5502
5794
  return Number(value.toFixed(3)).toString();
5503
5795
  }
5504
- function DocumentPageStack({ pageColor, pageCount, pageGap, pageHeight, pageWidth = 794, pages = [] }) {
5796
+ const EMPTY_DOCUMENT_PAGE_DESCRIPTORS = [];
5797
+ const document_page_stack_DOCUMENT_PAGE_WINDOW_THRESHOLD = 24;
5798
+ const DOCUMENT_PAGE_INITIAL_WINDOW_SIZE = 8;
5799
+ const document_page_stack_DOCUMENT_PAGE_WINDOW_OVERSCAN = 3;
5800
+ function DocumentPageStack({ pageColor, pageCount, pageGap, pageHeight, pageWidth = 794, pages = EMPTY_DOCUMENT_PAGE_DESCRIPTORS }) {
5505
5801
  const count = Math.max(1, Math.trunc(pageCount));
5506
5802
  const gap = Math.max(0, pageGap);
5507
5803
  const height = Math.max(1, pageHeight);
5508
- const fallbackPage = {
5509
- width: Math.max(1, pageWidth),
5804
+ const fallbackPage = useMemo(()=>({
5805
+ width: Math.max(1, pageWidth),
5806
+ height,
5807
+ marginTop: 0,
5808
+ marginRight: 0,
5809
+ marginBottom: 0,
5810
+ marginLeft: 0,
5811
+ headerHeight: 0,
5812
+ footerHeight: 0,
5813
+ pageGap: gap
5814
+ }), [
5815
+ gap,
5510
5816
  height,
5511
- marginTop: 0,
5512
- marginRight: 0,
5513
- marginBottom: 0,
5514
- marginLeft: 0,
5515
- headerHeight: 0,
5516
- footerHeight: 0,
5517
- pageGap: gap
5518
- };
5519
- const geometry = documentPageSurfaceGeometry(pages.map((page)=>page.page ?? fallbackPage), fallbackPage, count);
5520
- const descriptors = geometry.frames.map((frame)=>({
5817
+ pageWidth
5818
+ ]);
5819
+ const geometry = useMemo(()=>documentPageSurfaceGeometry(pages.map((page)=>page.page ?? fallbackPage), fallbackPage, count), [
5820
+ count,
5821
+ fallbackPage,
5822
+ pages
5823
+ ]);
5824
+ const windowed = count > document_page_stack_DOCUMENT_PAGE_WINDOW_THRESHOLD;
5825
+ const stackRef = useRef(null);
5826
+ const [requestedWindow, setRequestedWindow] = useState(()=>initialDocumentPageWindow(count));
5827
+ const pageWindow = windowed ? clampDocumentPageWindow(requestedWindow, count) : {
5828
+ start: 0,
5829
+ end: count
5830
+ };
5831
+ const descriptors = geometry.frames.slice(pageWindow.start, pageWindow.end).map((frame)=>({
5521
5832
  frame,
5522
5833
  page: pages[frame.pageIndex]
5523
5834
  }));
5835
+ useLayoutEffect(()=>{
5836
+ const stack = stackRef.current;
5837
+ if (!stack) return;
5838
+ return registerDocumentPageSurfaceGeometry(stack, ()=>{
5839
+ if (pages.length < count) return [];
5840
+ return geometry.frames.map((frame)=>{
5841
+ const descriptor = pages[frame.pageIndex];
5842
+ const pageSize = descriptor ? resolveDocumentPageSize(descriptor.layout) : null;
5843
+ return {
5844
+ height: frame.height,
5845
+ left: frame.left,
5846
+ orientation: pageSize?.orientation ?? 'portrait',
5847
+ pageHeightPoints: pageSize?.heightPoints ?? 72 * frame.height / 96,
5848
+ pageIndex: frame.pageIndex,
5849
+ pageSize: pageSize?.preset && 'custom' !== pageSize.preset ? pageSize.preset : 'a4',
5850
+ pageWidthPoints: pageSize?.widthPoints ?? 72 * frame.width / 96,
5851
+ top: frame.top,
5852
+ width: frame.width
5853
+ };
5854
+ });
5855
+ });
5856
+ }, [
5857
+ count,
5858
+ geometry.frames,
5859
+ pages
5860
+ ]);
5861
+ useLayoutEffect(()=>{
5862
+ const stack = stackRef.current;
5863
+ if (!stack || !windowed) return;
5864
+ const root = stack.closest('.work-document-scroll');
5865
+ if (!root) {
5866
+ const next = initialDocumentPageWindow(count);
5867
+ setRequestedWindow((current)=>documentPageWindowsEqual(current, next) ? current : next);
5868
+ return;
5869
+ }
5870
+ let animationFrame = 0;
5871
+ const update = ()=>{
5872
+ animationFrame = 0;
5873
+ const next = documentPageWindowForViewport(geometry.frames, stack, root);
5874
+ setRequestedWindow((current)=>documentPageWindowsEqual(current, next) ? current : next);
5875
+ };
5876
+ const schedule = ()=>{
5877
+ if (animationFrame) return;
5878
+ animationFrame = requestAnimationFrame(update);
5879
+ };
5880
+ const resizeObserver = "u" < typeof ResizeObserver ? null : new ResizeObserver(schedule);
5881
+ root.addEventListener('scroll', schedule, {
5882
+ passive: true
5883
+ });
5884
+ globalThis.addEventListener('resize', schedule);
5885
+ resizeObserver?.observe(root);
5886
+ resizeObserver?.observe(stack);
5887
+ update();
5888
+ return ()=>{
5889
+ if (animationFrame) cancelAnimationFrame(animationFrame);
5890
+ resizeObserver?.disconnect();
5891
+ root.removeEventListener('scroll', schedule);
5892
+ globalThis.removeEventListener('resize', schedule);
5893
+ };
5894
+ }, [
5895
+ count,
5896
+ geometry.frames,
5897
+ windowed
5898
+ ]);
5524
5899
  return /*#__PURE__*/ jsxs(Fragment, {
5525
5900
  children: [
5526
5901
  /*#__PURE__*/ jsx("div", {
5902
+ ref: stackRef,
5527
5903
  className: "work-document-page-stack",
5528
5904
  "data-page-count": count,
5529
5905
  "data-page-surface-height": geometry.height,
5530
5906
  "data-page-surface-width": geometry.width,
5907
+ "data-page-window-end": pageWindow.end,
5908
+ "data-page-window-start": pageWindow.start + 1,
5909
+ "data-page-windowed": String(windowed),
5531
5910
  "aria-hidden": "true",
5532
5911
  children: descriptors.map(({ frame, page })=>{
5533
5912
  const resolvedPageSize = page ? resolveDocumentPageSize(page.layout) : null;
@@ -5585,6 +5964,69 @@ function DocumentPageStack({ pageColor, pageCount, pageGap, pageHeight, pageWidt
5585
5964
  ]
5586
5965
  });
5587
5966
  }
5967
+ function initialDocumentPageWindow(pageCount) {
5968
+ return {
5969
+ start: 0,
5970
+ end: Math.min(pageCount, DOCUMENT_PAGE_INITIAL_WINDOW_SIZE)
5971
+ };
5972
+ }
5973
+ function clampDocumentPageWindow(pageWindow, pageCount) {
5974
+ const start = Math.max(0, Math.min(pageCount - 1, pageWindow.start));
5975
+ const end = Math.max(start + 1, Math.min(pageCount, pageWindow.end));
5976
+ return {
5977
+ start,
5978
+ end
5979
+ };
5980
+ }
5981
+ function documentPageWindowForViewport(frames, stack, root) {
5982
+ if (!frames.length) return {
5983
+ start: 0,
5984
+ end: 1
5985
+ };
5986
+ const stackRect = stack.getBoundingClientRect();
5987
+ const rootRect = root.getBoundingClientRect();
5988
+ if (!(stackRect.width > 0) || !(rootRect.height > 0)) return initialDocumentPageWindow(frames.length);
5989
+ const scale = Math.max(0.01, stackRect.width / Math.max(1, stack.offsetWidth));
5990
+ const viewportTop = Math.max(0, (rootRect.top - stackRect.top) / scale);
5991
+ const viewportBottom = Math.max(viewportTop, (rootRect.bottom - stackRect.top) / scale);
5992
+ const firstVisible = firstDocumentPageEndingAfter(frames, viewportTop);
5993
+ const lastVisible = lastDocumentPageStartingBefore(frames, viewportBottom);
5994
+ return {
5995
+ start: Math.max(0, firstVisible - document_page_stack_DOCUMENT_PAGE_WINDOW_OVERSCAN),
5996
+ end: Math.min(frames.length, Math.max(firstVisible + 1, lastVisible + 1) + document_page_stack_DOCUMENT_PAGE_WINDOW_OVERSCAN)
5997
+ };
5998
+ }
5999
+ function firstDocumentPageEndingAfter(frames, offset) {
6000
+ let lower = 0;
6001
+ let upper = frames.length - 1;
6002
+ let result = upper;
6003
+ while(lower <= upper){
6004
+ const middle = Math.floor((lower + upper) / 2);
6005
+ const frame = frames[middle];
6006
+ if (frame && frame.top + frame.height >= offset) {
6007
+ result = middle;
6008
+ upper = middle - 1;
6009
+ } else lower = middle + 1;
6010
+ }
6011
+ return result;
6012
+ }
6013
+ function lastDocumentPageStartingBefore(frames, offset) {
6014
+ let lower = 0;
6015
+ let upper = frames.length - 1;
6016
+ let result = 0;
6017
+ while(lower <= upper){
6018
+ const middle = Math.floor((lower + upper) / 2);
6019
+ const frame = frames[middle];
6020
+ if (frame && frame.top <= offset) {
6021
+ result = middle;
6022
+ lower = middle + 1;
6023
+ } else upper = middle - 1;
6024
+ }
6025
+ return result;
6026
+ }
6027
+ function documentPageWindowsEqual(left, right) {
6028
+ return left.start === right.start && left.end === right.end;
6029
+ }
5588
6030
  function DocumentRulerTabStops({ marginLeft, pageWidth, rulerRef, tabStops, textWidth, onChange }) {
5589
6031
  const normalized = constrainRulerTabStops(tabStops, textWidth);
5590
6032
  const positionFromClientX = (clientX)=>{
@@ -13262,7 +13704,7 @@ function useDocumentPageChrome({ editor, enabled, firstPage, footerRef, headerRe
13262
13704
  visibleChrome
13263
13705
  };
13264
13706
  }
13265
- function planIncrementalDocumentLayout(previous, next, dirtyFrom) {
13707
+ function planIncrementalDocumentLayout(previous, next, dirtyFrom, reusedPrefixBlockCount = 0) {
13266
13708
  const fullLayout = ()=>({
13267
13709
  blocks: next.map(({ block })=>block),
13268
13710
  reusedPageCount: 0,
@@ -13270,7 +13712,8 @@ function planIncrementalDocumentLayout(previous, next, dirtyFrom) {
13270
13712
  startPageIndex: 0
13271
13713
  });
13272
13714
  if (!previous || !Number.isFinite(dirtyFrom) || dirtyFrom <= 0 || 0 !== previous.layout.startPageIndex || previous.layout.pages.length < 3) return fullLayout();
13273
- const affectedBlockIndex = earliestAffectedBlockIndex(previous.blocks, next, dirtyFrom);
13715
+ const stablePrefixBlockCount = Math.max(0, Math.min(Math.trunc(reusedPrefixBlockCount), previous.blocks.length, next.length));
13716
+ const affectedBlockIndex = earliestAffectedBlockIndex(previous.blocks, next, dirtyFrom, stablePrefixBlockCount);
13274
13717
  const pageByBlockId = new Map(previous.layout.pages.flatMap((page)=>page.placements.map((placement)=>[
13275
13718
  placement.blockId,
13276
13719
  page.index
@@ -13288,10 +13731,6 @@ function planIncrementalDocumentLayout(previous, next, dirtyFrom) {
13288
13731
  block.id,
13289
13732
  index
13290
13733
  ]));
13291
- const previousBlockById = new Map(previous.blocks.map(({ block })=>[
13292
- block.id,
13293
- block
13294
- ]));
13295
13734
  let startPageIndex = affectedPageIndex - 1;
13296
13735
  while(startPageIndex > 0){
13297
13736
  const startBlockId = previous.layout.pages[startPageIndex]?.placements[0]?.blockId;
@@ -13313,7 +13752,7 @@ function planIncrementalDocumentLayout(previous, next, dirtyFrom) {
13313
13752
  startPageIndex -= 1;
13314
13753
  continue;
13315
13754
  }
13316
- if (!prefixMatches(previous.layout.pages, startPageIndex, previousBlockById, next, startBlockIndex)) {
13755
+ if (!prefixMatches(previous.layout.pages, startPageIndex, previous.blocks, next, startBlockIndex, stablePrefixBlockCount)) {
13317
13756
  startPageIndex -= 1;
13318
13757
  continue;
13319
13758
  }
@@ -13349,13 +13788,22 @@ function mergeIncrementalDocumentLayout(previous, partial) {
13349
13788
  ]
13350
13789
  };
13351
13790
  }
13352
- function earliestAffectedBlockIndex(previous, next, dirtyFrom) {
13353
- const positionIndex = next.findIndex((candidate)=>candidate.to > dirtyFrom);
13791
+ function earliestAffectedBlockIndex(previous, next, dirtyFrom, stablePrefixBlockCount) {
13792
+ let lower = 0;
13793
+ let upper = next.length;
13794
+ while(lower < upper){
13795
+ const middle = Math.floor((lower + upper) / 2);
13796
+ if (next[middle].to <= dirtyFrom) lower = middle + 1;
13797
+ else upper = middle;
13798
+ }
13799
+ const positionIndex = lower < next.length ? lower : -1;
13354
13800
  const sharedLength = Math.min(previous.length, next.length);
13355
- let divergentIndex = -1;
13356
- for(let index = 0; index < sharedLength; index += 1)if (!sameLayoutBlock(previous[index].block, next[index].block)) {
13357
- divergentIndex = index;
13358
- break;
13801
+ let divergentIndex = stablePrefixBlockCount > 0 && stablePrefixBlockCount < sharedLength ? stablePrefixBlockCount : -1;
13802
+ if (0 === stablePrefixBlockCount) {
13803
+ for(let index = 0; index < sharedLength; index += 1)if (!sameLayoutBlock(previous[index].block, next[index].block)) {
13804
+ divergentIndex = index;
13805
+ break;
13806
+ }
13359
13807
  }
13360
13808
  if (divergentIndex < 0 && previous.length !== next.length) divergentIndex = sharedLength;
13361
13809
  const candidates = [
@@ -13366,14 +13814,18 @@ function earliestAffectedBlockIndex(previous, next, dirtyFrom) {
13366
13814
  Math.max(0, next.length - 1)
13367
13815
  ]);
13368
13816
  }
13369
- function prefixMatches(pages, startPageIndex, previousBlockById, next, startBlockIndex) {
13370
- const prefixIds = pages.slice(0, startPageIndex).flatMap((page)=>page.placements.map((placement)=>placement.blockId));
13371
- if (prefixIds.length !== startBlockIndex) return false;
13372
- return prefixIds.every((blockId, index)=>{
13373
- const previous = previousBlockById.get(blockId);
13374
- const candidate = next[index]?.block;
13375
- return void 0 !== previous && candidate?.id === blockId && sameLayoutBlock(previous, candidate);
13376
- });
13817
+ function prefixMatches(pages, startPageIndex, previous, next, startBlockIndex, stablePrefixBlockCount) {
13818
+ let blockIndex = 0;
13819
+ for(let pageIndex = 0; pageIndex < startPageIndex; pageIndex += 1)for (const placement of pages[pageIndex]?.placements ?? []){
13820
+ if (blockIndex >= startBlockIndex) return false;
13821
+ if (blockIndex >= stablePrefixBlockCount) {
13822
+ const previousBlock = previous[blockIndex]?.block;
13823
+ const nextBlock = next[blockIndex]?.block;
13824
+ if (previousBlock?.id !== placement.blockId || nextBlock?.id !== placement.blockId || !sameLayoutBlock(previousBlock, nextBlock)) return false;
13825
+ }
13826
+ blockIndex += 1;
13827
+ }
13828
+ return blockIndex === startBlockIndex;
13377
13829
  }
13378
13830
  function sameLayoutBlock(left, right) {
13379
13831
  return left.id === right.id && left.height === right.height && left.pageStyleId === right.pageStyleId && left.breakBefore === right.breakBefore && left.breakAfter === right.breakAfter && left.keepTogether === right.keepTogether && left.keepWithNext === right.keepWithNext && left.flowId === right.flowId && left.flowIndex === right.flowIndex && left.flowCount === right.flowCount && left.minimumFragmentsPerPage === right.minimumFragmentsPerPage && left.repeatHeaderCount === right.repeatHeaderCount && left.repeatHeaderHeight === right.repeatHeaderHeight;
@@ -13492,6 +13944,7 @@ function createDocumentPaginationRunCoordinator({ cancelFrame, onAbort, onCoales
13492
13944
  request
13493
13945
  };
13494
13946
  }
13947
+ const MAX_DOCUMENT_BLOCK_RESIZE_OBSERVATIONS = 4096;
13495
13948
  function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, page, selectionVersion, wasmUrl, layoutFonts, loadedLayoutFontIds }) {
13496
13949
  const client = useOfficeKernelClient(wasmUrl, layoutFonts);
13497
13950
  const editorMounted = useEditorMounted(editor);
@@ -13537,6 +13990,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
13537
13990
  delete editorDom.dataset.paginationFallbackGlyphs;
13538
13991
  delete editorDom.dataset.paginationFlows;
13539
13992
  delete editorDom.dataset.paginationMeasuredBlocks;
13993
+ delete editorDom.dataset.paginationObservedBlocks;
13540
13994
  delete editorDom.dataset.paginationLaidOutBlocks;
13541
13995
  delete editorDom.dataset.paginationPages;
13542
13996
  delete editorDom.dataset.paginationReusedBlocks;
@@ -13556,6 +14010,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
13556
14010
  delete editorDom.dataset.paginationDocumentTriggers;
13557
14011
  delete editorDom.dataset.paginationFontTriggers;
13558
14012
  delete editorDom.dataset.paginationResizeTriggers;
14013
+ delete editorDom.dataset.paginationResizeScope;
13559
14014
  delete editorDom.dataset.paginationRuns;
13560
14015
  delete editorDom.dataset.paginationTextBatch;
13561
14016
  delete editorDom.dataset.paginationTextBatches;
@@ -13618,7 +14073,10 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
13618
14073
  };
13619
14074
  const observeBlocks = (blocks)=>{
13620
14075
  stopObservingBlocks();
13621
- observedBlockPositions = documentResizeObservationPositions(blocks);
14076
+ const observation = documentResizeObservationTargets(editorDom, blocks);
14077
+ editorDom.dataset.paginationObservedBlocks = String(observation.observedBlockCount);
14078
+ editorDom.dataset.paginationResizeScope = observation.scope;
14079
+ observedBlockPositions = observation.positions;
13622
14080
  observedElements = Array.from(observedBlockPositions.keys());
13623
14081
  observedHeights.clear();
13624
14082
  for (const element of observedElements)observedHeights.set(element, element.offsetHeight);
@@ -13700,7 +14158,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
13700
14158
  return;
13701
14159
  }
13702
14160
  const previousPagination = paginationCache.current;
13703
- const layoutPlan = planIncrementalDocumentLayout(previousPagination, snapshot.blocks, measurementStart);
14161
+ const layoutPlan = planIncrementalDocumentLayout(previousPagination, snapshot.blocks, measurementStart, snapshot.reusedPrefixBlockCount);
13704
14162
  editorDom.dataset.paginationLaidOutBlocks = String(layoutPlan.blocks.length);
13705
14163
  editorDom.dataset.paginationReusedPages = String(layoutPlan.reusedPageCount);
13706
14164
  try {
@@ -13806,7 +14264,11 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
13806
14264
  const markDirty = (position)=>{
13807
14265
  measurementRange.invalidate(position);
13808
14266
  };
13809
- const handleDocumentUpdate = ({ transaction })=>{
14267
+ const handleDocumentUpdate = ({ appendedTransactions, transaction })=>{
14268
+ if (documentTransactionsOnlyHydrateChunks([
14269
+ transaction,
14270
+ ...appendedTransactions ?? []
14271
+ ])) return;
13810
14272
  updateDiagnostic('documentTriggers', 'paginationDocumentTriggers');
13811
14273
  markDirty(earliestChangedPosition(transaction));
13812
14274
  schedule(true);
@@ -13914,6 +14376,24 @@ function documentResizeObservationPositions(blocks) {
13914
14376
  }
13915
14377
  return positions;
13916
14378
  }
14379
+ function documentResizeObservationTargets(editorDom, blocks) {
14380
+ const positions = documentResizeObservationPositions(blocks);
14381
+ if (positions.size <= MAX_DOCUMENT_BLOCK_RESIZE_OBSERVATIONS) return {
14382
+ observedBlockCount: positions.size,
14383
+ positions,
14384
+ scope: 'blocks'
14385
+ };
14386
+ return {
14387
+ observedBlockCount: positions.size,
14388
+ positions: new Map([
14389
+ [
14390
+ editorDom,
14391
+ 0
14392
+ ]
14393
+ ]),
14394
+ scope: 'document'
14395
+ };
14396
+ }
13917
14397
  function deriveDocumentPaginationPageDescriptors(layout, blocks, documentNode, previousPages = [], requestedReusedPageCount = 0) {
13918
14398
  const blockById = new Map(blocks.map((candidate)=>[
13919
14399
  candidate.block.id,
@@ -14062,20 +14542,25 @@ function pageForPosition(pagination, position) {
14062
14542
  return block ? pagination.pageByBlockId.get(block.block.id) ?? 1 : 1;
14063
14543
  }
14064
14544
  function blockForPosition(blocks, position) {
14065
- const rangedBlock = blocks.find((block)=>block.selectionRanges?.some((range)=>range.from <= position && position < range.to));
14066
- if (rangedBlock) return rangedBlock;
14545
+ if (!blocks.length) return;
14067
14546
  let lower = 0;
14068
14547
  let upper = blocks.length - 1;
14069
- let containing = blocks[0];
14548
+ let containingIndex = 0;
14070
14549
  while(lower <= upper){
14071
14550
  const middle = Math.floor((lower + upper) / 2);
14072
14551
  const candidate = blocks[middle];
14073
14552
  if (candidate.from <= position) {
14074
- containing = candidate;
14553
+ containingIndex = middle;
14075
14554
  lower = middle + 1;
14076
14555
  } else upper = middle - 1;
14077
14556
  }
14078
- return containing;
14557
+ let overlappingFrom = containingIndex;
14558
+ while(overlappingFrom > 0 && blocks[overlappingFrom - 1].to > position)overlappingFrom -= 1;
14559
+ for(let index = overlappingFrom; index <= containingIndex; index += 1){
14560
+ const candidate = blocks[index];
14561
+ if (candidate.selectionRanges?.some((range)=>range.from <= position && position < range.to)) return candidate;
14562
+ }
14563
+ return blocks[containingIndex];
14079
14564
  }
14080
14565
  function pageMetricsKey(page) {
14081
14566
  return [
@@ -14395,20 +14880,29 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14395
14880
  const citationsDraftFocusRef = useRef(null);
14396
14881
  const statisticsInvokerRef = useRef(null);
14397
14882
  const contentRef = useRef(effectiveContent);
14883
+ const editorMountStartedAtRef = useRef(documentEditorNow());
14884
+ const editorBeforeCreateAtRef = useRef(null);
14885
+ const editorDetachedMountAtRef = useRef(null);
14398
14886
  const onChangeRef = useRef(onChange);
14399
14887
  const trackChangesRef = useRef(suggestionOnly || Boolean(effectiveContent.trackChanges));
14400
14888
  const collaborationBindingRef = useRef(collaborationBinding);
14401
- const normalizedContent = useMemo(()=>normalizeDocumentHtml(effectiveContent), [
14889
+ const validatedModel = useMemo(()=>documentModelForContent(effectiveContent), [
14402
14890
  effectiveContent
14403
14891
  ]);
14404
- const editorInput = useMemo(()=>resolveWorkDocumentEditorInput(effectiveContent, normalizedContent), [
14892
+ const normalizedContent = useMemo(()=>validatedModel ? effectiveContent.html : normalizeDocumentHtml(effectiveContent), [
14405
14893
  effectiveContent,
14406
- normalizedContent
14894
+ validatedModel
14895
+ ]);
14896
+ const editorInput = useMemo(()=>resolveWorkDocumentEditorInput(effectiveContent, normalizedContent, validatedModel), [
14897
+ effectiveContent,
14898
+ normalizedContent,
14899
+ validatedModel
14407
14900
  ]);
14408
14901
  const initialEditorSourceRef = useRef(editorInput.source);
14409
14902
  const appliedSourceKeyRef = useRef(editorInput.sourceKey);
14410
14903
  const activeReviewConflictsRef = useRef([]);
14411
14904
  const publishedDocumentRef = useRef(null);
14905
+ const pendingLazyPublicationRef = useRef(null);
14412
14906
  const [taskPane, setTaskPane] = useState(null);
14413
14907
  const [layoutPanelTab, setLayoutPanelTab] = useState('page');
14414
14908
  const [findReplaceFocusRequest, setFindReplaceFocusRequest] = useState(0);
@@ -14453,7 +14947,10 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14453
14947
  });
14454
14948
  }
14455
14949
  };
14456
- const editorExtensions = useMemo(()=>mergeOfficeTiptapExtensions('DocumentEditor', [
14950
+ const trustInitialIntegrityFeatures = documentModelHasTrustedInitialIntegrityFeatures(editorInput.model);
14951
+ const editorExtensions = useMemo(()=>{
14952
+ const startedAt = documentEditorNow();
14953
+ const merged = mergeOfficeTiptapExtensions('DocumentEditor', [
14457
14954
  ...collaborationBinding?.extensions ?? createWorkDocumentExtensions({
14458
14955
  getContent: ()=>contentRef.current,
14459
14956
  isTracking: ()=>trackChangesRef.current,
@@ -14469,17 +14966,22 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14469
14966
  trackChanges
14470
14967
  };
14471
14968
  commitContentChange(next);
14472
- }
14969
+ },
14970
+ trustInitialIntegrityFeatures
14473
14971
  }),
14474
14972
  extension_placeholder.configure({
14475
14973
  placeholder: '在这里开始输入…'
14476
14974
  }),
14477
14975
  DocumentPagination
14478
- ], collaboration ? EMPTY_DOCUMENT_EXTENSIONS : extensions), [
14976
+ ], collaboration ? EMPTY_DOCUMENT_EXTENSIONS : extensions);
14977
+ recordDocumentEditorMeasure('a3s-office.document.editor-extensions', startedAt, documentEditorNow());
14978
+ return merged;
14979
+ }, [
14479
14980
  collaboration,
14480
14981
  collaborationBinding,
14481
14982
  commitContentChange,
14482
- extensions
14983
+ extensions,
14984
+ trustInitialIntegrityFeatures
14483
14985
  ]);
14484
14986
  const editorProps = useMemo(()=>({
14485
14987
  attributes: {
@@ -14492,16 +14994,107 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14492
14994
  }), [
14493
14995
  commentOnly
14494
14996
  ]);
14997
+ const publishDocumentUpdate = useCallback((current, previousDocument)=>{
14998
+ if (current.isDestroyed || previousDocument.eq(current.state.doc)) return;
14999
+ const publishStartedAt = documentEditorNow();
15000
+ const previousContent = contentRef.current;
15001
+ const previousModel = previousContent.model;
15002
+ const compactRoot = current.getJSON();
15003
+ const materialized = previousModel && documentLazyHtmlProjection(previousModel) ? materializeLazyDocumentUpdate(previousDocument, current.state.doc, compactRoot, previousModel) : {
15004
+ html: null,
15005
+ htmlFingerprint: null,
15006
+ root: materializeLazyDocumentEditorRoot(compactRoot, previousModel)
15007
+ };
15008
+ const anchors = collectDocumentCommentAnchors(current.state.doc);
15009
+ const retainedCommentIds = new Set(activeReviewConflictsRef.current.filter((conflict)=>'comment' === conflict.kind).map((conflict)=>conflict.id));
15010
+ const synchronized = null === materialized.html ? syncDocumentContentFromHtml(previousContent, documentModelUsesWindowing(materialized.root) ? serializeWorkDocumentNode(materialized.root) : current.getHTML()) : {
15011
+ ...previousContent,
15012
+ html: materialized.html
15013
+ };
15014
+ const model = createSchemaDerivedWorkDocumentModel(synchronized.html, materialized.root, previousModel, materialized.htmlFingerprint ?? void 0);
15015
+ const next = {
15016
+ ...synchronized,
15017
+ model,
15018
+ comments: retainAnchoredDocumentComments(previousContent.comments ?? [], anchors, retainedCommentIds)
15019
+ };
15020
+ appliedSourceKeyRef.current = `model:${model.revision}:${model.htmlFingerprint}`;
15021
+ if (!collaborationBindingRef.current) {
15022
+ contentRef.current = next;
15023
+ onChangeRef.current(next);
15024
+ }
15025
+ const publishEndedAt = documentEditorNow();
15026
+ const publishCount = Number(current.view.dom.dataset.documentControlledPublishCount) || 0;
15027
+ current.view.dom.dataset.documentControlledPublishCount = String(publishCount + 1);
15028
+ current.view.dom.dataset.documentControlledPublishMode = null === materialized.html ? 'full' : 'lazy-chunk';
15029
+ current.view.dom.dataset.documentControlledPublishMs = String(Math.round((publishEndedAt - publishStartedAt) * 10) / 10);
15030
+ recordDocumentEditorMeasure('a3s-office.document.controlled-publish', publishStartedAt, publishEndedAt, {
15031
+ mode: current.view.dom.dataset.documentControlledPublishMode
15032
+ });
15033
+ }, []);
15034
+ const queueLazyDocumentPublication = useCallback((current, previousDocument)=>{
15035
+ const pending = pendingLazyPublicationRef.current;
15036
+ if (pending) {
15037
+ pending.editor = current;
15038
+ return;
15039
+ }
15040
+ const flush = ()=>{
15041
+ const queued = pendingLazyPublicationRef.current;
15042
+ pendingLazyPublicationRef.current = null;
15043
+ if (queued) publishDocumentUpdate(queued.editor, queued.before);
15044
+ };
15045
+ pendingLazyPublicationRef.current = {
15046
+ before: previousDocument,
15047
+ cancel: scheduleDocumentEditorFrame(flush),
15048
+ editor: current
15049
+ };
15050
+ }, [
15051
+ publishDocumentUpdate
15052
+ ]);
15053
+ useEffect(()=>()=>{
15054
+ const pending = pendingLazyPublicationRef.current;
15055
+ pendingLazyPublicationRef.current = null;
15056
+ if (!pending) return;
15057
+ pending.cancel();
15058
+ publishDocumentUpdate(pending.editor, pending.before);
15059
+ }, [
15060
+ publishDocumentUpdate
15061
+ ]);
14495
15062
  const editor = useEditor({
15063
+ immediatelyRender: false,
14496
15064
  extensions: editorExtensions,
14497
15065
  content: collaboration ? void 0 : initialEditorSourceRef.current,
14498
15066
  editable: !readOnly,
14499
15067
  editorProps,
15068
+ onBeforeCreate: ()=>{
15069
+ const beforeCreateAt = documentEditorNow();
15070
+ editorBeforeCreateAtRef.current = beforeCreateAt;
15071
+ recordDocumentEditorMeasure('a3s-office.document.editor-before-create', editorMountStartedAtRef.current, beforeCreateAt);
15072
+ },
15073
+ onMount: ()=>{
15074
+ const mountedAt = documentEditorNow();
15075
+ editorDetachedMountAtRef.current = mountedAt;
15076
+ const beforeCreateAt = editorBeforeCreateAtRef.current;
15077
+ if (null !== beforeCreateAt) recordDocumentEditorMeasure('a3s-office.document.editor-state-view', beforeCreateAt, mountedAt);
15078
+ },
14500
15079
  onCreate: ({ editor: current })=>{
14501
15080
  publishedDocumentRef.current = current.state.doc;
15081
+ const mountedAt = documentEditorNow();
15082
+ const detachedMountAt = editorDetachedMountAtRef.current;
15083
+ if (null !== detachedMountAt) recordDocumentEditorMeasure('a3s-office.document.editor-create-dispatch', detachedMountAt, mountedAt);
15084
+ current.view.dom.dataset.documentEditorMountMs = String(Math.round((mountedAt - editorMountStartedAtRef.current) * 10) / 10);
15085
+ recordDocumentEditorMeasure('a3s-office.document.editor-mount', editorMountStartedAtRef.current, mountedAt, {
15086
+ source: editorInput.model ? 'model' : 'html',
15087
+ windowed: Boolean(editorInput.model && documentModelUsesWindowing(editorInput.model.root))
15088
+ });
15089
+ },
15090
+ onTransaction: ({ appendedTransactions, editor: current, transaction })=>{
15091
+ if (documentTransactionsOnlyHydrateChunks([
15092
+ transaction,
15093
+ ...appendedTransactions
15094
+ ])) publishedDocumentRef.current = current.state.doc;
14502
15095
  },
14503
- onUpdate: ({ editor: current, transaction })=>{
14504
- if (!shouldPublishDocumentUpdate(transaction)) {
15096
+ onUpdate: ({ appendedTransactions, editor: current, transaction })=>{
15097
+ if (!shouldPublishDocumentUpdate(transaction, appendedTransactions ?? [])) {
14505
15098
  publishedDocumentRef.current = current.state.doc;
14506
15099
  return;
14507
15100
  }
@@ -14509,22 +15102,13 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14509
15102
  publishedDocumentRef.current = current.state.doc;
14510
15103
  return;
14511
15104
  }
14512
- if (publishedDocumentRef.current.eq(current.state.doc)) return;
15105
+ const previousDocument = publishedDocumentRef.current;
15106
+ if (previousDocument.eq(current.state.doc)) return;
15107
+ const lazyProjection = documentLazyHtmlProjection(contentRef.current.model);
15108
+ if (lazyProjection) transferLazyDocumentTextStatistics(previousDocument, current.state.doc);
14513
15109
  publishedDocumentRef.current = current.state.doc;
14514
- const anchors = collectDocumentCommentAnchors(current.state.doc);
14515
- const retainedCommentIds = new Set(activeReviewConflictsRef.current.filter((conflict)=>'comment' === conflict.kind).map((conflict)=>conflict.id));
14516
- const synchronized = syncDocumentContentFromHtml(contentRef.current, current.getHTML());
14517
- const model = createWorkDocumentModel(synchronized.html, current.getJSON(), contentRef.current.model);
14518
- const next = {
14519
- ...synchronized,
14520
- model,
14521
- comments: retainAnchoredDocumentComments(contentRef.current.comments ?? [], anchors, retainedCommentIds)
14522
- };
14523
- appliedSourceKeyRef.current = `model:${model.revision}:${model.htmlFingerprint}`;
14524
- if (!collaborationBinding) {
14525
- contentRef.current = next;
14526
- onChangeRef.current(next);
14527
- }
15110
+ if (lazyProjection) queueLazyDocumentPublication(current, previousDocument);
15111
+ else publishDocumentUpdate(current, previousDocument);
14528
15112
  },
14529
15113
  onSelectionUpdate: ()=>setSelectionVersion((value)=>value + 1)
14530
15114
  });
@@ -15478,4 +16062,24 @@ function cssPixelValue(value) {
15478
16062
  const parsed = Number.parseFloat(value);
15479
16063
  return Number.isFinite(parsed) ? parsed : 0;
15480
16064
  }
16065
+ function scheduleDocumentEditorFrame(callback) {
16066
+ if ('function' == typeof requestAnimationFrame) {
16067
+ const frame = requestAnimationFrame(callback);
16068
+ return ()=>cancelAnimationFrame(frame);
16069
+ }
16070
+ const timeout = setTimeout(callback, 0);
16071
+ return ()=>clearTimeout(timeout);
16072
+ }
16073
+ function documentEditorNow() {
16074
+ return globalThis.performance?.now?.() ?? Date.now();
16075
+ }
16076
+ function recordDocumentEditorMeasure(name, start, end, detail) {
16077
+ try {
16078
+ globalThis.performance?.measure(name, {
16079
+ detail,
16080
+ end,
16081
+ start
16082
+ });
16083
+ } catch {}
16084
+ }
15481
16085
  export { document_editor_namespaceObject };