@beyondwork/docx-react-component 1.0.103 → 1.0.105

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 (45) hide show
  1. package/package.json +1 -1
  2. package/src/api/public-types.ts +66 -1
  3. package/src/api/v3/_runtime-handle.ts +2 -0
  4. package/src/api/v3/ai/_pe2-evidence.ts +153 -0
  5. package/src/api/v3/ai/bundle.ts +13 -5
  6. package/src/api/v3/ai/inspect.ts +7 -1
  7. package/src/api/v3/ai/outline.ts +2 -7
  8. package/src/api/v3/ai/replacement.ts +113 -0
  9. package/src/api/v3/runtime/geometry.ts +79 -0
  10. package/src/api/v3/ui/_types.ts +86 -0
  11. package/src/api/v3/ui/index.ts +5 -0
  12. package/src/api/v3/ui/overlays.ts +104 -0
  13. package/src/io/ooxml/parse-drawing.ts +99 -1
  14. package/src/io/ooxml/parse-fields.ts +27 -6
  15. package/src/io/ooxml/parse-shapes.ts +130 -0
  16. package/src/model/canonical-document.ts +34 -3
  17. package/src/model/canonical-layout-inputs.ts +979 -0
  18. package/src/model/layout/index.ts +9 -0
  19. package/src/model/layout/page-graph-types.ts +150 -0
  20. package/src/model/layout/runtime-page-graph-types.ts +23 -0
  21. package/src/runtime/collab/runtime-collab-sync.ts +3 -3
  22. package/src/runtime/debug/build-debug-inspector-snapshot.ts +17 -4
  23. package/src/runtime/document-runtime.ts +30 -14
  24. package/src/runtime/event-refresh-hints.ts +35 -5
  25. package/src/runtime/formatting/formatting-context.ts +110 -9
  26. package/src/runtime/formatting/index.ts +2 -0
  27. package/src/runtime/formatting/layout-inputs.ts +67 -3
  28. package/src/runtime/geometry/caret-geometry.ts +82 -10
  29. package/src/runtime/geometry/geometry-facet.ts +44 -0
  30. package/src/runtime/geometry/geometry-index.ts +1268 -0
  31. package/src/runtime/geometry/geometry-types.ts +227 -1
  32. package/src/runtime/geometry/index.ts +26 -0
  33. package/src/runtime/geometry/inert-geometry-facet.ts +3 -0
  34. package/src/runtime/geometry/object-handles.ts +7 -4
  35. package/src/runtime/geometry/replacement-envelope.ts +41 -2
  36. package/src/runtime/layout/layout-engine-instance.ts +2 -0
  37. package/src/runtime/layout/layout-engine-version.ts +44 -1
  38. package/src/runtime/layout/page-graph.ts +877 -2
  39. package/src/runtime/layout/project-block-fragments.ts +101 -1
  40. package/src/runtime/layout/public-facet.ts +152 -0
  41. package/src/runtime/prerender/graph-canonicalize.ts +44 -0
  42. package/src/runtime/surface-projection.ts +43 -3
  43. package/src/runtime/workflow/coordinator.ts +57 -11
  44. package/src/ui/ui-controller-factory.ts +11 -0
  45. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +3 -0
@@ -235,11 +235,27 @@ function emitSlicedParagraph(
235
235
  ...deriveStyleMetadata(block),
236
236
  kind: "paragraph-slice",
237
237
  paragraphLineRange: slice.lineRange,
238
+ continuation: buildParagraphContinuationCursor(slice, i, slices.length),
238
239
  };
239
240
  emit(slice.pageIndex, fragment);
240
241
  }
241
242
  }
242
243
 
