@beyondwork/docx-react-component 1.0.109 → 1.0.111
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/package.json +1 -1
- package/src/api/public-types.ts +3 -0
- package/src/model/layout/page-graph-types.ts +33 -0
- package/src/model/layout/runtime-page-graph-types.ts +25 -0
- package/src/runtime/document-runtime.ts +46 -0
- package/src/runtime/geometry/adjacent-geometry-intake.ts +820 -15
- package/src/runtime/geometry/caret-geometry.ts +219 -7
- package/src/runtime/geometry/geometry-index.ts +52 -12
- package/src/runtime/geometry/object-handles.ts +42 -1
- package/src/runtime/layout/index.ts +3 -0
- package/src/runtime/layout/inert-layout-facet.ts +13 -0
- package/src/runtime/layout/layout-engine-instance.ts +233 -4
- package/src/runtime/layout/layout-engine-version.ts +47 -2
- package/src/runtime/layout/layout-facet-types.ts +3 -0
- package/src/runtime/layout/page-graph.ts +88 -7
- package/src/runtime/layout/paginated-layout-engine.ts +34 -0
- package/src/runtime/layout/project-block-fragments.ts +144 -1
- package/src/runtime/layout/public-facet.ts +228 -9
- package/src/runtime/layout/resolve-page-previews.ts +46 -8
- package/src/runtime/scopes/adjacent-geometry-evidence.ts +456 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +8 -0
- package/src/runtime/scopes/evidence.ts +16 -0
- package/src/runtime/scopes/index.ts +13 -0
- package/src/runtime/scopes/semantic-scope-types.ts +67 -0
- package/src/ui-tailwind/chrome-overlay/tw-table-split-row-carry-overlay.tsx +62 -0
- package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +104 -0
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +50 -5
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +27 -0
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +62 -0
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +1 -0
- package/src/README.md +0 -85
- package/src/api/README.md +0 -26
- package/src/api/v3/README.md +0 -91
- package/src/component-inventory.md +0 -99
- package/src/core/README.md +0 -10
- package/src/core/commands/README.md +0 -3
- package/src/core/schema/README.md +0 -3
- package/src/core/selection/README.md +0 -3
- package/src/core/state/README.md +0 -3
- package/src/io/README.md +0 -10
- package/src/io/export/README.md +0 -3
- package/src/io/normalize/README.md +0 -3
- package/src/io/ooxml/README.md +0 -3
- package/src/io/opc/README.md +0 -3
- package/src/model/README.md +0 -3
- package/src/preservation/README.md +0 -3
- package/src/review/README.md +0 -16
- package/src/review/store/README.md +0 -3
- package/src/runtime/README.md +0 -3
- package/src/ui/README.md +0 -30
- package/src/ui/comments/README.md +0 -3
- package/src/ui/compatibility/README.md +0 -3
- package/src/ui/editor-surface/README.md +0 -3
- package/src/ui/review/README.md +0 -3
- package/src/ui/status/README.md +0 -3
- package/src/ui/theme/README.md +0 -3
- package/src/ui/toolbar/README.md +0 -3
- package/src/ui-tailwind/debug/README.md +0 -22
- package/src/validation/README.md +0 -3
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
buildPageStackFromWithSplits,
|
|
50
50
|
buildPageStackWithSplits,
|
|
51
51
|
type LayoutInvalidationReason,
|
|
52
|
+
type PageStackPaginationOptions,
|
|
52
53
|
} from "./paginated-layout-engine.ts";
|
|
53
54
|
import {
|
|
54
55
|
buildPageGraph,
|
|
@@ -102,6 +103,21 @@ export interface LayoutEngineViewState {
|
|
|
102
103
|
export interface LayoutEngineQueryInput {
|
|
103
104
|
document: CanonicalDocumentEnvelope;
|
|
104
105
|
viewState?: LayoutEngineViewState;
|
|
106
|
+
/**
|
|
107
|
+
* Optional page window for lazy pagination. L04 materializes this window
|
|
108
|
+
* plus its buffer and returns `unpaginated` placeholders for known pages
|
|
109
|
+
* outside it.
|
|
110
|
+
*/
|
|
111
|
+
viewportPageWindow?: LayoutViewportPageWindow;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface LayoutViewportPageWindow {
|
|
115
|
+
startPageIndex: number;
|
|
116
|
+
endPageIndex: number;
|
|
117
|
+
/** Extra pages to materialize before/after the requested window. */
|
|
118
|
+
bufferPages?: number;
|
|
119
|
+
/** Optional total page estimate supplied by the viewport/runtime layer. */
|
|
120
|
+
estimatedPageCount?: number;
|
|
105
121
|
}
|
|
106
122
|
|
|
107
123
|
export interface LayoutEngineEvent {
|
|
@@ -227,9 +243,206 @@ interface CacheKey {
|
|
|
227
243
|
content: CanonicalDocumentEnvelope["content"];
|
|
228
244
|
styles: CanonicalDocumentEnvelope["styles"];
|
|
229
245
|
subParts: CanonicalDocumentEnvelope["subParts"];
|
|
246
|
+
viewportWindowKey: string;
|
|
230
247
|
// Note: view state does not invalidate the graph itself (graph is global).
|
|
231
248
|
}
|
|
232
249
|
|
|
250
|
+
interface NormalizedViewportPageWindow {
|
|
251
|
+
startPageIndex: number;
|
|
252
|
+
endPageIndex: number;
|
|
253
|
+
estimatedPageCount?: number;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const FULL_VIEWPORT_WINDOW_KEY = "full";
|
|
257
|
+
const DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER = 1;
|
|
258
|
+
|
|
259
|
+
function normalizeViewportPageWindow(
|
|
260
|
+
window: LayoutViewportPageWindow | undefined,
|
|
261
|
+
): NormalizedViewportPageWindow | undefined {
|
|
262
|
+
if (!window) return undefined;
|
|
263
|
+
const buffer = Number.isFinite(window.bufferPages)
|
|
264
|
+
? Math.max(0, Math.floor(window.bufferPages ?? 0))
|
|
265
|
+
: DEFAULT_VIEWPORT_PAGE_WINDOW_BUFFER;
|
|
266
|
+
const rawStart = Number.isFinite(window.startPageIndex)
|
|
267
|
+
? Math.floor(window.startPageIndex)
|
|
268
|
+
: 0;
|
|
269
|
+
const rawEnd = Number.isFinite(window.endPageIndex)
|
|
270
|
+
? Math.floor(window.endPageIndex)
|
|
271
|
+
: rawStart;
|
|
272
|
+
const startPageIndex = Math.max(0, Math.min(rawStart, rawEnd) - buffer);
|
|
273
|
+
const endPageIndex = Math.max(
|
|
274
|
+
startPageIndex,
|
|
275
|
+
Math.max(rawStart, rawEnd) + buffer,
|
|
276
|
+
);
|
|
277
|
+
const estimatedPageCount =
|
|
278
|
+
window.estimatedPageCount !== undefined && Number.isFinite(window.estimatedPageCount)
|
|
279
|
+
? Math.max(0, Math.floor(window.estimatedPageCount))
|
|
280
|
+
: undefined;
|
|
281
|
+
return {
|
|
282
|
+
startPageIndex,
|
|
283
|
+
endPageIndex,
|
|
284
|
+
...(estimatedPageCount !== undefined ? { estimatedPageCount } : {}),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function viewportWindowKey(
|
|
289
|
+
window: NormalizedViewportPageWindow | undefined,
|
|
290
|
+
): string {
|
|
291
|
+
if (!window) return FULL_VIEWPORT_WINDOW_KEY;
|
|
292
|
+
return [
|
|
293
|
+
"window",
|
|
294
|
+
window.startPageIndex,
|
|
295
|
+
window.endPageIndex,
|
|
296
|
+
window.estimatedPageCount ?? "unknown",
|
|
297
|
+
].join(":");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function pageStackOptionsForWindow(
|
|
301
|
+
window: NormalizedViewportPageWindow | undefined,
|
|
302
|
+
): PageStackPaginationOptions | undefined {
|
|
303
|
+
if (!window) return undefined;
|
|
304
|
+
return { maxPageCount: window.endPageIndex + 1 };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function applyViewportWindowMaterialization(
|
|
308
|
+
graph: RuntimePageGraph,
|
|
309
|
+
window: NormalizedViewportPageWindow | undefined,
|
|
310
|
+
priorGraph: RuntimePageGraph | null,
|
|
311
|
+
): RuntimePageGraph {
|
|
312
|
+
if (!window) {
|
|
313
|
+
return graph.materialization?.kind === "complete"
|
|
314
|
+
? graph
|
|
315
|
+
: { ...graph, materialization: { kind: "complete" } };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const estimatedPageCount = Math.max(
|
|
319
|
+
graph.pages.length,
|
|
320
|
+
window.endPageIndex + 1,
|
|
321
|
+
window.estimatedPageCount ?? 0,
|
|
322
|
+
priorGraph?.pages.length ?? 0,
|
|
323
|
+
);
|
|
324
|
+
const hiddenPageIds = new Set<string>();
|
|
325
|
+
const pages: RuntimePageNode[] = graph.pages.map((page) => {
|
|
326
|
+
const materialized =
|
|
327
|
+
page.pageIndex >= window.startPageIndex &&
|
|
328
|
+
page.pageIndex <= window.endPageIndex;
|
|
329
|
+
if (materialized) {
|
|
330
|
+
return { ...page, materialization: "paginated" };
|
|
331
|
+
}
|
|
332
|
+
hiddenPageIds.add(page.pageId);
|
|
333
|
+
return toUnpaginatedPlaceholder(page);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const seed = pages[pages.length - 1] ?? graph.pages[graph.pages.length - 1];
|
|
337
|
+
if (seed) {
|
|
338
|
+
for (let pageIndex = pages.length; pageIndex < estimatedPageCount; pageIndex += 1) {
|
|
339
|
+
const placeholder = createTrailingUnpaginatedPlaceholder(
|
|
340
|
+
graph.revision,
|
|
341
|
+
pageIndex,
|
|
342
|
+
seed,
|
|
343
|
+
);
|
|
344
|
+
hiddenPageIds.add(placeholder.pageId);
|
|
345
|
+
pages.push(placeholder);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const fragments = graph.fragments.filter((fragment) => !hiddenPageIds.has(fragment.pageId));
|
|
350
|
+
const anchors = graph.anchors.filter((anchor) => !hiddenPageIds.has(anchor.pageId));
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
...graph,
|
|
354
|
+
pages,
|
|
355
|
+
fragments,
|
|
356
|
+
anchors,
|
|
357
|
+
contentPageCount: pages.filter((page) => !page.isBlankFiller).length,
|
|
358
|
+
materialization: {
|
|
359
|
+
kind: "viewport-window",
|
|
360
|
+
requestedWindow: {
|
|
361
|
+
startPageIndex: window.startPageIndex,
|
|
362
|
+
endPageIndex: window.endPageIndex,
|
|
363
|
+
},
|
|
364
|
+
paginatedRange: {
|
|
365
|
+
startPageIndex: window.startPageIndex,
|
|
366
|
+
endPageIndex: Math.min(window.endPageIndex, Math.max(0, graph.pages.length - 1)),
|
|
367
|
+
},
|
|
368
|
+
estimatedPageCount,
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function toUnpaginatedPlaceholder(page: RuntimePageNode): RuntimePageNode {
|
|
374
|
+
const { frame: _frame, divergences: _divergences, ...rest } = page;
|
|
375
|
+
void _frame;
|
|
376
|
+
void _divergences;
|
|
377
|
+
return {
|
|
378
|
+
...rest,
|
|
379
|
+
regions: buildUnpaginatedRegions(page.layout),
|
|
380
|
+
lineBoxes: [],
|
|
381
|
+
noteAllocations: [],
|
|
382
|
+
materialization: "unpaginated",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function createTrailingUnpaginatedPlaceholder(
|
|
387
|
+
revision: number,
|
|
388
|
+
pageIndex: number,
|
|
389
|
+
seed: RuntimePageNode,
|
|
390
|
+
): RuntimePageNode {
|
|
391
|
+
const displayPageNumber =
|
|
392
|
+
seed.stories.displayPageNumber + Math.max(0, pageIndex - seed.pageIndex);
|
|
393
|
+
return {
|
|
394
|
+
pageId: `page-${revision}-${pageIndex}`,
|
|
395
|
+
pageIndex,
|
|
396
|
+
sectionIndex: seed.sectionIndex,
|
|
397
|
+
pageInSection:
|
|
398
|
+
seed.pageInSection >= 0
|
|
399
|
+
? seed.pageInSection + Math.max(0, pageIndex - seed.pageIndex)
|
|
400
|
+
: pageIndex,
|
|
401
|
+
startOffset: seed.endOffset,
|
|
402
|
+
endOffset: seed.endOffset,
|
|
403
|
+
layout: seed.layout,
|
|
404
|
+
stories: {
|
|
405
|
+
...seed.stories,
|
|
406
|
+
isFirstPage: false,
|
|
407
|
+
isEvenPage: displayPageNumber % 2 === 0,
|
|
408
|
+
displayPageNumber,
|
|
409
|
+
},
|
|
410
|
+
regions: buildUnpaginatedRegions(seed.layout),
|
|
411
|
+
lineBoxes: [],
|
|
412
|
+
noteAllocations: [],
|
|
413
|
+
isBlankFiller: false,
|
|
414
|
+
materialization: "unpaginated",
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function buildUnpaginatedRegions(
|
|
419
|
+
layout: PageLayoutSnapshot,
|
|
420
|
+
): RuntimePageNode["regions"] {
|
|
421
|
+
const bodyWidth = Math.max(
|
|
422
|
+
0,
|
|
423
|
+
layout.pageWidth - layout.marginLeft - layout.marginRight - layout.gutter,
|
|
424
|
+
);
|
|
425
|
+
const bodyHeight = Math.max(
|
|
426
|
+
0,
|
|
427
|
+
layout.pageHeight - layout.marginTop - layout.marginBottom,
|
|
428
|
+
);
|
|
429
|
+
return {
|
|
430
|
+
body: {
|
|
431
|
+
kind: "body",
|
|
432
|
+
originTwips: layout.marginTop,
|
|
433
|
+
widthTwips: bodyWidth,
|
|
434
|
+
heightTwips: bodyHeight,
|
|
435
|
+
fragmentIds: [],
|
|
436
|
+
rectTwips: {
|
|
437
|
+
xTwips: layout.marginLeft,
|
|
438
|
+
yTwips: layout.marginTop,
|
|
439
|
+
widthTwips: bodyWidth,
|
|
440
|
+
heightTwips: bodyHeight,
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
233
446
|
// ---------------------------------------------------------------------------
|
|
234
447
|
// Perf-probe helper (§6 E.7)
|
|
235
448
|
// ---------------------------------------------------------------------------
|
|
@@ -451,6 +664,7 @@ export function createLayoutEngine(
|
|
|
451
664
|
const recomputeStart = telemetryOn ? telemetryNow() : 0;
|
|
452
665
|
const pageCountBeforeRecompute = previousPageCount;
|
|
453
666
|
const document = input.document;
|
|
667
|
+
const viewportWindow = normalizeViewportPageWindow(input.viewportPageWindow);
|
|
454
668
|
const mainSurface = createEditorSurfaceSnapshot(
|
|
455
669
|
document,
|
|
456
670
|
createSelectionSnapshot(0, 0),
|
|
@@ -463,6 +677,7 @@ export function createLayoutEngine(
|
|
|
463
677
|
sections,
|
|
464
678
|
mainSurface,
|
|
465
679
|
measurementProvider,
|
|
680
|
+
pageStackOptionsForWindow(viewportWindow),
|
|
466
681
|
);
|
|
467
682
|
const pages = pageStack.pages;
|
|
468
683
|
const stories = resolvePageStories(pages);
|
|
@@ -478,6 +693,7 @@ export function createLayoutEngine(
|
|
|
478
693
|
pages,
|
|
479
694
|
bodyFragmentsByPageIndex,
|
|
480
695
|
pageStack.fragmentMeasurementsByPageIndex,
|
|
696
|
+
mainSurface,
|
|
481
697
|
);
|
|
482
698
|
// P8.1b — merge per-note fragments (regionKind: "footnote-area") into the
|
|
483
699
|
// main fragments map so buildPageGraph sees them alongside body fragments.
|
|
@@ -486,7 +702,7 @@ export function createLayoutEngine(
|
|
|
486
702
|
const existing = fragmentsByPageIndex.get(pageIndex) ?? [];
|
|
487
703
|
fragmentsByPageIndex.set(pageIndex, [...existing, ...noteFragments]);
|
|
488
704
|
}
|
|
489
|
-
const
|
|
705
|
+
const measuredGraph = buildPageGraph({
|
|
490
706
|
pages,
|
|
491
707
|
sections,
|
|
492
708
|
stories,
|
|
@@ -495,6 +711,11 @@ export function createLayoutEngine(
|
|
|
495
711
|
noteAllocationsByPageIndex: pageStack.noteAllocationsByPageIndex,
|
|
496
712
|
subParts: document.subParts,
|
|
497
713
|
});
|
|
714
|
+
const graph = applyViewportWindowMaterialization(
|
|
715
|
+
measuredGraph,
|
|
716
|
+
viewportWindow,
|
|
717
|
+
cachedGraph,
|
|
718
|
+
);
|
|
498
719
|
|
|
499
720
|
// Field dirtiness diff from previous graph
|
|
500
721
|
const dirtyFamilies = computeFieldDirtiness(cachedGraph, graph);
|
|
@@ -504,7 +725,7 @@ export function createLayoutEngine(
|
|
|
504
725
|
|
|
505
726
|
const formatting = buildResolvedFormattingState(document, mainSurface);
|
|
506
727
|
|
|
507
|
-
const currentPageCount =
|
|
728
|
+
const currentPageCount = graph.contentPageCount;
|
|
508
729
|
// Compute the delta only; `previousPageCount` is mutated AFTER all
|
|
509
730
|
// emits so every emission reads the pre-commit value through the
|
|
510
731
|
// `pageCountDelta` local. `incrementalRelayout` mirrors this order
|
|
@@ -520,6 +741,7 @@ export function createLayoutEngine(
|
|
|
520
741
|
content: document.content,
|
|
521
742
|
styles: document.styles,
|
|
522
743
|
subParts: document.subParts,
|
|
744
|
+
viewportWindowKey: viewportWindowKey(viewportWindow),
|
|
523
745
|
};
|
|
524
746
|
cachedGraph = graph;
|
|
525
747
|
cachedFormatting = formatting;
|
|
@@ -660,6 +882,7 @@ export function createLayoutEngine(
|
|
|
660
882
|
freshSnapshotsToRebuild,
|
|
661
883
|
freshBodyFragmentsByPageIndex,
|
|
662
884
|
freshResult.fragmentMeasurementsByPageIndex,
|
|
885
|
+
mainSurface,
|
|
663
886
|
);
|
|
664
887
|
// P8.1b — merge per-note fragments into the fresh fragments map.
|
|
665
888
|
const freshFragmentsByPageIndex = new Map(freshBodyFragmentsByPageIndex);
|
|
@@ -752,6 +975,7 @@ export function createLayoutEngine(
|
|
|
752
975
|
content: document.content,
|
|
753
976
|
styles: document.styles,
|
|
754
977
|
subParts: document.subParts,
|
|
978
|
+
viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY,
|
|
755
979
|
};
|
|
756
980
|
cachedGraph = splicedGraph;
|
|
757
981
|
cachedFormatting = formatting;
|
|
@@ -780,12 +1004,15 @@ export function createLayoutEngine(
|
|
|
780
1004
|
|
|
781
1005
|
function getGraphInternal(input: LayoutEngineQueryInput): RuntimePageGraph {
|
|
782
1006
|
const document = input.document;
|
|
1007
|
+
const normalizedWindow = normalizeViewportPageWindow(input.viewportPageWindow);
|
|
1008
|
+
const currentViewportWindowKey = viewportWindowKey(normalizedWindow);
|
|
783
1009
|
const keyEqual =
|
|
784
1010
|
cachedGraph !== null &&
|
|
785
1011
|
cachedKey !== null &&
|
|
786
1012
|
cachedKey.content === document.content &&
|
|
787
1013
|
cachedKey.styles === document.styles &&
|
|
788
|
-
cachedKey.subParts === document.subParts
|
|
1014
|
+
cachedKey.subParts === document.subParts &&
|
|
1015
|
+
cachedKey.viewportWindowKey === currentViewportWindowKey;
|
|
789
1016
|
|
|
790
1017
|
if (keyEqual && pendingInvalidation === null) {
|
|
791
1018
|
return cachedGraph!;
|
|
@@ -797,7 +1024,8 @@ export function createLayoutEngine(
|
|
|
797
1024
|
if (
|
|
798
1025
|
pending !== null &&
|
|
799
1026
|
pending.result.scope === "bounded" &&
|
|
800
|
-
cachedGraph !== null
|
|
1027
|
+
cachedGraph !== null &&
|
|
1028
|
+
normalizedWindow === undefined
|
|
801
1029
|
) {
|
|
802
1030
|
const spliced = incrementalRelayout(input, pending);
|
|
803
1031
|
if (spliced !== null) {
|
|
@@ -1009,6 +1237,7 @@ export function createLayoutEngine(
|
|
|
1009
1237
|
content: document.content,
|
|
1010
1238
|
styles: document.styles,
|
|
1011
1239
|
subParts: document.subParts,
|
|
1240
|
+
viewportWindowKey: FULL_VIEWPORT_WINDOW_KEY,
|
|
1012
1241
|
};
|
|
1013
1242
|
previousPageCount = graph.contentPageCount;
|
|
1014
1243
|
},
|
|
@@ -1233,8 +1233,49 @@
|
|
|
1233
1233
|
* history-block bumped to v81 in isolation; ship-preview's rollup advances
|
|
1234
1234
|
* to v87. Cache envelopes from v86 invalidate because table row ranges and
|
|
1235
1235
|
* continuation cursor payloads can change.
|
|
1236
|
+
*
|
|
1237
|
+
* 88 — Ship-side rollup: pe2 commit 327244cee ("Add L04 lazy pagination
|
|
1238
|
+
* placeholders") landed L04 lazy pagination — layout queries can now pass
|
|
1239
|
+
* a viewport page window; windowed reads bound pagination by the requested
|
|
1240
|
+
* high-water page when possible and emit `unpaginated` page placeholders
|
|
1241
|
+
* outside the materialized range. Pe2 commits 378e1b9c6 ("feat(05): consume
|
|
1242
|
+
* numbering readback joins") + 64e64567f ("feat(05): project adjacent
|
|
1243
|
+
* geometry into l04 frames") additionally brushed `src/runtime/geometry/**`,
|
|
1244
|
+
* and pe2 commit d5597ed33 ("feat(11): consume field ledgers and split row
|
|
1245
|
+
* carry") brushed `src/runtime/layout/public-facet.ts` +
|
|
1246
|
+
* `resolve-page-previews.ts`, all without separate pe2 bumps. The pe2
|
|
1247
|
+
* history-block bumped to v82 in isolation; ship-preview's rollup advances
|
|
1248
|
+
* to v88. Cache envelopes from v87 invalidate because page graph
|
|
1249
|
+
* materialization state, cache-key semantics, geometry projections, and
|
|
1250
|
+
* surface preview shapes can change.
|
|
1251
|
+
*
|
|
1252
|
+
* 89 — Ship-side rollup: pe2 commit covering L04 pagination telemetry read
|
|
1253
|
+
* model — `WordReviewEditorLayoutFacet` now exposes
|
|
1254
|
+
* `getPaginationTelemetry()`, with per-page materialization, body-fragment
|
|
1255
|
+
* counts, body block-reference counts, line-box counts, and
|
|
1256
|
+
* materialized-page averages. Pagination output and cached graph payloads
|
|
1257
|
+
* are unchanged; cache envelopes from v88 invalidate because the public
|
|
1258
|
+
* layout facet interface grew a method used by viewport-window consumers.
|
|
1259
|
+
* The pe2 history-block bumped to v83 in isolation; ship-preview's rollup
|
|
1260
|
+
* advances to v89.
|
|
1261
|
+
*
|
|
1262
|
+
* 90 — Ship-side rollup: pe2 commit 2fcc15a10 ("feat(04): publish precision
|
|
1263
|
+
* producer layout facts") landed L04 precision producer facts — runtime
|
|
1264
|
+
* line boxes now carry page-local rects, baseline page coordinates,
|
|
1265
|
+
* paragraph direction, and per-run layout-estimate anchors with first/last
|
|
1266
|
+
* glyph bounds. Page-local anchored-object ledgers can carry
|
|
1267
|
+
* `anchorRectTwips` when canonical anchor metadata gives L04 a source/frame
|
|
1268
|
+
* placement. Pe2 commits a22c2e4ab ("feat(05): consume l04 producer
|
|
1269
|
+
* geometry facts") + 6e71ee2ad ("feat(05): publish frame-pixel adjacent
|
|
1270
|
+
* geometry") additionally brushed `src/runtime/geometry/**`, and pe2
|
|
1271
|
+
* commits 883e46bb7 + 8519112d0 ("fix(11): suppress table-internal page
|
|
1272
|
+
* chrome / anchors") brushed `src/runtime/layout/page-graph.ts` without
|
|
1273
|
+
* separate pe2 bumps. The pe2 history-block bumped to v84 in isolation;
|
|
1274
|
+
* ship-preview's rollup advances to v90. Pagination output is unchanged,
|
|
1275
|
+
* but public graph/read-model semantics grew for L05 exact caret/object
|
|
1276
|
+
* projection consumers and for L11 page-anchor suppression in tables.
|
|
1236
1277
|
*/
|
|
1237
|
-
export const LAYOUT_ENGINE_VERSION =
|
|
1278
|
+
export const LAYOUT_ENGINE_VERSION = 90 as const;
|
|
1238
1279
|
|
|
1239
1280
|
/**
|
|
1240
1281
|
* Serialization schema version for the LayCache envelope and cached payload
|
|
@@ -1275,5 +1316,9 @@ export const LAYOUT_ENGINE_VERSION = 87 as const;
|
|
|
1275
1316
|
* `numberingRows[]` for all numbered paragraphs represented by the
|
|
1276
1317
|
* fragment, including table/SDT-nested paragraphs. Pagination output is
|
|
1277
1318
|
* unchanged, but cached graph payload shape grows.
|
|
1319
|
+
* 7 — L04 precision producer graph payload: line boxes carry page-local
|
|
1320
|
+
* rect/baseline/direction/run-anchor facts, and page-local anchored
|
|
1321
|
+
* object ledgers can carry source-anchor `anchorRectTwips`. Pagination
|
|
1322
|
+
* output is unchanged, but cached graph payload shape grows.
|
|
1278
1323
|
*/
|
|
1279
|
-
export const LAYCACHE_SCHEMA_VERSION =
|
|
1324
|
+
export const LAYCACHE_SCHEMA_VERSION = 7 as const;
|
|
@@ -42,11 +42,14 @@ export type {
|
|
|
42
42
|
PublicRegionKind,
|
|
43
43
|
PublicBlockFragment,
|
|
44
44
|
PublicLineBox,
|
|
45
|
+
PublicLineRunAnchor,
|
|
45
46
|
PublicNoteAllocation,
|
|
46
47
|
PublicPageAnchor,
|
|
47
48
|
PublicPageFrame,
|
|
48
49
|
PublicPageLocalStoryInstance,
|
|
50
|
+
PublicPagePaginationTelemetry,
|
|
49
51
|
PublicPageSpan,
|
|
52
|
+
PublicPaginationTelemetry,
|
|
50
53
|
PublicSectionNode,
|
|
51
54
|
PublicResolvedPageStories,
|
|
52
55
|
PublicResolvedStoryField,
|
|
@@ -77,12 +77,16 @@ export type {
|
|
|
77
77
|
RuntimeFragmentLayoutObject,
|
|
78
78
|
RuntimeBlockFragment,
|
|
79
79
|
RuntimeLineBox,
|
|
80
|
+
RuntimeLineRunAnchor,
|
|
80
81
|
RuntimeNoteAllocation,
|
|
81
82
|
RuntimePageAnchor,
|
|
82
83
|
} from "../../model/layout/page-graph-types.ts";
|
|
83
84
|
|
|
84
85
|
export type {
|
|
85
86
|
RuntimePageGraph,
|
|
87
|
+
RuntimePageGraphMaterialization,
|
|
88
|
+
RuntimePageMaterialization,
|
|
89
|
+
RuntimePageWindowRange,
|
|
86
90
|
RuntimePageNode,
|
|
87
91
|
BuildPageGraphInput,
|
|
88
92
|
} from "../../model/layout/runtime-page-graph-types.ts";
|
|
@@ -253,6 +257,7 @@ export function buildPageGraph(
|
|
|
253
257
|
[],
|
|
254
258
|
noteAllocations: pageNoteAllocations,
|
|
255
259
|
isBlankFiller: page.pageInSection === -1,
|
|
260
|
+
materialization: "paginated",
|
|
256
261
|
};
|
|
257
262
|
pages.push(node);
|
|
258
263
|
|
|
@@ -562,6 +567,7 @@ function buildPageLocalStoryInstance(
|
|
|
562
567
|
kind: target.kind,
|
|
563
568
|
variant: target.variant,
|
|
564
569
|
relationshipId: target.relationshipId,
|
|
570
|
+
region,
|
|
565
571
|
})
|
|
566
572
|
: { objects: [], divergences: [] };
|
|
567
573
|
const signature = buildPageLocalStorySignature({
|
|
@@ -617,6 +623,10 @@ function buildPageLocalStorySignature(input: {
|
|
|
617
623
|
object.display,
|
|
618
624
|
object.extentTwips?.widthTwips ?? "",
|
|
619
625
|
object.extentTwips?.heightTwips ?? "",
|
|
626
|
+
object.anchorRectTwips?.xTwips ?? "",
|
|
627
|
+
object.anchorRectTwips?.yTwips ?? "",
|
|
628
|
+
object.anchorRectTwips?.widthTwips ?? "",
|
|
629
|
+
object.anchorRectTwips?.heightTwips ?? "",
|
|
620
630
|
object.relationshipIds?.join(",") ?? "",
|
|
621
631
|
object.mediaIds?.join(",") ?? "",
|
|
622
632
|
object.wrapMode ?? "",
|
|
@@ -728,6 +738,7 @@ interface StoryObjectContext {
|
|
|
728
738
|
kind: "header" | "footer";
|
|
729
739
|
variant: RuntimePageLocalStoryInstance["variant"];
|
|
730
740
|
relationshipId: string;
|
|
741
|
+
region?: RuntimePageRegion;
|
|
731
742
|
}
|
|
732
743
|
|
|
733
744
|
function collectStoryAnchoredObjects(
|
|
@@ -832,13 +843,20 @@ function collectStoryAnchoredObjects(
|
|
|
832
843
|
const preserveHint = getDrawingFramePreserveHint(inline);
|
|
833
844
|
const relationshipIds = collectDrawingRelationshipIds(inline);
|
|
834
845
|
const display = inline.anchor.display;
|
|
846
|
+
const extentTwips = extentTwipsFromEmu(
|
|
847
|
+
inline.anchor.extent.widthEmu,
|
|
848
|
+
inline.anchor.extent.heightEmu,
|
|
849
|
+
);
|
|
835
850
|
pushObject({
|
|
836
851
|
objectId: getDrawingFrameObjectId(inline, context.storyKey, ordinal),
|
|
837
852
|
sourceType: "drawing-frame",
|
|
838
853
|
display,
|
|
839
|
-
extentTwips
|
|
840
|
-
|
|
841
|
-
|
|
854
|
+
extentTwips,
|
|
855
|
+
anchorRectTwips: resolveObjectAnchorRectTwips(
|
|
856
|
+
context.region,
|
|
857
|
+
extentTwips,
|
|
858
|
+
inline.anchor.positionH,
|
|
859
|
+
inline.anchor.positionV,
|
|
842
860
|
),
|
|
843
861
|
...(relationshipIds.length > 0 ? { relationshipIds } : {}),
|
|
844
862
|
...(inline.content.type === "picture" && inline.content.mediaId
|
|
@@ -859,15 +877,22 @@ function collectStoryAnchoredObjects(
|
|
|
859
877
|
case "wordart":
|
|
860
878
|
case "vml_shape": {
|
|
861
879
|
const preserveHint = inline.preserveOnlyObject;
|
|
880
|
+
const extentTwips = preserveHint?.extentEmu
|
|
881
|
+
? extentTwipsFromEmu(
|
|
882
|
+
preserveHint.extentEmu.widthEmu,
|
|
883
|
+
preserveHint.extentEmu.heightEmu,
|
|
884
|
+
)
|
|
885
|
+
: undefined;
|
|
862
886
|
pushObject({
|
|
863
887
|
objectId: getPreserveOnlyObjectId(inline, context.storyKey, ordinal),
|
|
864
888
|
sourceType: sourceTypeForInlineObject(inline.type),
|
|
865
889
|
display: preserveHint?.display ?? "unknown",
|
|
866
|
-
...(
|
|
890
|
+
...(extentTwips
|
|
867
891
|
? {
|
|
868
|
-
extentTwips
|
|
869
|
-
|
|
870
|
-
|
|
892
|
+
extentTwips,
|
|
893
|
+
anchorRectTwips: resolveObjectAnchorRectTwips(
|
|
894
|
+
context.region,
|
|
895
|
+
extentTwips,
|
|
871
896
|
),
|
|
872
897
|
}
|
|
873
898
|
: {}),
|
|
@@ -982,6 +1007,59 @@ function extentTwipsFromEmu(
|
|
|
982
1007
|
};
|
|
983
1008
|
}
|
|
984
1009
|
|
|
1010
|
+
function resolveObjectAnchorRectTwips(
|
|
1011
|
+
region: RuntimePageRegion | undefined,
|
|
1012
|
+
extentTwips: RuntimeStoryAnchoredObject["extentTwips"],
|
|
1013
|
+
positionH?: { relativeFrom: string; align?: string; offset?: number },
|
|
1014
|
+
positionV?: { relativeFrom: string; align?: string; offset?: number },
|
|
1015
|
+
): RuntimeTwipsRect | undefined {
|
|
1016
|
+
if (!region?.rectTwips || !extentTwips) return undefined;
|
|
1017
|
+
const regionRect = region.rectTwips;
|
|
1018
|
+
const widthTwips = Math.max(0, extentTwips.widthTwips);
|
|
1019
|
+
const heightTwips = Math.max(0, extentTwips.heightTwips);
|
|
1020
|
+
return rect(
|
|
1021
|
+
resolveAxisTwips(
|
|
1022
|
+
regionRect.xTwips,
|
|
1023
|
+
regionRect.widthTwips,
|
|
1024
|
+
widthTwips,
|
|
1025
|
+
positionH?.align,
|
|
1026
|
+
positionH?.offset,
|
|
1027
|
+
),
|
|
1028
|
+
resolveAxisTwips(
|
|
1029
|
+
regionRect.yTwips,
|
|
1030
|
+
regionRect.heightTwips,
|
|
1031
|
+
heightTwips,
|
|
1032
|
+
positionV?.align,
|
|
1033
|
+
positionV?.offset,
|
|
1034
|
+
),
|
|
1035
|
+
widthTwips,
|
|
1036
|
+
heightTwips,
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function resolveAxisTwips(
|
|
1041
|
+
originTwips: number,
|
|
1042
|
+
spanTwips: number,
|
|
1043
|
+
objectSpanTwips: number,
|
|
1044
|
+
align?: string,
|
|
1045
|
+
offsetEmu?: number,
|
|
1046
|
+
): number {
|
|
1047
|
+
if (offsetEmu !== undefined) {
|
|
1048
|
+
return originTwips + Math.round(offsetEmu / EMUS_PER_TWIP);
|
|
1049
|
+
}
|
|
1050
|
+
switch (align) {
|
|
1051
|
+
case "center":
|
|
1052
|
+
return originTwips + Math.round((spanTwips - objectSpanTwips) / 2);
|
|
1053
|
+
case "right":
|
|
1054
|
+
case "bottom":
|
|
1055
|
+
return originTwips + Math.max(0, spanTwips - objectSpanTwips);
|
|
1056
|
+
case "left":
|
|
1057
|
+
case "top":
|
|
1058
|
+
default:
|
|
1059
|
+
return originTwips;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
985
1063
|
function resolvePageInstanceFieldDisplayText(
|
|
986
1064
|
family: string,
|
|
987
1065
|
cachedDisplayText: string,
|
|
@@ -1390,6 +1468,9 @@ function pageNodesStructurallyEqual(
|
|
|
1390
1468
|
if (a.startOffset !== b.startOffset) return false;
|
|
1391
1469
|
if (a.endOffset !== b.endOffset) return false;
|
|
1392
1470
|
if (a.isBlankFiller !== b.isBlankFiller) return false;
|
|
1471
|
+
if ((a.materialization ?? "paginated") !== (b.materialization ?? "paginated")) {
|
|
1472
|
+
return false;
|
|
1473
|
+
}
|
|
1393
1474
|
if (a.regions.body.fragmentIds.length !== b.regions.body.fragmentIds.length) {
|
|
1394
1475
|
return false;
|
|
1395
1476
|
}
|