@beyondwork/docx-react-component 1.0.28 → 1.0.30

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 (92) hide show
  1. package/package.json +26 -37
  2. package/src/api/public-types.ts +531 -0
  3. package/src/api/session-state.ts +2 -0
  4. package/src/core/commands/index.ts +201 -79
  5. package/src/core/commands/table-structure-commands.ts +138 -5
  6. package/src/core/state/text-transaction.ts +370 -3
  7. package/src/index.ts +41 -0
  8. package/src/io/docx-session.ts +318 -25
  9. package/src/io/export/serialize-footnotes.ts +41 -46
  10. package/src/io/export/serialize-headers-footers.ts +36 -40
  11. package/src/io/export/serialize-main-document.ts +55 -89
  12. package/src/io/export/serialize-numbering.ts +104 -4
  13. package/src/io/export/serialize-runtime-revisions.ts +196 -2
  14. package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
  15. package/src/io/export/table-properties-xml.ts +318 -0
  16. package/src/io/normalize/normalize-text.ts +34 -3
  17. package/src/io/ooxml/parse-comments.ts +6 -0
  18. package/src/io/ooxml/parse-footnotes.ts +69 -13
  19. package/src/io/ooxml/parse-headers-footers.ts +54 -11
  20. package/src/io/ooxml/parse-main-document.ts +112 -42
  21. package/src/io/ooxml/parse-numbering.ts +341 -26
  22. package/src/io/ooxml/parse-revisions.ts +118 -4
  23. package/src/io/ooxml/parse-styles.ts +176 -0
  24. package/src/io/ooxml/parse-tables.ts +34 -25
  25. package/src/io/ooxml/revision-boundaries.ts +127 -3
  26. package/src/io/ooxml/workflow-payload.ts +544 -0
  27. package/src/model/canonical-document.ts +91 -1
  28. package/src/model/snapshot.ts +112 -1
  29. package/src/preservation/store.ts +73 -3
  30. package/src/review/store/comment-store.ts +19 -1
  31. package/src/review/store/revision-actions.ts +29 -0
  32. package/src/review/store/revision-store.ts +12 -1
  33. package/src/review/store/revision-types.ts +11 -0
  34. package/src/runtime/context-analytics.ts +824 -0
  35. package/src/runtime/document-locations.ts +521 -0
  36. package/src/runtime/document-navigation.ts +14 -1
  37. package/src/runtime/document-outline.ts +440 -0
  38. package/src/runtime/document-runtime.ts +941 -45
  39. package/src/runtime/event-refresh-hints.ts +137 -0
  40. package/src/runtime/numbering-prefix.ts +67 -39
  41. package/src/runtime/page-layout-estimation.ts +100 -7
  42. package/src/runtime/resolved-numbering-geometry.ts +293 -0
  43. package/src/runtime/session-capabilities.ts +2 -2
  44. package/src/runtime/suggestions-snapshot.ts +137 -0
  45. package/src/runtime/surface-projection.ts +223 -27
  46. package/src/runtime/table-style-resolver.ts +409 -0
  47. package/src/runtime/view-state.ts +17 -1
  48. package/src/runtime/workflow-markup.ts +54 -14
  49. package/src/ui/WordReviewEditor.tsx +1269 -87
  50. package/src/ui/editor-command-bag.ts +7 -0
  51. package/src/ui/editor-runtime-boundary.ts +111 -10
  52. package/src/ui/editor-shell-view.tsx +17 -15
  53. package/src/ui/editor-surface-controller.tsx +5 -0
  54. package/src/ui/headless/selection-tool-context.ts +19 -0
  55. package/src/ui/headless/selection-tool-resolver.ts +752 -0
  56. package/src/ui/headless/selection-tool-types.ts +129 -0
  57. package/src/ui/headless/selection-toolbar-model.ts +10 -33
  58. package/src/ui/runtime-shortcut-dispatch.ts +365 -0
  59. package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
  60. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
  61. package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
  62. package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
  63. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +1 -9
  64. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +1 -5
  65. package/src/ui-tailwind/chrome/tw-page-ruler.tsx +8 -29
  66. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
  67. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
  68. package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
  69. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +298 -0
  70. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
  71. package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
  72. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
  73. package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +3 -3
  74. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +3 -3
  75. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +86 -14
  76. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +57 -52
  77. package/src/ui-tailwind/editor-surface/pm-decorations.ts +36 -52
  78. package/src/ui-tailwind/editor-surface/pm-schema.ts +56 -5
  79. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +87 -24
  80. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +4 -0
  81. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +135 -32
  82. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +74 -7
  83. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +17 -17
  84. package/src/ui-tailwind/review/tw-review-rail.tsx +19 -17
  85. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +10 -10
  86. package/src/ui-tailwind/status/tw-status-bar.tsx +10 -6
  87. package/src/ui-tailwind/theme/editor-theme.css +58 -40
  88. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +4 -4
  89. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +250 -181
  90. package/src/ui-tailwind/tw-review-workspace.tsx +323 -280
  91. package/src/validation/compatibility-engine.ts +246 -2
  92. package/src/validation/docx-comment-proof.ts +24 -11
