@a3s-lab/office 0.9.0 → 0.9.2
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/COLLABORATION_ROADMAP.md +11 -4
- package/README.md +12 -3
- package/dist/0~document-editor.js +189 -134
- package/dist/8928.js +124 -71
- package/dist/internal/features/work/editors/document-pagination-measurement-range.d.ts +18 -0
- package/dist/internal/features/work/work-document-pagination-measurement.d.ts +11 -0
- package/dist/internal/features/work/work-document-pagination.d.ts +2 -1
- package/dist/office-kernel.wasm +0 -0
- package/docs/latest/en/browser-editor-architecture.md +7 -0
- package/package.json +1 -1
package/COLLABORATION_ROADMAP.md
CHANGED
|
@@ -395,8 +395,9 @@ projection, a host-injected live CLI transport session, authenticated browser
|
|
|
395
395
|
suggestion-update authorization, and typed Markdown, Document
|
|
396
396
|
content/comment/suggestion, Spreadsheet cell, Presentation scene-element, PDF
|
|
397
397
|
annotation/form-value, and PDF redaction/page-operation review mutation surfaces
|
|
398
|
-
are implemented
|
|
399
|
-
|
|
398
|
+
are implemented. The live CLI session also projects ephemeral native Presence
|
|
399
|
+
and format-specific locations through standard Yjs Awareness; remaining typed
|
|
400
|
+
format mutations are pending.
|
|
400
401
|
|
|
401
402
|
- Yrs `0.27.3` now uses 53-bit Yjs-compatible client IDs and exchanges standard
|
|
402
403
|
Yjs v1 updates, state vectors, and y-sync `SyncStep1`/`Update` messages with
|
|
@@ -426,6 +427,14 @@ are pending.
|
|
|
426
427
|
stdin/stdout for a coding-agent or product host. The host still owns the
|
|
427
428
|
WebSocket or IPC channel, room selection, authentication, authorization,
|
|
428
429
|
buffering, and delivery identities; the CLI never opens a provider itself.
|
|
430
|
+
- Supplying `--actor-name` gives the live session a separate in-memory Yrs
|
|
431
|
+
Awareness peer. Typed active/idle/away state and Document, Markdown,
|
|
432
|
+
Spreadsheet, Presentation, or PDF locations are emitted as bounded
|
|
433
|
+
`outbound-awareness` records, while validated remote updates and peer-left
|
|
434
|
+
events become sorted participant snapshots. Reconnect clears stale remote
|
|
435
|
+
state and republishes the local participant; orderly close emits an
|
|
436
|
+
Awareness tombstone. No Presence state or clock enters the replica,
|
|
437
|
+
checkpoint, durable update log, or operation receipts.
|
|
429
438
|
- Each replica binds one stable actor ID, actor kind, permission mode, artifact
|
|
430
439
|
identity/kind, namespace, and client ID. Apply/checkpoint/leave require the
|
|
431
440
|
same identity plus a stable operation ID and accept an optional state-vector
|
|
@@ -518,8 +527,6 @@ Remaining:
|
|
|
518
527
|
structural/rich-text operations plus PDF signatures; deepen Document
|
|
519
528
|
mutations to additional nested structures and complete table/list/section
|
|
520
529
|
revision workflows.
|
|
521
|
-
- Project editor-visible presence and selection state while keeping Awareness
|
|
522
|
-
ephemeral and outside native replica persistence.
|
|
523
530
|
|
|
524
531
|
Exit criterion: a browser, `office` CLI, MCP client, and `a3s code` agent edit
|
|
525
532
|
the same artifact concurrently, converge at the shared-model level, reconnect
|
package/README.md
CHANGED
|
@@ -415,7 +415,10 @@ interaction model.
|
|
|
415
415
|
edit/preview/PDF typography and page-chrome placement. Editing, read-only
|
|
416
416
|
preview, and browser PDF export share one live pagination result. Tail edits
|
|
417
417
|
reuse the stable physical-page prefix, including resolved first/odd/even
|
|
418
|
-
headers, footers, page numbers, and navigation descriptors.
|
|
418
|
+
headers, footers, page numbers, and navigation descriptors. Browser DOM
|
|
419
|
+
measurement runs in bounded 32 ms slices and yields only between top-level
|
|
420
|
+
blocks; document edits abort stale passes before a snapshot is committed, so
|
|
421
|
+
long repagination work does not monopolize the browser event loop.
|
|
419
422
|
Real DOCX fixtures provide deterministic A3S Test evidence for inherited
|
|
420
423
|
table styling across edit and preview, a centered 62.5% table with table and
|
|
421
424
|
cell margin overrides, all four Table Properties tabs at 390 px, exact
|
|
@@ -1039,7 +1042,7 @@ cargo run -p a3s-office-cli -- collab diff .a3s/report.replica \
|
|
|
1039
1042
|
|
|
1040
1043
|
# Bridge that replica to a host-owned room over machine-readable JSONL.
|
|
1041
1044
|
cargo run -p a3s-office-cli -- collab session .a3s/report.replica \
|
|
1042
|
-
--poll-ms 100 --json
|
|
1045
|
+
--poll-ms 100 --actor-name "A3S Agent" --json
|
|
1043
1046
|
|
|
1044
1047
|
# Make a typed local change in an initialized Markdown replica. A running
|
|
1045
1048
|
# session publishes the resulting incremental Yjs update automatically.
|
|
@@ -1177,7 +1180,11 @@ controller as a shared participant roster, remote canvas projection, and
|
|
|
1177
1180
|
participant-to-location navigation; neither component creates an account or
|
|
1178
1181
|
backend. The native CLI's JSONL session bridges the same host-channel envelope,
|
|
1179
1182
|
including reconnect handshakes, durable agent updates, and remote-echo
|
|
1180
|
-
suppression, without opening its own network provider.
|
|
1183
|
+
suppression, without opening its own network provider. With `--actor-name`, it
|
|
1184
|
+
also emits standard, bounded `outbound-awareness` records for ephemeral agent
|
|
1185
|
+
activity and format-specific locations, accepts remote Awareness and peer-left
|
|
1186
|
+
records, and publishes participant snapshots without changing the durable
|
|
1187
|
+
replica. Native Rust `project`,
|
|
1181
1188
|
`collab read`, and `office_collaboration_read` return the exact canonical
|
|
1182
1189
|
Markdown source or an Office-owned bounded Document projection with stable
|
|
1183
1190
|
paragraph/text identities, structural ancestry, option fields, subordinate
|
|
@@ -1320,6 +1327,8 @@ without hard-coded return URLs.
|
|
|
1320
1327
|
|
|
1321
1328
|
- [Live Playground](https://a3s-lab.github.io/Office/)
|
|
1322
1329
|
- [Documentation center](https://a3s-lab.github.io/Office/docs/)
|
|
1330
|
+
- [A3S Office 0.9.2 documentation](https://a3s-lab.github.io/Office/docs/0.9.2/)
|
|
1331
|
+
- [A3S Office 0.9.1 documentation](https://a3s-lab.github.io/Office/docs/0.9.1/)
|
|
1323
1332
|
- [A3S Office 0.9.0 documentation](https://a3s-lab.github.io/Office/docs/0.9.0/)
|
|
1324
1333
|
- [A3S Office 0.8.1 documentation](https://a3s-lab.github.io/Office/docs/0.8.1/)
|
|
1325
1334
|
- [A3S Office 0.8.0 documentation](https://a3s-lab.github.io/Office/docs/0.8.0/)
|
|
@@ -19,7 +19,7 @@ import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
|
|
|
19
19
|
import { useOfficeTaskPaneEscape, normalizeOfficeFontFamily, OfficeCheckbox, useOfficeDialog, useOfficeTaskPaneModal, CommittedOfficeNumberField, officeFontFamilyLabel, officeFontFamilies, CollectionState, createOfficeKernelClient, OfficeNumberField } from "./0~7048.js";
|
|
20
20
|
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
21
|
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,
|
|
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";
|
|
@@ -13382,6 +13382,44 @@ function incrementalBoundaryBreak(previous, next) {
|
|
|
13382
13382
|
spacerHeight: remainingBodyHeight + previous.page.marginBottom + previous.page.pageGap + next.page.marginTop
|
|
13383
13383
|
};
|
|
13384
13384
|
}
|
|
13385
|
+
function createDocumentPaginationMeasurementRange() {
|
|
13386
|
+
let activePass = null;
|
|
13387
|
+
let dirtyFrom = 0;
|
|
13388
|
+
const restore = (pass)=>{
|
|
13389
|
+
if (activePass !== pass) return;
|
|
13390
|
+
dirtyFrom = Math.min(dirtyFrom, pass.from);
|
|
13391
|
+
activePass = null;
|
|
13392
|
+
};
|
|
13393
|
+
return {
|
|
13394
|
+
begin: ()=>{
|
|
13395
|
+
const pass = {
|
|
13396
|
+
from: Number.isFinite(dirtyFrom) ? dirtyFrom : 0
|
|
13397
|
+
};
|
|
13398
|
+
activePass = pass;
|
|
13399
|
+
dirtyFrom = 1 / 0;
|
|
13400
|
+
return pass;
|
|
13401
|
+
},
|
|
13402
|
+
commit: (pass)=>{
|
|
13403
|
+
if (activePass === pass) activePass = null;
|
|
13404
|
+
},
|
|
13405
|
+
ensureDirty: ()=>{
|
|
13406
|
+
if (Number.isFinite(dirtyFrom)) return;
|
|
13407
|
+
dirtyFrom = activePass?.from ?? 0;
|
|
13408
|
+
},
|
|
13409
|
+
invalidate: (position)=>{
|
|
13410
|
+
const normalizedPosition = Number.isFinite(position) ? Math.max(0, position) : 0;
|
|
13411
|
+
dirtyFrom = Math.min(dirtyFrom, normalizedPosition);
|
|
13412
|
+
},
|
|
13413
|
+
reset: ()=>{
|
|
13414
|
+
activePass = null;
|
|
13415
|
+
dirtyFrom = 0;
|
|
13416
|
+
},
|
|
13417
|
+
restore,
|
|
13418
|
+
restoreActive: ()=>{
|
|
13419
|
+
if (activePass) restore(activePass);
|
|
13420
|
+
}
|
|
13421
|
+
};
|
|
13422
|
+
}
|
|
13385
13423
|
function createDocumentPaginationRunCoordinator({ cancelFrame, onAbort, onCoalescedRequest, onError, onRunFinish, onRunStart, requestFrame, run }) {
|
|
13386
13424
|
let activeController = null;
|
|
13387
13425
|
let disposed = false;
|
|
@@ -13455,7 +13493,9 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
13455
13493
|
const paginationCache = useRef(null);
|
|
13456
13494
|
const measurementEditor = useRef(null);
|
|
13457
13495
|
const measurementLayoutKey = useRef('');
|
|
13458
|
-
const
|
|
13496
|
+
const measurementRangeRef = useRef(null);
|
|
13497
|
+
measurementRangeRef.current ??= createDocumentPaginationMeasurementRange();
|
|
13498
|
+
const measurementRange = measurementRangeRef.current;
|
|
13459
13499
|
const observedDocumentRevision = useRef(documentRevision);
|
|
13460
13500
|
const [pagination, setPagination] = useState(null);
|
|
13461
13501
|
const pageKey = pageMetricsKey(page);
|
|
@@ -13470,10 +13510,10 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
13470
13510
|
paginationCache.current = null;
|
|
13471
13511
|
measurementEditor.current = editor;
|
|
13472
13512
|
measurementLayoutKey.current = measurementKey;
|
|
13473
|
-
|
|
13513
|
+
measurementRange.reset();
|
|
13474
13514
|
}
|
|
13475
13515
|
if (observedDocumentRevision.current !== documentRevision) {
|
|
13476
|
-
|
|
13516
|
+
measurementRange.ensureDirty();
|
|
13477
13517
|
observedDocumentRevision.current = documentRevision;
|
|
13478
13518
|
}
|
|
13479
13519
|
if (!editor || !editorMounted || editor.isDestroyed || !enabled || !client) {
|
|
@@ -13518,7 +13558,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
13518
13558
|
if (!enabled) {
|
|
13519
13559
|
measurementCache.current = null;
|
|
13520
13560
|
paginationCache.current = null;
|
|
13521
|
-
|
|
13561
|
+
measurementRange.reset();
|
|
13522
13562
|
}
|
|
13523
13563
|
setPagination(null);
|
|
13524
13564
|
return;
|
|
@@ -13586,143 +13626,155 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
13586
13626
|
editorDom.dataset.paginationReusedPageChrome = '0';
|
|
13587
13627
|
editorDom.dataset.paginationDerivedPageChrome = '0';
|
|
13588
13628
|
delete editorDom.dataset.paginationError;
|
|
13589
|
-
const
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
|
|
13602
|
-
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13629
|
+
const measurementPass = measurementRange.begin();
|
|
13630
|
+
const measurementStart = measurementPass.from;
|
|
13631
|
+
try {
|
|
13632
|
+
const textLayoutCollection = collectDocumentTextLayoutParagraphs(editor, layoutFonts, loadedLayoutFontIds, measurementCache.current, measurementStart);
|
|
13633
|
+
editorDom.dataset.paginationTextCandidates = String(textLayoutCollection.paragraphs.length);
|
|
13634
|
+
editorDom.dataset.paginationTextRuns = String(textLayoutCollection.paragraphs.reduce((count, paragraph)=>count + paragraph.runs.length, 0));
|
|
13635
|
+
const textLayouts = new Map();
|
|
13636
|
+
let fallbackGlyphCount = 0;
|
|
13637
|
+
if (textLayoutCollection.paragraphs.length) {
|
|
13638
|
+
editorDom.dataset.paginationState = 'shaping';
|
|
13639
|
+
try {
|
|
13640
|
+
let textLayoutEngine = '';
|
|
13641
|
+
let unsupportedTextLayoutCount = 0;
|
|
13642
|
+
const textLayoutBatches = documentTextLayoutBatches(textLayoutCollection.paragraphs);
|
|
13643
|
+
editorDom.dataset.paginationTextBatches = String(textLayoutBatches.length);
|
|
13644
|
+
for (const [batchIndex, paragraphs] of textLayoutBatches.entries()){
|
|
13645
|
+
editorDom.dataset.paginationTextBatch = String(batchIndex + 1);
|
|
13646
|
+
const textLayout = await client.textLayout({
|
|
13647
|
+
revision: nextRevision,
|
|
13648
|
+
documentRevision,
|
|
13649
|
+
paragraphs
|
|
13650
|
+
}, signal);
|
|
13651
|
+
if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed) return;
|
|
13652
|
+
textLayoutEngine ||= textLayout.engine;
|
|
13653
|
+
unsupportedTextLayoutCount += textLayout.unsupportedParagraphIds.length + textLayout.layouts.filter((layout)=>layout.missingGlyphCount > 0).length;
|
|
13654
|
+
for (const layout of textLayout.layouts)if (0 === layout.missingGlyphCount) {
|
|
13655
|
+
textLayouts.set(layout.id, layout);
|
|
13656
|
+
fallbackGlyphCount += layout.fallbackGlyphCount;
|
|
13657
|
+
}
|
|
13616
13658
|
}
|
|
13659
|
+
editorDom.dataset.paginationTextEngine = textLayoutEngine;
|
|
13660
|
+
editorDom.dataset.paginationUnsupportedText = String(unsupportedTextLayoutCount);
|
|
13661
|
+
} catch (error) {
|
|
13662
|
+
if (signal.aborted || error instanceof DOMException && 'AbortError' === error.name) return;
|
|
13663
|
+
textLayouts.clear();
|
|
13664
|
+
fallbackGlyphCount = 0;
|
|
13665
|
+
editorDom.dataset.paginationTextEngine = 'dom';
|
|
13666
|
+
editorDom.dataset.paginationUnsupportedText = String(textLayoutCollection.paragraphs.length);
|
|
13617
13667
|
}
|
|
13618
|
-
|
|
13619
|
-
editorDom.dataset.paginationUnsupportedText = String(unsupportedTextLayoutCount);
|
|
13620
|
-
} catch (error) {
|
|
13621
|
-
if (signal.aborted || error instanceof DOMException && 'AbortError' === error.name) return;
|
|
13622
|
-
textLayouts.clear();
|
|
13623
|
-
fallbackGlyphCount = 0;
|
|
13668
|
+
} else {
|
|
13624
13669
|
editorDom.dataset.paginationTextEngine = 'dom';
|
|
13625
|
-
editorDom.dataset.paginationUnsupportedText =
|
|
13670
|
+
editorDom.dataset.paginationUnsupportedText = '0';
|
|
13671
|
+
editorDom.dataset.paginationTextBatch = '0';
|
|
13672
|
+
editorDom.dataset.paginationTextBatches = '0';
|
|
13626
13673
|
}
|
|
13627
|
-
|
|
13628
|
-
editorDom.dataset.
|
|
13629
|
-
editorDom.dataset.
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
paginationCache.current
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13674
|
+
editorDom.dataset.paginationShapedParagraphs = String(textLayouts.size);
|
|
13675
|
+
editorDom.dataset.paginationFallbackGlyphs = String(fallbackGlyphCount);
|
|
13676
|
+
editorDom.dataset.paginationShapedRuns = String(textLayoutCollection.paragraphs.reduce((count, paragraph)=>count + (textLayouts.has(paragraph.id) ? paragraph.runs.length : 0), 0));
|
|
13677
|
+
const snapshot = await measureDocumentLayoutBlocksIncrementally(editor, measurementCache.current, measurementStart, textLayouts, 1000000, {
|
|
13678
|
+
signal
|
|
13679
|
+
});
|
|
13680
|
+
measurementCache.current = snapshot;
|
|
13681
|
+
editorDom.dataset.paginationBlocks = String(snapshot.blocks.length);
|
|
13682
|
+
editorDom.dataset.paginationFlows = String(new Set(snapshot.blocks.flatMap((block)=>block.block.flowId ? [
|
|
13683
|
+
block.block.flowId
|
|
13684
|
+
] : [])).size);
|
|
13685
|
+
editorDom.dataset.paginationMeasuredBlocks = String(snapshot.measuredBlockCount);
|
|
13686
|
+
editorDom.dataset.paginationReusedBlocks = String(snapshot.reusedBlockCount);
|
|
13687
|
+
if (snapshot.unsupportedLayout || !snapshot.blocks.length) {
|
|
13688
|
+
observeBlocks(snapshot.blocks);
|
|
13689
|
+
editorDom.dataset.paginationState = snapshot.unsupportedLayout ? 'unsupported' : 'empty';
|
|
13690
|
+
setPagination(null);
|
|
13691
|
+
paginationCache.current = null;
|
|
13692
|
+
measurementRange.commit(measurementPass);
|
|
13693
|
+
return;
|
|
13694
|
+
}
|
|
13695
|
+
const previousPagination = paginationCache.current;
|
|
13696
|
+
const layoutPlan = planIncrementalDocumentLayout(previousPagination, snapshot.blocks, measurementStart);
|
|
13697
|
+
editorDom.dataset.paginationLaidOutBlocks = String(layoutPlan.blocks.length);
|
|
13698
|
+
editorDom.dataset.paginationReusedPages = String(layoutPlan.reusedPageCount);
|
|
13699
|
+
try {
|
|
13700
|
+
editorDom.dataset.paginationState = 'layout';
|
|
13701
|
+
const partialLayout = await client.layout({
|
|
13702
|
+
revision: nextRevision,
|
|
13703
|
+
documentRevision,
|
|
13704
|
+
startPageIndex: layoutPlan.startPageIndex,
|
|
13705
|
+
page,
|
|
13706
|
+
pageStyles: snapshot.pageStyles,
|
|
13707
|
+
blocks: layoutPlan.blocks
|
|
13708
|
+
}, signal);
|
|
13709
|
+
if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed) return;
|
|
13710
|
+
const layout = previousPagination && layoutPlan.startPageIndex > 0 ? mergeIncrementalDocumentLayout(previousPagination.layout, partialLayout) : partialLayout;
|
|
13711
|
+
const blockById = new Map(snapshot.blocks.map((block)=>[
|
|
13712
|
+
block.block.id,
|
|
13713
|
+
block
|
|
13714
|
+
]));
|
|
13715
|
+
const pageDescriptorDerivation = deriveDocumentPaginationPageDescriptors(layout, snapshot.blocks, editor.state.doc, previousPagination?.pages, layoutPlan.reusedPageCount);
|
|
13716
|
+
const pages = pageDescriptorDerivation.pages;
|
|
13717
|
+
editorDom.dataset.paginationReusedPageChrome = String(pageDescriptorDerivation.reusedPageCount);
|
|
13718
|
+
editorDom.dataset.paginationDerivedPageChrome = String(pageDescriptorDerivation.derivedPageCount);
|
|
13719
|
+
const pageByIndex = new Map(pages.map((descriptor)=>[
|
|
13720
|
+
descriptor.pageIndex,
|
|
13721
|
+
descriptor
|
|
13722
|
+
]));
|
|
13723
|
+
editor.commands.applyDocumentPagination(nextRevision, layout.breaks.flatMap((pageBreak)=>{
|
|
13724
|
+
const block = blockById.get(pageBreak.beforeBlockId);
|
|
13725
|
+
return block ? [
|
|
13726
|
+
{
|
|
13727
|
+
...pageBreak,
|
|
13728
|
+
previousPage: pageByIndex.get(pageBreak.pageIndex - 1)?.page ?? layout.pages[pageBreak.pageIndex - 1]?.page ?? page,
|
|
13729
|
+
nextPage: pageByIndex.get(pageBreak.pageIndex)?.page ?? layout.pages[pageBreak.pageIndex]?.page ?? page,
|
|
13730
|
+
position: block.from,
|
|
13731
|
+
inlineOffsetLeft: block.inlineOffsetLeft,
|
|
13732
|
+
inlineOffsetRight: block.inlineOffsetRight,
|
|
13733
|
+
previousPageChrome: visualPageChrome(pageByIndex.get(pageBreak.pageIndex - 1)),
|
|
13734
|
+
nextPageChrome: visualPageChrome(pageByIndex.get(pageBreak.pageIndex)),
|
|
13735
|
+
tableBreak: block.tableBreak
|
|
13736
|
+
}
|
|
13737
|
+
] : [];
|
|
13738
|
+
}));
|
|
13739
|
+
observeBlocks(snapshot.blocks);
|
|
13740
|
+
editorDom.dataset.paginationEngine = layout.engine;
|
|
13741
|
+
editorDom.dataset.paginationDocumentRevision = String(layout.documentRevision);
|
|
13742
|
+
editorDom.dataset.paginationPages = String(layout.pages.length);
|
|
13743
|
+
editorDom.dataset.paginationState = 'ready';
|
|
13744
|
+
delete editorDom.dataset.paginationError;
|
|
13745
|
+
const nextPagination = {
|
|
13746
|
+
layout,
|
|
13747
|
+
blocks: snapshot.blocks,
|
|
13748
|
+
pages,
|
|
13749
|
+
pageByBlockId: new Map(layout.pages.flatMap((page)=>page.placements.map((placement)=>[
|
|
13750
|
+
placement.blockId,
|
|
13751
|
+
page.index + 1
|
|
13752
|
+
])))
|
|
13753
|
+
};
|
|
13754
|
+
paginationCache.current = nextPagination;
|
|
13755
|
+
measurementRange.commit(measurementPass);
|
|
13756
|
+
setPagination(nextPagination);
|
|
13757
|
+
} catch (error) {
|
|
13758
|
+
if (disposed || signal.aborted || error instanceof DOMException && 'AbortError' === error.name) return;
|
|
13759
|
+
editorDom.dataset.paginationState = 'error';
|
|
13760
|
+
editorDom.dataset.paginationError = error instanceof Error ? `${error.name}: ${error.message}` : 'UnknownError';
|
|
13761
|
+
editor.commands.clearDocumentPagination(nextRevision);
|
|
13762
|
+
paginationCache.current = null;
|
|
13763
|
+
setPagination(null);
|
|
13764
|
+
}
|
|
13765
|
+
} finally{
|
|
13766
|
+
measurementRange.restore(measurementPass);
|
|
13719
13767
|
}
|
|
13720
13768
|
};
|
|
13721
13769
|
const coordinator = createDocumentPaginationRunCoordinator({
|
|
13722
13770
|
cancelFrame: cancelAnimationFrame,
|
|
13723
|
-
onAbort: ()=>
|
|
13771
|
+
onAbort: ()=>{
|
|
13772
|
+
measurementRange.restoreActive();
|
|
13773
|
+
updateDiagnostic('aborts', 'paginationAborts');
|
|
13774
|
+
},
|
|
13724
13775
|
onCoalescedRequest: ()=>updateDiagnostic('coalescedRequests', 'paginationCoalescedRequests'),
|
|
13725
13776
|
onError: (error)=>{
|
|
13777
|
+
measurementRange.restoreActive();
|
|
13726
13778
|
if (disposed || editor.isDestroyed) return;
|
|
13727
13779
|
editorDom.dataset.paginationState = 'error';
|
|
13728
13780
|
editorDom.dataset.paginationError = error instanceof Error ? `${error.name}: ${error.message}` : 'UnknownError';
|
|
@@ -13745,7 +13797,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
13745
13797
|
});
|
|
13746
13798
|
};
|
|
13747
13799
|
const markDirty = (position)=>{
|
|
13748
|
-
|
|
13800
|
+
measurementRange.invalidate(position);
|
|
13749
13801
|
};
|
|
13750
13802
|
const handleDocumentUpdate = ({ transaction })=>{
|
|
13751
13803
|
updateDiagnostic('documentTriggers', 'paginationDocumentTriggers');
|
|
@@ -14029,7 +14081,10 @@ function pageMetricsKey(page) {
|
|
|
14029
14081
|
page.headerHeight,
|
|
14030
14082
|
page.footerHeight,
|
|
14031
14083
|
page.pageGap
|
|
14032
|
-
].join(':');
|
|
14084
|
+
].map(canonicalPageMetric).join(':');
|
|
14085
|
+
}
|
|
14086
|
+
function canonicalPageMetric(value) {
|
|
14087
|
+
return Math.round(1000000 * value) / 1000000;
|
|
14033
14088
|
}
|
|
14034
14089
|
function earliestChangedPosition(transaction) {
|
|
14035
14090
|
let earliest = 1 / 0;
|
package/dist/8928.js
CHANGED
|
@@ -7672,7 +7672,7 @@ function documentSectionNodeAttributes(layout, id) {
|
|
|
7672
7672
|
documentGridLinePitch: normalizedDocumentGrid(layout.documentGrid)?.linePitch ?? null
|
|
7673
7673
|
};
|
|
7674
7674
|
}
|
|
7675
|
-
function
|
|
7675
|
+
function work_document_section_documentSectionLayoutFromNodeAttributes(attributes, fallback) {
|
|
7676
7676
|
const base = fallback ?? {
|
|
7677
7677
|
pageSize: 'a4',
|
|
7678
7678
|
orientation: 'portrait',
|
|
@@ -7765,7 +7765,7 @@ function documentSectionDomAttributes(layout, id) {
|
|
|
7765
7765
|
};
|
|
7766
7766
|
}
|
|
7767
7767
|
function documentSectionLayoutFromElement(element, fallback) {
|
|
7768
|
-
return
|
|
7768
|
+
return work_document_section_documentSectionLayoutFromNodeAttributes({
|
|
7769
7769
|
pageSize: element.dataset.sectionPageSize,
|
|
7770
7770
|
orientation: element.dataset.sectionOrientation,
|
|
7771
7771
|
marginTop: numberValue(element.dataset.sectionMarginTop),
|
|
@@ -7911,7 +7911,7 @@ function activeDocumentSectionFromState(state) {
|
|
|
7911
7911
|
count: sections.length,
|
|
7912
7912
|
position,
|
|
7913
7913
|
node,
|
|
7914
|
-
layout:
|
|
7914
|
+
layout: work_document_section_documentSectionLayoutFromNodeAttributes(node.attrs)
|
|
7915
7915
|
};
|
|
7916
7916
|
}
|
|
7917
7917
|
function updateActiveDocumentSection(layout, commandContext) {
|
|
@@ -7933,7 +7933,7 @@ function updateDocumentSection(sectionId, layout, commandContext) {
|
|
|
7933
7933
|
const globals = documentPageMarginsForLayout(next);
|
|
7934
7934
|
for (const [index, candidate] of directDocumentSections(state.doc).entries()){
|
|
7935
7935
|
const id = documentSectionId(candidate.node, index);
|
|
7936
|
-
const current =
|
|
7936
|
+
const current = work_document_section_documentSectionLayoutFromNodeAttributes(candidate.node.attrs);
|
|
7937
7937
|
const synchronized = synchronizeDocumentPageMarginGlobals(id === sectionId ? next : current, globals);
|
|
7938
7938
|
commandContext.tr.setNodeMarkup(candidate.position, void 0, documentSectionNodeAttributes(synchronized, id));
|
|
7939
7939
|
}
|
|
@@ -8008,7 +8008,7 @@ function documentSectionByIdInDocument(document1, sectionId) {
|
|
|
8008
8008
|
count: sections.length,
|
|
8009
8009
|
position: section.position,
|
|
8010
8010
|
node: section.node,
|
|
8011
|
-
layout:
|
|
8011
|
+
layout: work_document_section_documentSectionLayoutFromNodeAttributes(section.node.attrs)
|
|
8012
8012
|
};
|
|
8013
8013
|
}
|
|
8014
8014
|
function directDocumentSections(document1) {
|
|
@@ -12967,30 +12967,37 @@ function sanitizeRepeatedDocumentTableElement(clone) {
|
|
|
12967
12967
|
pageBreak.remove();
|
|
12968
12968
|
});
|
|
12969
12969
|
}
|
|
12970
|
-
|
|
12970
|
+
const DOCUMENT_LAYOUT_MEASUREMENT_SLICE_MS = 32;
|
|
12971
|
+
async function measureDocumentLayoutBlocksIncrementally(editor, previous = null, dirtyFrom = 0, textLayouts = new Map(), maximumFragmentedTableRowHeight = 1000000, options = {}) {
|
|
12971
12972
|
const blocks = [];
|
|
12972
12973
|
const pageStyleByMetrics = new Map();
|
|
12973
12974
|
const counts = {
|
|
12974
12975
|
measured: 0,
|
|
12975
12976
|
reused: 0
|
|
12976
12977
|
};
|
|
12978
|
+
const checkpoint = options.checkpoint ?? createDocumentLayoutMeasurementCheckpoint();
|
|
12979
|
+
throwIfDocumentMeasurementAborted(options.signal);
|
|
12977
12980
|
let unsupportedLayout = false;
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
const
|
|
12981
|
-
if (
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
pageStyle =
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12981
|
+
let sectionPosition = 0;
|
|
12982
|
+
for(let sectionIndex = 0; sectionIndex < editor.state.doc.childCount; sectionIndex += 1){
|
|
12983
|
+
const section = editor.state.doc.child(sectionIndex);
|
|
12984
|
+
if ('documentSection' === section.type.name) {
|
|
12985
|
+
const layout = work_document_section_documentSectionLayoutFromNodeAttributes(section.attrs);
|
|
12986
|
+
if (layout.columns.count > 1) unsupportedLayout = true;
|
|
12987
|
+
const page = documentPageMetrics(layout);
|
|
12988
|
+
const metricsKey = documentPageMetricsKey(page);
|
|
12989
|
+
let pageStyle = pageStyleByMetrics.get(metricsKey);
|
|
12990
|
+
if (!pageStyle) {
|
|
12991
|
+
pageStyle = {
|
|
12992
|
+
id: `document-page-style-${pageStyleByMetrics.size + 1}`,
|
|
12993
|
+
page
|
|
12994
|
+
};
|
|
12995
|
+
pageStyleByMetrics.set(metricsKey, pageStyle);
|
|
12996
|
+
}
|
|
12997
|
+
await measureSectionBlocksIncrementally(editor, section, sectionPosition, sectionIndex, layout, pageStyle, previous?.blocks ?? [], dirtyFrom, textLayouts, Math.min(maximumFragmentedTableRowHeight, documentPageBodyHeight(pageStyle.page)), counts, blocks, checkpoint, options.signal);
|
|
12991
12998
|
}
|
|
12992
|
-
|
|
12993
|
-
}
|
|
12999
|
+
sectionPosition += section.nodeSize;
|
|
13000
|
+
}
|
|
12994
13001
|
return {
|
|
12995
13002
|
blocks,
|
|
12996
13003
|
pageStyles: [
|
|
@@ -13022,63 +13029,74 @@ function documentPageMetrics(layout, physicalPage = 1) {
|
|
|
13022
13029
|
function documentPageBodyHeight(page) {
|
|
13023
13030
|
return Math.max(1, page.height - page.marginTop - page.marginBottom);
|
|
13024
13031
|
}
|
|
13025
|
-
function
|
|
13032
|
+
async function measureSectionBlocksIncrementally(editor, section, sectionPosition, sectionIndex, layout, pageStyle, previous, dirtyFrom, textLayouts, maximumFragmentedTableRowHeight, counts, result, checkpoint, signal) {
|
|
13026
13033
|
const sectionBlocks = [];
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
const
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
}
|
|
13046
|
-
}
|
|
13047
|
-
const reused = reusableDocumentLayoutBlocks(previous, id, element, position + node.nodeSize, dirtyFrom);
|
|
13034
|
+
let offset = 0;
|
|
13035
|
+
for(let index = 0; index < section.childCount; index += 1){
|
|
13036
|
+
await checkpoint(signal);
|
|
13037
|
+
throwIfDocumentMeasurementAborted(signal);
|
|
13038
|
+
const node = section.child(index);
|
|
13039
|
+
measureSectionBlock(editor, node, offset, index, sectionPosition, previous, dirtyFrom, textLayouts, maximumFragmentedTableRowHeight, counts, sectionBlocks);
|
|
13040
|
+
offset += node.nodeSize;
|
|
13041
|
+
}
|
|
13042
|
+
finishMeasuredSection(section, sectionPosition, sectionIndex, layout, pageStyle, sectionBlocks, result);
|
|
13043
|
+
}
|
|
13044
|
+
function measureSectionBlock(editor, node, offset, index, sectionPosition, previous, dirtyFrom, textLayouts, maximumFragmentedTableRowHeight, counts, sectionBlocks) {
|
|
13045
|
+
const position = sectionPosition + offset + 1;
|
|
13046
|
+
const element = elementForNode(editor, position);
|
|
13047
|
+
if (!element) return;
|
|
13048
|
+
const id = documentBlockId(sectionPosition, index, position);
|
|
13049
|
+
const paragraphPagination = documentNodeParagraphPagination(node);
|
|
13050
|
+
if (isDocumentListNode(node)) {
|
|
13051
|
+
const reused = reusableDocumentListLayoutBlocks(previous, id, position + node.nodeSize, dirtyFrom);
|
|
13048
13052
|
if (reused.length) {
|
|
13049
13053
|
counts.reused += reused.length;
|
|
13050
13054
|
sectionBlocks.push(...reused);
|
|
13051
13055
|
return;
|
|
13052
13056
|
}
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
return;
|
|
13059
|
-
}
|
|
13057
|
+
const listBlocks = measureDocumentListBlocks(editor, node, element, id, position, textLayouts, maximumFragmentedTableRowHeight);
|
|
13058
|
+
if (listBlocks.length) {
|
|
13059
|
+
counts.measured += listBlocks.length;
|
|
13060
|
+
sectionBlocks.push(...listBlocks);
|
|
13061
|
+
return;
|
|
13060
13062
|
}
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13063
|
+
}
|
|
13064
|
+
const reused = reusableDocumentLayoutBlocks(previous, id, element, position + node.nodeSize, dirtyFrom);
|
|
13065
|
+
if (reused.length) {
|
|
13066
|
+
counts.reused += reused.length;
|
|
13067
|
+
sectionBlocks.push(...reused);
|
|
13068
|
+
return;
|
|
13069
|
+
}
|
|
13070
|
+
if ('table' === node.type.name) {
|
|
13071
|
+
const tableRows = measureDocumentTableRows(editor, node, element, id, position, maximumFragmentedTableRowHeight);
|
|
13072
|
+
if (tableRows.length) {
|
|
13073
|
+
counts.measured += tableRows.length;
|
|
13074
|
+
sectionBlocks.push(...tableRows);
|
|
13065
13075
|
return;
|
|
13066
13076
|
}
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13077
|
+
}
|
|
13078
|
+
const lineFragments = measureParagraphLineFragments(editor, node, element, id, position, position + node.nodeSize, paragraphPagination, textLayouts.get(id));
|
|
13079
|
+
if (lineFragments.length > 1) {
|
|
13080
|
+
counts.measured += lineFragments.length;
|
|
13081
|
+
sectionBlocks.push(...lineFragments);
|
|
13082
|
+
return;
|
|
13083
|
+
}
|
|
13084
|
+
counts.measured += 1;
|
|
13085
|
+
sectionBlocks.push(measuredDocumentBlock({
|
|
13086
|
+
block: {
|
|
13087
|
+
id,
|
|
13088
|
+
height: documentBlockFlowHeight(node, element),
|
|
13089
|
+
breakBefore: paragraphPagination.pageBreakBefore,
|
|
13090
|
+
breakAfter: 'pageBreak' === node.type.name,
|
|
13091
|
+
keepTogether: paragraphPagination.keepLines || shouldKeepDocumentBlockTogether(node),
|
|
13092
|
+
keepWithNext: paragraphPagination.keepWithNext
|
|
13093
|
+
},
|
|
13094
|
+
element,
|
|
13095
|
+
from: position,
|
|
13096
|
+
to: position + node.nodeSize
|
|
13097
|
+
}));
|
|
13098
|
+
}
|
|
13099
|
+
function finishMeasuredSection(section, sectionPosition, sectionIndex, layout, pageStyle, sectionBlocks, result) {
|
|
13082
13100
|
const last = sectionBlocks.at(-1);
|
|
13083
13101
|
if (last && 'continuous' !== layout.breakAfter && 'nextColumn' !== layout.breakAfter) last.block.breakAfter = true;
|
|
13084
13102
|
const sectionMetadata = {
|
|
@@ -13095,6 +13113,41 @@ function measureSectionBlocks(editor, section, sectionPosition, sectionIndex, la
|
|
|
13095
13113
|
}
|
|
13096
13114
|
result.push(...sectionBlocks);
|
|
13097
13115
|
}
|
|
13116
|
+
function createDocumentLayoutMeasurementCheckpoint() {
|
|
13117
|
+
let deadline = documentMeasurementNow() + DOCUMENT_LAYOUT_MEASUREMENT_SLICE_MS;
|
|
13118
|
+
return async (signal)=>{
|
|
13119
|
+
throwIfDocumentMeasurementAborted(signal);
|
|
13120
|
+
if (documentMeasurementNow() < deadline) return;
|
|
13121
|
+
await yieldDocumentMeasurement();
|
|
13122
|
+
throwIfDocumentMeasurementAborted(signal);
|
|
13123
|
+
deadline = documentMeasurementNow() + DOCUMENT_LAYOUT_MEASUREMENT_SLICE_MS;
|
|
13124
|
+
};
|
|
13125
|
+
}
|
|
13126
|
+
function documentMeasurementNow() {
|
|
13127
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
13128
|
+
}
|
|
13129
|
+
function yieldDocumentMeasurement() {
|
|
13130
|
+
if ("u" > typeof MessageChannel) return new Promise((resolve)=>{
|
|
13131
|
+
const channel = new MessageChannel();
|
|
13132
|
+
channel.port1.addEventListener('message', ()=>{
|
|
13133
|
+
channel.port1.close();
|
|
13134
|
+
channel.port2.close();
|
|
13135
|
+
resolve();
|
|
13136
|
+
}, {
|
|
13137
|
+
once: true
|
|
13138
|
+
});
|
|
13139
|
+
channel.port1.start();
|
|
13140
|
+
channel.port2.postMessage(void 0);
|
|
13141
|
+
});
|
|
13142
|
+
return new Promise((resolve)=>globalThis.setTimeout(resolve, 0));
|
|
13143
|
+
}
|
|
13144
|
+
function throwIfDocumentMeasurementAborted(signal) {
|
|
13145
|
+
if (!signal?.aborted) return;
|
|
13146
|
+
if (signal.reason instanceof Error) throw signal.reason;
|
|
13147
|
+
const error = new Error('Document layout measurement was aborted');
|
|
13148
|
+
error.name = 'AbortError';
|
|
13149
|
+
throw error;
|
|
13150
|
+
}
|
|
13098
13151
|
function documentPageMetricsKey(page) {
|
|
13099
13152
|
return [
|
|
13100
13153
|
page.width,
|
|
@@ -13337,7 +13390,7 @@ const DocumentSection = core_Node.create({
|
|
|
13337
13390
|
];
|
|
13338
13391
|
},
|
|
13339
13392
|
renderHTML ({ node, HTMLAttributes }) {
|
|
13340
|
-
const layout =
|
|
13393
|
+
const layout = work_document_section_documentSectionLayoutFromNodeAttributes(node.attrs);
|
|
13341
13394
|
const id = 'string' == typeof node.attrs.id && node.attrs.id ? node.attrs.id : 'document-section';
|
|
13342
13395
|
const columns = layout.columns;
|
|
13343
13396
|
const page = documentPageMetrics(layout);
|
|
@@ -17415,4 +17468,4 @@ function capturePages(surface) {
|
|
|
17415
17468
|
width: surface.pageWidth
|
|
17416
17469
|
}));
|
|
17417
17470
|
}
|
|
17418
|
-
export { DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DEFAULT_DOCUMENT_TABLE_GEOMETRY, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_PAGE_MARGIN_KEYS, DOCUMENT_PARAGRAPH_BORDER_EDGES, DOCUMENT_PARAGRAPH_BORDER_STYLES, DOCUMENT_PARAGRAPH_SHADING_PATTERNS, DOCUMENT_TABLE_ROW_ID_ATTRIBUTE, DOCUMENT_TABLE_ROW_TEXT_ID_ATTRIBUTE, DOCUMENT_TABLE_STYLE_OPTIONS, DocumentEquation, DocumentImage, DocumentParagraphFormatting, DocumentParagraphIdentity, DocumentSubscript, DocumentSuperscript, DocumentTableRowIdentity, DocxThemePatchCollector, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, MAX_DOCUMENT_NUMBERING_START, activeDocumentBookmark, activeDocumentSection, activeDocumentTableStyle, applyDocumentImageCropToElement, applyDocumentImageIdentityToElement, applyDocumentImageLayerToElement, applyDocumentImageWrapContourToElement, applyDocumentPageGeometry, applyDocumentParagraphIdentityToElement, applyDocumentTableGeometryToElement, applyDocumentTableRowIdentityToElement, canChangeDocumentIndent, canInsertDocumentComment, canSetDocumentTableRowRepeatHeader, clampDocumentMargin, collectDocumentChanges, collectDocumentCommentAnchors, collectDocumentNotes, collectDocumentTextLayoutParagraphs, createDocumentBibliography, createDocumentEquationElement, createDocumentImageIdentityRegistry, createDocumentNoteElement, createDocumentParagraphIdentityRegistry, createWorkDocumentExtensions, createWorkDocumentModel, createWorkDocumentModelFromContent, createWorkOfficeDocumentCollaborationBinding as createOfficeDocumentCollaborationBinding, defaultDocumentImageWrapContour, documentAutoLineHeight, documentBookmarkNameExists, documentBookmarkReferenceInstruction, documentBulletListStyle, documentCaptionKind, documentCaptionLabel, documentCitationCount, documentCitationInstruction, documentCitationStyle, documentCitationStyleDetails, documentCitationTags, documentCitationTagsFromInstruction, documentCommentDraftRange, documentCommentViews, documentContentLayoutProperties, documentEquationFromElement, documentEquationText, documentImageCropFromElement, documentImageIdentityFromElement, documentImageLayerFromElement, documentImageLayoutFromElement, documentImageLayoutOptions, documentImagePositionFromElement, documentImageProperties, documentImageWrapContourFromElement, documentInitialSectionLayout, documentModelForContent, documentNoteKey, documentNoteKind, documentOrderedListState, documentPageBordersVisible, documentPageChromeLegacyFields, documentPageGeometryForLayout, documentPageHorizontalMarginTwips, documentPageMarginBody, documentPageMarginsForLayout, documentPageMetrics, documentParagraphBordersDomAttributes, documentParagraphDirection, documentParagraphIdentityFromElement, documentParagraphIndent, documentParagraphPagination, documentParagraphShadingDomAttributes, documentParagraphSpacing, documentParagraphTabStops, documentSectionById, documentSectionDomAttributes, documentSections, documentTabLeaderLabel, documentTableBordersFromElement, documentTableCellFormat, documentTableCellMarginOverridesFromElement, documentTableColumnPercentagesFromElement, documentTableGeometryFromElement, documentTableHorizontalAlignment, documentTableRowIdentityFromElement, documentTableRowOptions, documentTableSizing, documentTextLayoutBatches, documentWordLineHeightFactor, docxBookmarkReferenceTarget, docxDocumentFieldKind, editorDocumentBookmarkReferenceTargets, editorDocumentCaptionTargets, initializeWorkOfficeDocumentCollaboration as initializeOfficeDocumentCollaboration, isContourImageLayout, isDocumentParagraphArtBorderStyle, isValidDocumentCitationTag, materializeWorkDocumentContent,
|
|
17471
|
+
export { DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DEFAULT_DOCUMENT_TABLE_GEOMETRY, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_PAGE_MARGIN_KEYS, DOCUMENT_PARAGRAPH_BORDER_EDGES, DOCUMENT_PARAGRAPH_BORDER_STYLES, DOCUMENT_PARAGRAPH_SHADING_PATTERNS, DOCUMENT_TABLE_ROW_ID_ATTRIBUTE, DOCUMENT_TABLE_ROW_TEXT_ID_ATTRIBUTE, DOCUMENT_TABLE_STYLE_OPTIONS, DocumentEquation, DocumentImage, DocumentParagraphFormatting, DocumentParagraphIdentity, DocumentSubscript, DocumentSuperscript, DocumentTableRowIdentity, DocxThemePatchCollector, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, MAX_DOCUMENT_NUMBERING_START, activeDocumentBookmark, activeDocumentSection, activeDocumentTableStyle, applyDocumentImageCropToElement, applyDocumentImageIdentityToElement, applyDocumentImageLayerToElement, applyDocumentImageWrapContourToElement, applyDocumentPageGeometry, applyDocumentParagraphIdentityToElement, applyDocumentTableGeometryToElement, applyDocumentTableRowIdentityToElement, canChangeDocumentIndent, canInsertDocumentComment, canSetDocumentTableRowRepeatHeader, clampDocumentMargin, collectDocumentChanges, collectDocumentCommentAnchors, collectDocumentNotes, collectDocumentTextLayoutParagraphs, createDocumentBibliography, createDocumentEquationElement, createDocumentImageIdentityRegistry, createDocumentNoteElement, createDocumentParagraphIdentityRegistry, createWorkDocumentExtensions, createWorkDocumentModel, createWorkDocumentModelFromContent, createWorkOfficeDocumentCollaborationBinding as createOfficeDocumentCollaborationBinding, defaultDocumentImageWrapContour, documentAutoLineHeight, documentBookmarkNameExists, documentBookmarkReferenceInstruction, documentBulletListStyle, documentCaptionKind, documentCaptionLabel, documentCitationCount, documentCitationInstruction, documentCitationStyle, documentCitationStyleDetails, documentCitationTags, documentCitationTagsFromInstruction, documentCommentDraftRange, documentCommentViews, documentContentLayoutProperties, documentEquationFromElement, documentEquationText, documentImageCropFromElement, documentImageIdentityFromElement, documentImageLayerFromElement, documentImageLayoutFromElement, documentImageLayoutOptions, documentImagePositionFromElement, documentImageProperties, documentImageWrapContourFromElement, documentInitialSectionLayout, documentModelForContent, documentNoteKey, documentNoteKind, documentOrderedListState, documentPageBordersVisible, documentPageChromeLegacyFields, documentPageGeometryForLayout, documentPageHorizontalMarginTwips, documentPageMarginBody, documentPageMarginsForLayout, documentPageMetrics, documentParagraphBordersDomAttributes, documentParagraphDirection, documentParagraphIdentityFromElement, documentParagraphIndent, documentParagraphPagination, documentParagraphShadingDomAttributes, documentParagraphSpacing, documentParagraphTabStops, documentSectionById, documentSectionDomAttributes, documentSections, documentTabLeaderLabel, documentTableBordersFromElement, documentTableCellFormat, documentTableCellMarginOverridesFromElement, documentTableColumnPercentagesFromElement, documentTableGeometryFromElement, documentTableHorizontalAlignment, documentTableRowIdentityFromElement, documentTableRowOptions, documentTableSizing, documentTextLayoutBatches, documentWordLineHeightFactor, docxBookmarkReferenceTarget, docxDocumentFieldKind, editorDocumentBookmarkReferenceTargets, editorDocumentCaptionTargets, initializeWorkOfficeDocumentCollaboration as initializeOfficeDocumentCollaboration, isContourImageLayout, isDocumentParagraphArtBorderStyle, isValidDocumentCitationTag, materializeWorkDocumentContent, measureDocumentLayoutBlocksIncrementally, millimetersToPixels, mountWorkLiveDocumentCapture, nextDocumentTabAlignment, normalizeDocumentBookmarkName, normalizeDocumentBookmarkNativeId, normalizeDocumentBookmarkReferencesHtml, normalizeDocumentBookmarksHtml, normalizeDocumentCaptionsHtml, normalizeDocumentCitationsHtml, normalizeDocumentColumns, normalizeDocumentEquation, normalizeDocumentFieldsHtml, normalizeDocumentHtml, normalizeDocumentImageAlignment, normalizeDocumentImageCrop, normalizeDocumentImageIdentity, normalizeDocumentImageLayer, normalizeDocumentImageLayoutOptions, normalizeDocumentImagePosition, normalizeDocumentImageWrapContour, normalizeDocumentImageWrapSide, normalizeDocumentNotesHtml, normalizeDocumentPageBorders, normalizeDocumentPageChrome, normalizeDocumentPageGeometry, normalizeDocumentPageMargins, normalizeDocumentPaperSource, normalizeDocumentParagraphBorder, normalizeDocumentParagraphBorders, normalizeDocumentParagraphId, normalizeDocumentParagraphIdentity, normalizeDocumentParagraphIndent, normalizeDocumentTabStops, normalizeDocumentTableBorderStyle, normalizeDocumentTableBorderWidth, normalizeDocumentTableRowHeightRule, normalizeDocumentTableRowIdentity, normalizeDocumentTableVerticalAlign, normalizeTableColor, normalizedTabPosition, pageTwipsToMillimeters, parseDocumentParagraphBordersElement, parseDocumentParagraphShadingElement, parseDocxThemeReference, patchDocxThemeReferences, positionWorkLiveDocumentCapture, readWorkOfficeDocumentCollaboration as readOfficeDocumentCollaboration, renderDocumentAutoLineHeight, renderDocumentTableBorders, renderDocumentTableCellMarginOverrides, resolveDocumentPageBorders, resolveDocumentPageChrome, resolveDocumentPageMargins, resolveDocumentPageSize, resolveWorkDocumentEditorInput, retainAnchoredDocumentComments, sanitizeDocumentPageChromeHtml, serializeDocumentTabStops, serializeDocxThemeReference, serializeWorkDocumentNode, setCustomDocumentColumns, supportedDocxBookmarkReferenceInstruction, syncDocumentContentFromHtml, uniqueDocumentImageIdentity, uniqueDocumentParagraphIdentity, updateDocumentColumnWidth, updateDocumentCustomPageMillimeters, updateDocumentGutterPosition, updateDocumentMirrorMargins, updateDocumentPageChromeVariant, updateDocumentPageMarginMillimeters, updateDocumentPageMarginMode, updateDocumentPageOrientation, updateDocumentPaperSizePreset, validateDocumentBookmarkName, workDocumentSchema, workOfficeDocumentCollaborationFragment as officeDocumentCollaborationFragment, work_document_page_margins_twipsToMillimeters, wrapsBesideImage };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface DocumentPaginationMeasurementPass {
|
|
2
|
+
readonly from: number;
|
|
3
|
+
}
|
|
4
|
+
export interface DocumentPaginationMeasurementRange {
|
|
5
|
+
begin: () => DocumentPaginationMeasurementPass;
|
|
6
|
+
commit: (pass: DocumentPaginationMeasurementPass) => void;
|
|
7
|
+
ensureDirty: () => void;
|
|
8
|
+
invalidate: (position: number) => void;
|
|
9
|
+
reset: () => void;
|
|
10
|
+
restore: (pass: DocumentPaginationMeasurementPass) => void;
|
|
11
|
+
restoreActive: () => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Tracks the earliest document position that the next pagination pass must
|
|
15
|
+
* measure. An active pass consumes that position temporarily, then either
|
|
16
|
+
* commits it or restores it when cooperative work is aborted.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createDocumentPaginationMeasurementRange(): DocumentPaginationMeasurementRange;
|
|
@@ -2,7 +2,18 @@ import type { Editor } from '@tiptap/core';
|
|
|
2
2
|
import type { OfficeKernelPageMetrics, OfficeKernelTextLayoutParagraphResult } from '../../kernel/office-kernel-protocol';
|
|
3
3
|
import type { DocumentPaginationSnapshot } from './work-document-pagination-types';
|
|
4
4
|
import type { WorkDocumentSectionLayout } from './work-types';
|
|
5
|
+
export interface IncrementalDocumentLayoutMeasurementOptions {
|
|
6
|
+
checkpoint?: (signal?: AbortSignal) => Promise<void>;
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
}
|
|
5
9
|
export declare function measureDocumentLayoutBlocks(editor: Editor, previous?: DocumentPaginationSnapshot | null, dirtyFrom?: number, textLayouts?: ReadonlyMap<string, OfficeKernelTextLayoutParagraphResult>, maximumFragmentedTableRowHeight?: number): DocumentPaginationSnapshot;
|
|
10
|
+
/**
|
|
11
|
+
* Measures the same canonical editor DOM as `measureDocumentLayoutBlocks`
|
|
12
|
+
* while yielding between top-level blocks. The browser keeps input, media,
|
|
13
|
+
* and animation tasks schedulable during large-document pagination without
|
|
14
|
+
* weakening the layout result or replacing the controlled editor model.
|
|
15
|
+
*/
|
|
16
|
+
export declare function measureDocumentLayoutBlocksIncrementally(editor: Editor, previous?: DocumentPaginationSnapshot | null, dirtyFrom?: number, textLayouts?: ReadonlyMap<string, OfficeKernelTextLayoutParagraphResult>, maximumFragmentedTableRowHeight?: number, options?: IncrementalDocumentLayoutMeasurementOptions): Promise<DocumentPaginationSnapshot>;
|
|
6
17
|
export declare function documentPageMetrics(layout: WorkDocumentSectionLayout, physicalPage?: number): OfficeKernelPageMetrics;
|
|
7
18
|
export declare function documentPageBodyHeight(page: OfficeKernelPageMetrics): number;
|
|
8
19
|
export declare function documentPaginationSurfaceHeight(pageCount: number, page: OfficeKernelPageMetrics): number;
|
|
@@ -2,7 +2,8 @@ import { Extension } from '@tiptap/core';
|
|
|
2
2
|
import type { DocumentPaginationVisualBreak } from './work-document-pagination-types';
|
|
3
3
|
export { createDocumentLineFragments, createShapedDocumentLineFragments, findDocumentLineStartOffset, } from './work-document-line-measurement';
|
|
4
4
|
export { reusableDocumentLayoutBlocks } from './work-document-pagination-dom';
|
|
5
|
-
export { documentPageBodyHeight, documentPageMetrics, documentPaginationSurfaceHeight, measureDocumentLayoutBlocks, } from './work-document-pagination-measurement';
|
|
5
|
+
export { documentPageBodyHeight, documentPageMetrics, documentPaginationSurfaceHeight, measureDocumentLayoutBlocks, measureDocumentLayoutBlocksIncrementally, } from './work-document-pagination-measurement';
|
|
6
|
+
export type { IncrementalDocumentLayoutMeasurementOptions } from './work-document-pagination-measurement';
|
|
6
7
|
export type { DocumentPaginationSection, DocumentPaginationSnapshot, DocumentPaginationVisualBreak, DocumentPaginationVisualPageChrome, DocumentTableCellBoundary, DocumentTableCellFragmentMeasurement, DocumentTableCellPageBreak, DocumentTablePaginationBreak, DocumentTableRowFragmentPlan, DocumentTextLayoutCollection, MeasuredDocumentLayoutBlock, } from './work-document-pagination-types';
|
|
7
8
|
export { createDocumentTableRowFragmentPlan } from './work-document-table-pagination';
|
|
8
9
|
export { collectDocumentTextLayoutParagraphs, collectDocumentTextLayoutRuns, documentTextLayoutBatches, } from './work-document-text-layout';
|
package/dist/office-kernel.wasm
CHANGED
|
Binary file
|
|
@@ -844,6 +844,13 @@ text validation, UTF-16 offset mapping, shaping, and their tests live in
|
|
|
844
844
|
focused modules. This keeps the fallback and WASM paths independently
|
|
845
845
|
testable without duplicating their public protocol.
|
|
846
846
|
|
|
847
|
+
Live DOM measurement is cooperatively scheduled in bounded 32 ms slices. It
|
|
848
|
+
yields only between top-level ProseMirror blocks, so one block is always
|
|
849
|
+
measured atomically against its rendered element. Document invalidation aborts
|
|
850
|
+
the stale pass before it can replace the reusable snapshot, while the existing
|
|
851
|
+
single-flight coordinator coalesces one fresh run. The synchronous measurement
|
|
852
|
+
path remains available for deterministic callers and parity tests.
|
|
853
|
+
|
|
847
854
|
Layout requests carry a bounded, deduplicated page-style table and let each
|
|
848
855
|
measured block reference its section geometry. A geometry transition opens a
|
|
849
856
|
new physical page in both the JavaScript fallback and Rust/WASM kernel, and
|