244
+ function buildParagraphContinuationCursor(
245
+ slice: ParagraphLineSlice,
246
+ sequenceIndex: number,
247
+ sliceCount: number,
248
+ ): NonNullable<RuntimeBlockFragment["continuation"]> {
249
+ return {
250
+ kind: "paragraph",
251
+ sequenceIndex,
252
+ sliceCount,
253
+ lineRange: slice.lineRange,
254
+ continuesFromPreviousPage: slice.lineRange.from > 0,
255
+ continuesToNextPage: slice.lineRange.to < slice.lineRange.totalLines,
256
+ };
257
+ }
258
+
243
259
  function estimateSliceHeightFromLines(lineRange: {
244
260
  from: number;
245
261
  to: number;
@@ -259,7 +275,7 @@ function estimateSliceHeightFromLines(lineRange: {
259
275
  * every continuation page.
260
276
  */
261
277
  function emitSlicedTable(
262
- block: SurfaceBlockSnapshot,
278
+ block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
263
279
  slices: readonly TableRowSlice[],
264
280
  emit: (pageIndex: number, fragment: FragmentWithoutPageId) => void,
265
281
  ): void {
@@ -276,12 +292,96 @@ function emitSlicedTable(
276
292
  ...deriveStyleMetadata(block),
277
293
  kind: "table-slice",
278
294
  tableRowRange: slice.rowRange,
295
+ continuation: buildTableContinuationCursor(block, slice, i, slices.length),
279
296
  ...(slice.columnIndex !== undefined ? { columnIndex: slice.columnIndex } : {}),
280
297
  };
281
298
  emit(slice.pageIndex, fragment);
282
299
  }
283
300
  }
284
301
 
302
+ function buildTableContinuationCursor(
303
+ block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
304
+ slice: TableRowSlice,
305
+ sequenceIndex: number,
306
+ sliceCount: number,
307
+ ): NonNullable<RuntimeBlockFragment["continuation"]> {
308
+ return {
309
+ kind: "table",
310
+ sequenceIndex,
311
+ sliceCount,
312
+ rowRange: slice.rowRange,
313
+ continuesFromPreviousPage: slice.rowRange.from > 0,
314
+ continuesToNextPage: slice.rowRange.to < slice.rowRange.totalRows,
315
+ repeatedHeaderRowIndexes:
316
+ slice.rowRange.from > 0
317
+ ? collectRepeatedHeaderRowIndexes(block, slice.rowRange.from)
318
+ : [],
319
+ verticalMergeCarry: collectVerticalMergeCarry(block, slice.rowRange.from),
320
+ };
321
+ }
322
+
323
+ function collectRepeatedHeaderRowIndexes(
324
+ block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
325
+ startRow: number,
326
+ ): number[] {
327
+ const headerRows: number[] = [];
328
+ for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
329
+ if (rowIndex >= startRow) break;
330
+ if (block.rows[rowIndex]?.isHeader === true) headerRows.push(rowIndex);
331
+ }
332
+ return headerRows;
333
+ }
334
+
335
+ function collectVerticalMergeCarry(
336
+ block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
337
+ startRow: number,
338
+ ): Array<{ columnIndex: number; restartRowIndex: number }> {
339
+ if (startRow <= 0) return [];
340
+
341
+ const activeByColumn = new Map<number, number>();
342
+ for (let rowIndex = 0; rowIndex < startRow; rowIndex += 1) {
343
+ visitRowCells(block.rows[rowIndex], (columnIndex, span, verticalMerge) => {
344
+ for (let column = columnIndex; column < columnIndex + span; column += 1) {
345
+ if (verticalMerge === "restart") {
346
+ activeByColumn.set(column, rowIndex);
347
+ } else if (verticalMerge !== "continue") {
348
+ activeByColumn.delete(column);
349
+ }
350
+ }
351
+ });
352
+ }
353
+
354
+ const carried = new Map<number, number>();
355
+ visitRowCells(block.rows[startRow], (columnIndex, span, verticalMerge) => {
356
+ if (verticalMerge !== "continue") return;
357
+ for (let column = columnIndex; column < columnIndex + span; column += 1) {
358
+ const restartRowIndex = activeByColumn.get(column);
359
+ if (restartRowIndex !== undefined) carried.set(column, restartRowIndex);
360
+ }
361
+ });
362
+
363
+ return [...carried]
364
+ .sort(([a], [b]) => a - b)
365
+ .map(([columnIndex, restartRowIndex]) => ({ columnIndex, restartRowIndex }));
366
+ }
367
+
368
+ function visitRowCells(
369
+ row: Extract<SurfaceBlockSnapshot, { kind: "table" }>["rows"][number] | undefined,
370
+ visit: (
371
+ columnIndex: number,
372
+ span: number,
373
+ verticalMerge: "restart" | "continue" | null,
374
+ ) => void,
375
+ ): void {
376
+ if (!row) return;
377
+ let columnIndex = Math.max(0, row.gridBefore ?? 0);
378
+ for (const cell of row.cells) {
379
+ const span = Math.max(1, cell.gridSpan || cell.colspan || 1);
380
+ visit(columnIndex, span, cell.verticalMerge);
381
+ columnIndex += span;
382
+ }
383
+ }
384
+
285
385
  function estimateSliceHeightFromRows(rowRange: {
286
386
  from: number;
287
387
  to: number;
@@ -25,12 +25,16 @@ import type {
25
25
  } from "./page-story-resolver.ts";
26
26
  import type {
27
27
  RuntimeBlockFragment,
28
+ RuntimeLayoutContinuationCursor,
29
+ RuntimeLayoutDivergence,
28
30
  RuntimeLineBox,
29
31
  RuntimeNoteAllocation,
32
+ RuntimePageFrame,
30
33
  RuntimePageGraph,
31
34
  RuntimePageNode,
32
35
  RuntimePageRegion,
33
36
  RuntimePageRegions,
37
+ RuntimeTwipsRect,
34
38
  } from "./page-graph.ts";
35
39
  import type {
36
40
  ResolvedFormattingState,
@@ -132,6 +136,40 @@ export function emitLayoutGuardWarning(
132
136
  // Public read model types (shape-stable, cloned at the facet boundary)
133
137
  // ---------------------------------------------------------------------------
134
138
 
139
+ export interface PublicTwipsRect {
140
+ xTwips: number;
141
+ yTwips: number;
142
+ widthTwips: number;
143
+ heightTwips: number;
144
+ }
145
+
146
+ export interface PublicLayoutDivergence {
147
+ divergenceId: string;
148
+ kind: RuntimeLayoutDivergence["kind"];
149
+ source: RuntimeLayoutDivergence["source"];
150
+ severity: RuntimeLayoutDivergence["severity"];
151
+ message: string;
152
+ regionKinds?: readonly RuntimePageRegion["kind"][];
153
+ fragmentIds?: readonly string[];
154
+ }
155
+
156
+ export interface PublicPageFrame {
157
+ frameId: string;
158
+ pageId: string;
159
+ pageIndex: number;
160
+ sectionIndex: number;
161
+ displayPageNumber: number;
162
+ physicalBoundsTwips: PublicTwipsRect;
163
+ divergenceIds: readonly string[];
164
+ signature: string;
165
+ exclusionZoneCount: number;
166
+ regionFrames: readonly {
167
+ kind: RuntimePageRegion["kind"];
168
+ rectTwips?: PublicTwipsRect;
169
+ fragmentIds: readonly string[];
170
+ }[];
171
+ }
172
+
135
173
  export interface PublicPageNode {
136
174
  pageId: string;
137
175
  pageIndex: number;
@@ -157,6 +195,10 @@ export interface PublicPageNode {
157
195
  lineBoxCount: number;
158
196
  /** Footnotes reserved at the bottom of the page, if any. */
159
197
  noteAllocations: readonly PublicNoteAllocation[];
198
+ /** PE2 page-frame graph projection, when emitted by the L04 graph. */
199
+ frame?: PublicPageFrame;
200
+ /** Typed layout divergences detected while building this page. */
201
+ divergences?: readonly PublicLayoutDivergence[];
160
202
  }
161
203
 
162
204
  export interface PublicResolvedPageStories {
@@ -187,6 +229,8 @@ export interface PublicPageRegion {
187
229
  widthTwips: number;
188
230
  heightTwips: number;
189
231
  fragmentCount: number;
232
+ /** PE2 semantic twips rect, when populated by the L04 page-frame graph. */
233
+ rectTwips?: PublicTwipsRect;
190
234
  }
191
235
 
192
236
  /**
@@ -208,8 +252,23 @@ export interface PublicBlockFragment {
208
252
  to: number;
209
253
  heightTwips: number;
210
254
  orderInRegion: number;
255
+ kind?: "whole" | "paragraph-slice" | "table-slice";
256
+ paragraphLineRange?: {
257
+ from: number;
258
+ to: number;
259
+ totalLines: number;
260
+ };
261
+ tableRowRange?: {
262
+ from: number;
263
+ to: number;
264
+ totalRows: number;
265
+ };
266
+ columnIndex?: number;
267
+ continuation?: PublicLayoutContinuationCursor;
211
268
  }
212
269
 
270
+ export type PublicLayoutContinuationCursor = RuntimeLayoutContinuationCursor;
271
+
213
272
  /**
214
273
  * P8 — One block snapshot rendered into a region of a page. Returned by
215
274
  * `WordReviewEditorLayoutFacet.getStoryBlocksForRegion` and
@@ -245,6 +304,7 @@ export interface PublicNoteAllocation {
245
304
  noteKind: "footnote" | "endnote";
246
305
  noteId: string;
247
306
  reservedHeightTwips: number;
307
+ fragmentId?: string;
248
308
  }
249
309
 
250
310
  export interface PublicPageAnchor {
@@ -1367,12 +1427,74 @@ function toPublicPageNode(
1367
1427
  regions: toPublicPageRegions(node.regions),
1368
1428
  lineBoxCount: node.lineBoxes.length,
1369
1429
  noteAllocations: node.noteAllocations.map(toPublicNoteAllocation),
1430
+ ...(node.frame ? { frame: toPublicPageFrame(node.frame) } : {}),
1431
+ ...(node.divergences && node.divergences.length > 0
1432
+ ? { divergences: node.divergences.map(toPublicLayoutDivergence) }
1433
+ : {}),
1370
1434
  };
1371
1435
  publicPageNodeCache.set(node, built);
1372
1436
  void graph; // reserved for future cross-page derivations
1373
1437
  return built;
1374
1438
  }
1375
1439
 
1440
+ function toPublicTwipsRect(rect: RuntimeTwipsRect): PublicTwipsRect {
1441
+ return {
1442
+ xTwips: rect.xTwips,
1443
+ yTwips: rect.yTwips,
1444
+ widthTwips: rect.widthTwips,
1445
+ heightTwips: rect.heightTwips,
1446
+ };
1447
+ }
1448
+
1449
+ function frameRegionEntries(
1450
+ frame: RuntimePageFrame,
1451
+ ): PublicPageFrame["regionFrames"] {
1452
+ const regions: PublicPageFrame["regionFrames"][number][] = [];
1453
+ const push = (region: RuntimePageRegion | undefined) => {
1454
+ if (!region) return;
1455
+ regions.push({
1456
+ kind: region.kind,
1457
+ ...(region.rectTwips ? { rectTwips: toPublicTwipsRect(region.rectTwips) } : {}),
1458
+ fragmentIds: [...region.fragmentIds],
1459
+ });
1460
+ };
1461
+ push(frame.regions.header);
1462
+ push(frame.regions.body);
1463
+ for (const column of frame.regions.columns ?? []) push(column);
1464
+ push(frame.regions.footer);
1465
+ for (const footnote of frame.regions.footnotes ?? []) push(footnote);
1466
+ return regions;
1467
+ }
1468
+
1469
+ function toPublicPageFrame(frame: RuntimePageFrame): PublicPageFrame {
1470
+ return {
1471
+ frameId: frame.frameId,
1472
+ pageId: frame.pageId,
1473
+ pageIndex: frame.pageIndex,
1474
+ sectionIndex: frame.sectionIndex,
1475
+ displayPageNumber: frame.displayPageNumber,
1476
+ physicalBoundsTwips: toPublicTwipsRect(frame.physicalBoundsTwips),
1477
+ divergenceIds: [...frame.divergenceIds],
1478
+ signature: frame.signature,
1479
+ exclusionZoneCount: frame.regions.exclusionZones.length,
1480
+ regionFrames: frameRegionEntries(frame),
1481
+ };
1482
+ }
1483
+
1484
+ function toPublicLayoutDivergence(
1485
+ divergence: RuntimeLayoutDivergence,
1486
+ ): PublicLayoutDivergence {
1487
+ return {
1488
+ divergenceId: divergence.divergenceId,
1489
+ kind: divergence.kind,
1490
+ source: divergence.source,
1491
+ severity: divergence.severity,
1492
+ message: divergence.message,
1493
+ ...(divergence.regionKinds !== undefined ? { regionKinds: [...divergence.regionKinds] } : {}),
1494
+ ...(divergence.fragmentIds !== undefined ? { fragmentIds: [...divergence.fragmentIds] } : {}),
1495
+ };
1496
+ }
1497
+
1376
1498
  function toPublicResolvedPageStories(
1377
1499
  stories: ResolvedPageStories,
1378
1500
  ): PublicResolvedPageStories {
@@ -1404,6 +1526,7 @@ function toPublicPageRegion(region: RuntimePageRegion): PublicPageRegion {
1404
1526
  widthTwips: region.widthTwips,
1405
1527
  heightTwips: region.heightTwips,
1406
1528
  fragmentCount: region.fragmentIds.length,
1529
+ ...(region.rectTwips ? { rectTwips: toPublicTwipsRect(region.rectTwips) } : {}),
1407
1530
  };
1408
1531
  }
1409
1532
 
@@ -1422,6 +1545,34 @@ function toPublicBlockFragment(
1422
1545
  to: fragment.to,
1423
1546
  heightTwips: fragment.heightTwips,
1424
1547
  orderInRegion: fragment.orderInRegion,
1548
+ ...(fragment.kind !== undefined ? { kind: fragment.kind } : {}),
1549
+ ...(fragment.paragraphLineRange !== undefined
1550
+ ? { paragraphLineRange: { ...fragment.paragraphLineRange } }
1551
+ : {}),
1552
+ ...(fragment.tableRowRange !== undefined
1553
+ ? { tableRowRange: { ...fragment.tableRowRange } }
1554
+ : {}),
1555
+ ...(fragment.columnIndex !== undefined ? { columnIndex: fragment.columnIndex } : {}),
1556
+ ...(fragment.continuation !== undefined
1557
+ ? { continuation: cloneContinuationCursor(fragment.continuation) }
1558
+ : {}),
1559
+ };
1560
+ }
1561
+
1562
+ function cloneContinuationCursor(
1563
+ cursor: RuntimeLayoutContinuationCursor,
1564
+ ): RuntimeLayoutContinuationCursor {
1565
+ if (cursor.kind === "paragraph") {
1566
+ return {
1567
+ ...cursor,
1568
+ lineRange: { ...cursor.lineRange },
1569
+ };
1570
+ }
1571
+ return {
1572
+ ...cursor,
1573
+ rowRange: { ...cursor.rowRange },
1574
+ repeatedHeaderRowIndexes: [...cursor.repeatedHeaderRowIndexes],
1575
+ verticalMergeCarry: cursor.verticalMergeCarry.map((carry) => ({ ...carry })),
1425
1576
  };
1426
1577
  }
1427
1578
 
@@ -1440,6 +1591,7 @@ function toPublicNoteAllocation(note: RuntimeNoteAllocation): PublicNoteAllocati
1440
1591
  noteKind: note.noteKind,
1441
1592
  noteId: note.noteId,
1442
1593
  reservedHeightTwips: note.reservedHeightTwips,
1594
+ ...(note.fragmentId !== undefined ? { fragmentId: note.fragmentId } : {}),
1443
1595
  };
1444
1596
  }
1445
1597
 
@@ -1,7 +1,9 @@
1
1
  import type {
2
2
  RuntimeBlockFragment,
3
3
  RuntimePageAnchor,
4
+ RuntimePageFrame,
4
5
  RuntimePageGraph,
6
+ RuntimePageLocalStoryInstance,
5
7
  RuntimePageNode,
6
8
  RuntimePageRegion,
7
9
  RuntimePageRegions,
@@ -54,6 +56,9 @@ export function canonicalizeGraph(graph: RuntimePageGraph): RuntimePageGraph {
54
56
  ...page,
55
57
  pageId: rewriteId(page.pageId),
56
58
  regions: rewriteRegions(page.regions, rewriteId),
59
+ ...(page.frame === undefined
60
+ ? {}
61
+ : { frame: rewriteFrame(page.frame, rewriteId) }),
57
62
  lineBoxes: page.lineBoxes.map((line) => ({
58
63
  ...line,
59
64
  fragmentId: rewriteId(line.fragmentId),
@@ -86,6 +91,45 @@ export function canonicalizeGraph(graph: RuntimePageGraph): RuntimePageGraph {
86
91
  };
87
92
  }
88
93
 
94
+ function rewriteFrame(
95
+ frame: RuntimePageFrame,
96
+ rewriteId: (id: string) => string,
97
+ ): RuntimePageFrame {
98
+ return {
99
+ ...frame,
100
+ pageId: rewriteId(frame.pageId),
101
+ pageLocalStories: frame.pageLocalStories.map((story) =>
102
+ rewritePageLocalStoryInstance(story, rewriteId),
103
+ ),
104
+ regions: {
105
+ ...frame.regions,
106
+ body: rewriteRegion(frame.regions.body, rewriteId),
107
+ ...(frame.regions.header
108
+ ? { header: rewriteRegion(frame.regions.header, rewriteId) }
109
+ : {}),
110
+ ...(frame.regions.footer
111
+ ? { footer: rewriteRegion(frame.regions.footer, rewriteId) }
112
+ : {}),
113
+ ...(frame.regions.columns
114
+ ? { columns: frame.regions.columns.map((region) => rewriteRegion(region, rewriteId)) }
115
+ : {}),
116
+ ...(frame.regions.footnotes
117
+ ? { footnotes: frame.regions.footnotes.map((region) => rewriteRegion(region, rewriteId)) }
118
+ : {}),
119
+ },
120
+ };
121
+ }
122
+
123
+ function rewritePageLocalStoryInstance(
124
+ story: RuntimePageLocalStoryInstance,
125
+ rewriteId: (id: string) => string,
126
+ ): RuntimePageLocalStoryInstance {
127
+ return {
128
+ ...story,
129
+ pageId: rewriteId(story.pageId),
130
+ };
131
+ }
132
+
89
133
  function rewriteRegions(
90
134
  regions: RuntimePageRegions,
91
135
  rewriteId: (id: string) => string,
@@ -6,6 +6,7 @@ import type {
6
6
  SurfaceDrawingAnchor,
7
7
  SurfaceInlineSegment,
8
8
  SurfacePictureEffects,
9
+ SurfacePreserveOnlyObjectSizing,
9
10
  SurfaceTableCellSnapshot,
10
11
  SurfaceTableRowSnapshot,
11
12
  SurfaceTextMark,
@@ -38,6 +39,7 @@ import type {
38
39
  TextMark,
39
40
  DrawingFrameNode,
40
41
  PictureContent,
42
+ PreserveOnlyObjectSizing,
41
43
  ShapeContent,
42
44
  VmlShapeNode,
43
45
  WordArtNode,
@@ -1549,6 +1551,9 @@ function appendInlineSegments(
1549
1551
  ...(c.line ? { line: c.line } : {}),
1550
1552
  ...(c.isTextBox ? { isTextBox: true } : {}),
1551
1553
  ...(c.textBoxBody ? { textBoxBody: c.textBoxBody } : {}),
1554
+ ...(c.preserveOnlyObject
1555
+ ? { preserveOnlyObject: surfacePreserveOnlyObject(c.preserveOnlyObject) }
1556
+ : {}),
1552
1557
  ...(txbxText ? { txbxText } : {}),
1553
1558
  ...(txbxTextSegment?.marks && txbxTextSegment.marks.length > 0
1554
1559
  ? { txbxMarks: txbxTextSegment.marks }
@@ -1568,6 +1573,7 @@ function appendInlineSegments(
1568
1573
  {
1569
1574
  previewMediaId: c.previewMediaId,
1570
1575
  parsedChartId,
1576
+ anchor: surfaceAnchorFromGeometry(node.anchor),
1571
1577
  },
1572
1578
  );
1573
1579
  }
@@ -1578,7 +1584,10 @@ function appendInlineSegments(
1578
1584
  start,
1579
1585
  "SmartArt diagram",
1580
1586
  `DrawingFrame smartart_preview (${node.anchor.wrapMode}).`,
1581
- { previewMediaId: c.previewMediaId },
1587
+ {
1588
+ previewMediaId: c.previewMediaId,
1589
+ anchor: surfaceAnchorFromGeometry(node.anchor),
1590
+ },
1582
1591
  );
1583
1592
  }
1584
1593
  return appendComplexPreviewSegment(
@@ -1587,6 +1596,7 @@ function appendInlineSegments(
1587
1596
  start,
1588
1597
  "Drawing frame",
1589
1598
  `DrawingFrame ${c.type} (${node.anchor.wrapMode}).`,
1599
+ { anchor: surfaceAnchorFromGeometry(node.anchor) },
1590
1600
  );
1591
1601
  }
1592
1602
  case "symbol":
@@ -2109,12 +2119,19 @@ function extractTxbxFirstTextSegment(
2109
2119
 
2110
2120
  function appendComplexPreviewSegment(
2111
2121
  paragraph: ParagraphAccumulator,
2112
- node: { rawXml: string },
2122
+ node: { rawXml: string; preserveOnlyObject?: PreserveOnlyObjectSizing },
2113
2123
  start: number,
2114
2124
  label: string,
2115
2125
  detail: string,
2116
- extras: { previewMediaId?: string; parsedChartId?: string } = {},
2126
+ extras: {
2127
+ previewMediaId?: string;
2128
+ parsedChartId?: string;
2129
+ anchor?: SurfaceDrawingAnchor;
2130
+ } = {},
2117
2131
  ): { nextCursor: number; lockedFragmentIds: string[] } {
2132
+ const preserveOnlyObject = node.preserveOnlyObject
2133
+ ? surfacePreserveOnlyObject(node.preserveOnlyObject)
2134
+ : undefined;
2118
2135
  paragraph.segments.push({
2119
2136
  segmentId: `${paragraph.blockId}-segment-${paragraph.segments.length}`,
2120
2137
  kind: "opaque_inline",
@@ -2126,11 +2143,34 @@ function appendComplexPreviewSegment(
2126
2143
  detail,
2127
2144
  ...(extras.previewMediaId ? { previewMediaId: extras.previewMediaId } : {}),
2128
2145
  ...(extras.parsedChartId ? { parsedChartId: extras.parsedChartId } : {}),
2146
+ ...(preserveOnlyObject ? { preserveOnlyObject } : {}),
2147
+ ...(extras.anchor ? { anchor: extras.anchor } : {}),
2129
2148
  state: "locked-preserve-only",
2130
2149
  });
2131
2150
  return { nextCursor: start + 1, lockedFragmentIds: [] };
2132
2151
  }
2133
2152
 
2153
+ function surfacePreserveOnlyObject(
2154
+ object: PreserveOnlyObjectSizing,
2155
+ ): SurfacePreserveOnlyObjectSizing {
2156
+ return {
2157
+ ...(object.sourceId ? { sourceId: object.sourceId } : {}),
2158
+ display: object.display,
2159
+ ...(object.extentEmu
2160
+ ? {
2161
+ extentEmu: {
2162
+ widthEmu: object.extentEmu.widthEmu,
2163
+ heightEmu: object.extentEmu.heightEmu,
2164
+ },
2165
+ }
2166
+ : {}),
2167
+ fallbackHint: object.fallbackHint,
2168
+ ...(object.relationshipIds && object.relationshipIds.length > 0
2169
+ ? { relationshipIds: [...object.relationshipIds] }
2170
+ : {}),
2171
+ };
2172
+ }
2173
+
2134
2174
  function appendTextBoxSegment(
2135
2175
  paragraph: ParagraphAccumulator,
2136
2176
  start: number,