@@ -30,11 +30,14 @@ import type {
30
30
  } from "../model/canonical-document.ts";
31
31
  import {
32
32
  describeOpaqueFragment,
33
+ describeStructuredWrapperBlock,
33
34
  getOpaqueFragment,
35
+ isBlockedImportFeatureKey,
34
36
  } from "../preservation/store.ts";
35
37
  import { getStoryBlocks } from "./story-targeting.ts";
36
38
  import {
37
39
  createNumberingPrefixResolver,
40
+ type NumberingPrefixResult,
38
41
  type NumberingPrefixResolver,
39
42
  } from "./numbering-prefix.ts";
40
43
  import {
@@ -42,6 +45,7 @@ import {
42
45
  findHeaderFooterDocumentEntry,
43
46
  resolveSectionVariants,
44
47
  } from "./story-context.ts";
48
+ import { resolveTableStyleResolution } from "./table-style-resolver.ts";
45
49
 
46
50
  interface ParagraphAccumulator {
47
51
  blockId: string;
@@ -52,6 +56,7 @@ interface ParagraphAccumulator {
52
56
  numbering?: ParagraphNode["numbering"];
53
57
  numberingPrefix?: string;
54
58
  numberingSuffix?: "tab" | "space" | "nothing";
59
+ resolvedNumbering?: Extract<SurfaceBlockSnapshot, { kind: "paragraph" }>["resolvedNumbering"];
55
60
  contextualSpacing?: boolean;
56
61
  segments: SurfaceInlineSegment[];
57
62
  }
@@ -122,6 +127,9 @@ function createSurfaceBlock(
122
127
  if (block.type === "opaque_block") {
123
128
  const fragment = getOpaqueFragment(document.preservation as never, block.fragmentId);
124
129
  const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
130
+ const blockedReasonCode = descriptor && isBlockedImportFeatureKey(descriptor.featureKey)
131
+ ? "workflow_blocked_import"
132
+ : "workflow_preserve_only";
125
133
  const blockId = `opaque-${counters.opaque}`;
126
134
  counters.opaque += 1;
127
135
  return {
@@ -136,6 +144,7 @@ function createSurfaceBlock(
136
144
  detail:
137
145
  descriptor?.detail ??
138
146
  "Locked whole-unit to keep unsupported OOXML intact through export.",
147
+ ...(descriptor ? { featureKey: descriptor.featureKey, blockedReasonCode } : {}),
139
148
  state: "locked-preserve-only",
140
149
  },
141
150
  lockedFragmentIds: [block.fragmentId],
@@ -157,6 +166,31 @@ function createSurfaceBlock(
157
166
  }
158
167
 
159
168
  if (block.type === "sdt") {
169
+ const descriptor = describeStructuredWrapperBlock(block);
170
+ if (descriptor) {
171
+ const blockId = `sdt-wrapper-${counters.sdt}`;
172
+ counters.sdt += 1;
173
+ return {
174
+ block: {
175
+ blockId,
176
+ kind: "opaque_block",
177
+ from: cursor,
178
+ to: cursor + 1,
179
+ fragmentId: blockId,
180
+ warningId: blockId,
181
+ label: descriptor.label,
182
+ detail: descriptor.detail,
183
+ featureKey: descriptor.featureKey,
184
+ blockedReasonCode: isBlockedImportFeatureKey(descriptor.featureKey)
185
+ ? "workflow_blocked_import"
186
+ : "workflow_preserve_only",
187
+ state: "locked-preserve-only",
188
+ },
189
+ lockedFragmentIds: [],
190
+ nextCursor: cursor + 1,
191
+ };
192
+ }
193
+
160
194
  const sdtIndex = counters.sdt;
161
195
  counters.sdt += 1;
162
196
  return createSdtBlock(
@@ -170,6 +204,7 @@ function createSurfaceBlock(
170
204
  }
171
205
 
172
206
  if (block.type === "custom_xml") {
207
+ const descriptor = describeStructuredWrapperBlock(block);
173
208
  const blockId = `custom-xml-${counters.customXml}`;
174
209
  counters.customXml += 1;
175
210
  return {
@@ -180,11 +215,16 @@ function createSurfaceBlock(
180
215
  to: cursor + 1,
181
216
  fragmentId: blockId,
182
217
  warningId: blockId,
183
- label: "Custom XML block",
184
- detail:
185
- block.uri || block.element
186
- ? `Custom XML wrapper ${[block.element, block.uri].filter(Boolean).join(" ")} preserved as a read-only block.`
187
- : "Custom XML wrapper preserved as a read-only block.",
218
+ label: descriptor?.label ?? "Custom XML wrapper",
219
+ detail: descriptor?.detail ?? "Custom XML wrapper remains package-backed and read-only.",
220
+ ...(descriptor
221
+ ? {
222
+ featureKey: descriptor.featureKey,
223
+ blockedReasonCode: isBlockedImportFeatureKey(descriptor.featureKey)
224
+ ? "workflow_blocked_import"
225
+ : "workflow_preserve_only",
226
+ }
227
+ : {}),
188
228
  state: "locked-preserve-only",
189
229
  },
190
230
  lockedFragmentIds: [],
@@ -193,6 +233,7 @@ function createSurfaceBlock(
193
233
  }
194
234
 
195
235
  if (block.type === "alt_chunk") {
236
+ const descriptor = describeStructuredWrapperBlock(block);
196
237
  const blockId = `alt-chunk-${counters.altChunk}`;
197
238
  counters.altChunk += 1;
198
239
  return {
@@ -203,8 +244,18 @@ function createSurfaceBlock(
203
244
  to: cursor + 1,
204
245
  fragmentId: blockId,
205
246
  warningId: blockId,
206
- label: "AltChunk import",
207
- detail: `Alternate content import remains read-only through relationship ${block.relationshipId}.`,
247
+ label: descriptor?.label ?? "AltChunk import",
248
+ detail:
249
+ descriptor?.detail ??
250
+ `AltChunk import remains package-backed and blocked through relationship ${block.relationshipId}.`,
251
+ ...(descriptor
252
+ ? {
253
+ featureKey: descriptor.featureKey,
254
+ blockedReasonCode: isBlockedImportFeatureKey(descriptor.featureKey)
255
+ ? "workflow_blocked_import"
256
+ : "workflow_preserve_only",
257
+ }
258
+ : {}),
208
259
  state: "locked-preserve-only",
209
260
  },
210
261
  lockedFragmentIds: [],
@@ -262,9 +313,11 @@ function createTableBlock(
262
313
  let innerCursor = cursor;
263
314
  const rows: SurfaceTableRowSnapshot[] = [];
264
315
  const rowSpans = computeTableRowSpans(table);
316
+ const resolvedTable = resolveTableStyleResolution(table, document.styles.tables);
265
317
 
266
318
  for (const [rowIndex, row] of table.rows.entries()) {
267
319
  const cells: SurfaceTableCellSnapshot[] = [];
320
+ const resolvedRow = resolvedTable.rows[rowIndex];
268
321
  for (const [cellIndex, cell] of row.cells.entries()) {
269
322
  const cellContent: SurfaceBlockSnapshot[] = [];
270
323
  for (const child of cell.children) {
@@ -279,14 +332,15 @@ function createTableBlock(
279
332
  lockedFragmentIds.push(...result.lockedFragmentIds);
280
333
  innerCursor = result.nextCursor;
281
334
  }
282
- const cellBorders = resolveCellBorderStyles(cell.borders);
335
+ const resolvedCell = resolvedRow?.cells[cellIndex];
336
+ const cellBorders = resolveCellBorderStyles(resolvedCell?.borders ?? cell.borders);
283
337
  cells.push({
284
338
  gridSpan: cell.gridSpan ?? 1,
285
339
  verticalMerge: cell.verticalMerge ?? null,
286
340
  colspan: cell.gridSpan ?? 1,
287
341
  rowspan: rowSpans.get(`${rowIndex}:${cellIndex}`) ?? 1,
288
- ...(cell.shading?.fill ? { backgroundColor: `#${cell.shading.fill}` } : {}),
289
- ...(cell.verticalAlign ? { verticalAlign: cell.verticalAlign } : {}),
342
+ ...(resolvedCell?.shading?.fill ? { backgroundColor: `#${resolvedCell.shading.fill}` } : {}),
343
+ ...(resolvedCell?.verticalAlign ? { verticalAlign: resolvedCell.verticalAlign } : {}),
290
344
  ...(cellBorders.borderTop ? { borderTop: cellBorders.borderTop } : {}),
291
345
  ...(cellBorders.borderRight ? { borderRight: cellBorders.borderRight } : {}),
292
346
  ...(cellBorders.borderBottom ? { borderBottom: cellBorders.borderBottom } : {}),
@@ -294,13 +348,16 @@ function createTableBlock(
294
348
  content: cellContent,
295
349
  });
296
350
  }
351
+ const headerLike =
352
+ row.isHeader === true ||
353
+ resolvedRow?.style.isHeader === true;
297
354
  rows.push({
298
355
  cells,
299
356
  ...(row.gridBefore !== undefined ? { gridBefore: row.gridBefore } : {}),
300
357
  ...(row.gridAfter !== undefined ? { gridAfter: row.gridAfter } : {}),
301
- ...(row.height !== undefined ? { height: row.height } : {}),
302
- ...(row.heightRule ? { heightRule: row.heightRule } : {}),
303
- ...(row.isHeader ? { isHeader: row.isHeader } : {}),
358
+ ...(resolvedRow?.style.height !== undefined ? { height: resolvedRow.style.height } : {}),
359
+ ...(resolvedRow?.style.heightRule ? { heightRule: resolvedRow.style.heightRule } : {}),
360
+ ...(headerLike ? { isHeader: true } : {}),
304
361
  });
305
362
  }
306
363
 
@@ -312,8 +369,8 @@ function createTableBlock(
312
369
  to: innerCursor,
313
370
  styleId: table.styleId,
314
371
  gridColumns: table.gridColumns,
315
- ...(table.alignment ? { alignment: table.alignment } : {}),
316
- ...(table.tblLook ? { tblLook: table.tblLook } : {}),
372
+ ...(resolvedTable.table?.alignment ? { alignment: resolvedTable.table.alignment } : {}),
373
+ tblLook: resolvedTable.effectiveTblLook,
317
374
  rows,
318
375
  },
319
376
  lockedFragmentIds,
@@ -452,23 +509,25 @@ function createParagraphBlock(
452
509
  nextCursor: number;
453
510
  lockedFragmentIds: string[];
454
511
  } {
512
+ const effectiveNumbering = resolveEffectiveParagraphNumbering(document, paragraph);
513
+ const resolvedNumbering = effectiveNumbering
514
+ ? numberingPrefixResolver.resolveDetailed(effectiveNumbering, paragraph)
515
+ : null;
455
516
  const accumulator: ParagraphAccumulator = {
456
517
  blockId: `paragraph-${paragraphIndex}`,
457
518
  kind: "paragraph",
458
519
  from: start,
459
520
  to: start,
460
521
  ...(paragraph.styleId ? { styleId: paragraph.styleId } : {}),
461
- ...(paragraph.numbering ? { numbering: paragraph.numbering } : {}),
462
- ...(paragraph.numbering
463
- ? (() => {
464
- const detailed = numberingPrefixResolver.resolveDetailed(paragraph.numbering);
465
- return detailed
466
- ? {
467
- numberingPrefix: detailed.text,
468
- ...(detailed.suffix ? { numberingSuffix: detailed.suffix } : {}),
469
- }
470
- : {};
471
- })()
522
+ ...(effectiveNumbering ? { numbering: effectiveNumbering } : {}),
523
+ ...(resolvedNumbering
524
+ ? {
525
+ ...(resolvedNumbering.text !== null ? { numberingPrefix: resolvedNumbering.text } : {}),
526
+ ...(resolvedNumbering.text !== null && resolvedNumbering.suffix
527
+ ? { numberingSuffix: resolvedNumbering.suffix }
528
+ : {}),
529
+ resolvedNumbering: toSurfaceResolvedNumbering(resolvedNumbering),
530
+ }
472
531
  : {}),
473
532
  ...(paragraph.alignment ? { alignment: paragraph.alignment } : {}),
474
533
  ...(paragraph.spacing ? { spacing: paragraph.spacing } : {}),
@@ -507,6 +566,106 @@ function createParagraphBlock(
507
566
  };
508
567
  }
509
568
 
569
+ function resolveEffectiveParagraphNumbering(
570
+ document: CanonicalDocumentEnvelope,
571
+ paragraph: ParagraphNode,
572
+ ): ParagraphNode["numbering"] | undefined {
573
+ if (paragraph.numbering) {
574
+ return paragraph.numbering;
575
+ }
576
+ if (!paragraph.styleId) {
577
+ return undefined;
578
+ }
579
+
580
+ const paragraphStyles = document.styles?.paragraphs ?? {};
581
+ const styleChain = collectParagraphStyleChain(document, paragraph.styleId);
582
+ let styleNumbering:
583
+ | CanonicalDocumentEnvelope["styles"]["paragraphs"][string]["numbering"]
584
+ | undefined;
585
+ for (const styleId of styleChain) {
586
+ const style = paragraphStyles[styleId];
587
+ if (style?.numbering) {
588
+ styleNumbering = style.numbering;
589
+ break;
590
+ }
591
+ }
592
+ if (!styleNumbering) {
593
+ return undefined;
594
+ }
595
+ if (styleNumbering.level !== undefined) {
596
+ return {
597
+ numberingInstanceId: styleNumbering.numberingInstanceId,
598
+ level: styleNumbering.level,
599
+ };
600
+ }
601
+
602
+ const resolvedLevel = resolveStyleLinkedNumberingLevel(
603
+ document,
604
+ styleNumbering.numberingInstanceId,
605
+ styleChain,
606
+ );
607
+ return resolvedLevel !== undefined
608
+ ? {
609
+ numberingInstanceId: styleNumbering.numberingInstanceId,
610
+ level: resolvedLevel,
611
+ }
612
+ : undefined;
613
+ }
614
+
615
+ function collectParagraphStyleChain(
616
+ document: CanonicalDocumentEnvelope,
617
+ styleId: string,
618
+ ): string[] {
619
+ const paragraphStyles = document.styles?.paragraphs ?? {};
620
+ const chain: string[] = [];
621
+ const visited = new Set<string>();
622
+ let currentStyleId: string | undefined = styleId;
623
+
624
+ while (currentStyleId && !visited.has(currentStyleId)) {
625
+ visited.add(currentStyleId);
626
+ chain.push(currentStyleId);
627
+ currentStyleId = paragraphStyles[currentStyleId]?.basedOn;
628
+ }
629
+
630
+ return chain;
631
+ }
632
+
633
+ function resolveStyleLinkedNumberingLevel(
634
+ document: CanonicalDocumentEnvelope,
635
+ numberingInstanceId: string,
636
+ styleChain: readonly string[],
637
+ ): number | undefined {
638
+ const instance = document.numbering.instances[numberingInstanceId];
639
+ if (!instance) {
640
+ return undefined;
641
+ }
642
+
643
+ for (const styleId of styleChain) {
644
+ const overrideMatch = instance.overrides.find(
645
+ (override) => override.levelDefinition?.paragraphStyleId === styleId,
646
+ );
647
+ if (overrideMatch) {
648
+ return overrideMatch.level;
649
+ }
650
+ }
651
+
652
+ const abstractDefinition = document.numbering.abstractDefinitions[instance.abstractNumberingId];
653
+ if (!abstractDefinition) {
654
+ return undefined;
655
+ }
656
+
657
+ for (const styleId of styleChain) {
658
+ const levelMatch = abstractDefinition.levels.find(
659
+ (levelDefinition) => levelDefinition.paragraphStyleId === styleId,
660
+ );
661
+ if (levelMatch) {
662
+ return levelMatch.level;
663
+ }
664
+ }
665
+
666
+ return undefined;
667
+ }
668
+
510
669
  function appendInlineSegments(
511
670
  paragraph: ParagraphAccumulator,
512
671
  node: InlineNode,
@@ -580,6 +739,9 @@ function appendInlineSegments(
580
739
  const fragment = getOpaqueFragment(document.preservation as never, node.fragmentId);
581
740
  const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
582
741
  const preview = fragment ? describePreservedInlinePreview(fragment.payloadReference) : null;
742
+ const blockedReasonCode = descriptor && isBlockedImportFeatureKey(descriptor.featureKey)
743
+ ? "workflow_blocked_import"
744
+ : "workflow_preserve_only";
583
745
  paragraph.segments.push({
584
746
  segmentId: `${paragraph.blockId}-segment-${paragraph.segments.length}`,
585
747
  kind: "opaque_inline",
@@ -592,6 +754,7 @@ function appendInlineSegments(
592
754
  preview?.detail ??
593
755
  descriptor?.detail ??
594
756
  "Locked whole-unit to keep unsupported inline OOXML intact through export.",
757
+ ...(descriptor ? { featureKey: descriptor.featureKey, blockedReasonCode } : {}),
595
758
  ...(preview?.presentation ? { presentation: preview.presentation } : {}),
596
759
  state: "locked-preserve-only",
597
760
  });
@@ -626,7 +789,8 @@ function appendInlineSegments(
626
789
  fragmentId: "",
627
790
  warningId: "",
628
791
  label: "Column break",
629
- detail: "Column break marker preserved for export.",
792
+ detail: "Word column break marker preserved for export safety.",
793
+ presentation: "quiet-marker",
630
794
  state: "locked-preserve-only",
631
795
  });
632
796
  return { nextCursor: start + 1, lockedFragmentIds: [] };
@@ -1116,6 +1280,38 @@ function toSurfaceTabStop(
1116
1280
  };
1117
1281
  }
1118
1282
 
1283
+ function toSurfaceResolvedNumbering(
1284
+ numbering: NumberingPrefixResult,
1285
+ ): NonNullable<Extract<SurfaceBlockSnapshot, { kind: "paragraph" }>["resolvedNumbering"]> {
1286
+ return {
1287
+ level: numbering.level,
1288
+ format: numbering.format,
1289
+ ...(numbering.text !== null ? { text: numbering.text } : {}),
1290
+ startAt: numbering.startAt,
1291
+ ...(numbering.paragraphStyleId ? { paragraphStyleId: numbering.paragraphStyleId } : {}),
1292
+ ...(numbering.isLegalNumbering ? { isLegalNumbering: true } : {}),
1293
+ ...(numbering.suffix ? { suffix: numbering.suffix } : {}),
1294
+ geometry: {
1295
+ ...(numbering.geometry.markerJustification
1296
+ ? { markerJustification: numbering.geometry.markerJustification }
1297
+ : {}),
1298
+ ...(numbering.geometry.spacing ? { spacing: { ...numbering.geometry.spacing } } : {}),
1299
+ ...(numbering.geometry.indentation
1300
+ ? { indentation: { ...numbering.geometry.indentation } }
1301
+ : {}),
1302
+ ...(numbering.geometry.tabStops && numbering.geometry.tabStops.length > 0
1303
+ ? { tabStops: numbering.geometry.tabStops.map((tabStop) => toSurfaceTabStop(tabStop)) }
1304
+ : {}),
1305
+ ...(numbering.geometry.markerLane
1306
+ ? { markerLane: { ...numbering.geometry.markerLane } }
1307
+ : {}),
1308
+ ...(numbering.geometry.textColumn
1309
+ ? { textColumn: { ...numbering.geometry.textColumn } }
1310
+ : {}),
1311
+ },
1312
+ };
1313
+ }
1314
+
1119
1315
  function describePreservedInlinePreview(
1120
1316
  payloadReference: string,
1121
1317
  ): {