@beyondwork/docx-react-component 1.0.84 → 1.0.86

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 (53) hide show
  1. package/package.json +1 -1
  2. package/src/api/internal/build-ref-projections.ts +3 -0
  3. package/src/api/public-types.ts +38 -0
  4. package/src/api/v3/_runtime-handle.ts +11 -0
  5. package/src/api/v3/runtime/content.ts +148 -1
  6. package/src/api/v3/runtime/formatting.ts +41 -0
  7. package/src/api/v3/runtime/review.ts +98 -0
  8. package/src/core/commands/index.ts +81 -25
  9. package/src/core/state/editor-state.ts +15 -0
  10. package/src/io/ooxml/header-footer-reference.ts +38 -0
  11. package/src/io/ooxml/parse-headers-footers.ts +11 -23
  12. package/src/io/ooxml/parse-main-document.ts +7 -10
  13. package/src/model/canonical-document.ts +9 -0
  14. package/src/model/review/comment-types.ts +2 -0
  15. package/src/runtime/document-runtime.ts +677 -54
  16. package/src/runtime/formatting/field/resolver.ts +73 -8
  17. package/src/runtime/layout/layout-engine-version.ts +31 -12
  18. package/src/runtime/layout/paginated-layout-engine.ts +18 -11
  19. package/src/runtime/layout/public-facet.ts +119 -16
  20. package/src/runtime/layout/resolve-page-fields.ts +68 -6
  21. package/src/runtime/layout/resolve-page-previews.ts +1 -1
  22. package/src/runtime/suggestions-snapshot.ts +24 -0
  23. package/src/runtime/surface-projection.ts +59 -2
  24. package/src/shell/ref-commands.ts +3 -354
  25. package/src/shell/session-bootstrap.ts +8 -0
  26. package/src/ui/WordReviewEditor.tsx +192 -35
  27. package/src/ui/editor-command-bag.ts +7 -1
  28. package/src/ui/editor-shell-view.tsx +1 -0
  29. package/src/ui/headless/revision-decoration-model.ts +13 -0
  30. package/src/ui/headless/selection-tool-types.ts +2 -0
  31. package/src/ui-tailwind/chrome/editor-action-registry.ts +7 -26
  32. package/src/ui-tailwind/chrome/tw-detach-handle.tsx +6 -2
  33. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +7 -3
  34. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +175 -25
  35. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +1 -1
  36. package/src/ui-tailwind/editor-surface/pm-decorations.ts +12 -0
  37. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +18 -30
  38. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +1 -1
  39. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +1 -1
  40. package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +20 -11
  41. package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +9 -4
  42. package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +12 -7
  43. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +29 -10
  44. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +1 -1
  45. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +8 -3
  46. package/src/ui-tailwind/review/tw-review-rail.tsx +2 -0
  47. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +46 -31
  48. package/src/ui-tailwind/review/tw-workflow-tab.tsx +159 -8
  49. package/src/ui-tailwind/review-workspace/types.ts +7 -2
  50. package/src/ui-tailwind/review-workspace/use-page-markers.ts +11 -1
  51. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +8 -9
  52. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +21 -16
  53. package/src/ui-tailwind/tw-review-workspace.tsx +27 -4
@@ -1536,7 +1536,34 @@ function appendInlineSegments(
1536
1536
  node.fieldFamily === "NOTEREF" ||
1537
1537
  node.fieldFamily === "TOC" ||
1538
1538
  node.fieldFamily === "PAGE" ||
1539
- node.fieldFamily === "NUMPAGES";
1539
+ node.fieldFamily === "NUMPAGES" ||
1540
+ node.fieldFamily === "SECTIONPAGES";
1541
+ const isPageScopedField =
1542
+ node.fieldFamily === "PAGE" ||
1543
+ node.fieldFamily === "NUMPAGES" ||
1544
+ node.fieldFamily === "SECTIONPAGES";
1545
+ if (isPageScopedField) {
1546
+ const fieldLabel =
1547
+ node.fieldFamily === "PAGE"
1548
+ ? "Current page number"
1549
+ : node.fieldFamily === "NUMPAGES"
1550
+ ? "Total pages"
1551
+ : "Section pages";
1552
+ const displayText = flattenSurfaceFieldDisplayText(node.children);
1553
+ paragraph.segments.push({
1554
+ segmentId: `${paragraph.blockId}-segment-${paragraph.segments.length}`,
1555
+ kind: "field_ref",
1556
+ from: start,
1557
+ to: start + 1,
1558
+ fieldFamily: node.fieldFamily,
1559
+ fieldTarget: node.fieldTarget,
1560
+ instruction: node.instruction,
1561
+ refreshStatus: node.refreshStatus ?? "stale",
1562
+ label: fieldLabel,
1563
+ ...(displayText ? { displayText } : {}),
1564
+ } as SurfaceInlineSegment);
1565
+ return { nextCursor: start + 1, lockedFragmentIds: [] };
1566
+ }
1540
1567
  if (node.children && node.children.length > 0) {
1541
1568
  // For REF \h, pass the bookmark as a hyperlink href so child text gets hyperlink styling
1542
1569
  const refHyperlinkHref =
@@ -1574,7 +1601,9 @@ function appendInlineSegments(
1574
1601
  ? "Current page number"
1575
1602
  : node.fieldFamily === "NUMPAGES"
1576
1603
  ? "Total pages"
1577
- : `${node.fieldFamily ?? "Field"}: ${node.fieldTarget ?? node.instruction.trim()}`;
1604
+ : node.fieldFamily === "SECTIONPAGES"
1605
+ ? "Section pages"
1606
+ : `${node.fieldFamily ?? "Field"}: ${node.fieldTarget ?? node.instruction.trim()}`;
1578
1607
  paragraph.segments.push({
1579
1608
  segmentId: `${paragraph.blockId}-segment-${paragraph.segments.length}`,
1580
1609
  kind: "field_ref",
@@ -1743,6 +1772,34 @@ function normalizeSafeCssHexColor(value: string | undefined): string | undefined
1743
1772
  return trimmed.replace(/^#/, "").toUpperCase();
1744
1773
  }
1745
1774
 
1775
+ function flattenSurfaceFieldDisplayText(
1776
+ children: readonly InlineNode[] | undefined,
1777
+ ): string {
1778
+ if (!children || children.length === 0) return "";
1779
+ const parts: string[] = [];
1780
+ for (const child of children) {
1781
+ switch (child.type) {
1782
+ case "text":
1783
+ parts.push(child.text);
1784
+ break;
1785
+ case "tab":
1786
+ case "hard_break":
1787
+ parts.push(" ");
1788
+ break;
1789
+ case "symbol":
1790
+ parts.push(child.char ? String.fromCodePoint(parseInt(child.char, 16)) : "\uFFFD");
1791
+ break;
1792
+ case "field":
1793
+ case "hyperlink":
1794
+ parts.push(flattenSurfaceFieldDisplayText(child.children));
1795
+ break;
1796
+ default:
1797
+ break;
1798
+ }
1799
+ }
1800
+ return parts.join("");
1801
+ }
1802
+
1746
1803
  /**
1747
1804
  * V2c.5 — Extract the first paragraph's plain text from a parsed
1748
1805
  * `txbxBlocks` tree for the `txbxText` segment preview. The recursion
@@ -30,7 +30,6 @@
30
30
  import type {
31
31
  EditorSessionState,
32
32
  EditorStoryTarget,
33
- FormattingAlignment,
34
33
  HeaderFooterLinkPatch,
35
34
  InsertImageOptions,
36
35
  InsertTableOptions,
@@ -41,7 +40,6 @@ import type {
41
40
  SelectionSnapshot as PublicSelectionSnapshot,
42
41
  StyleCatalogSnapshot,
43
42
  SurfaceBlockSnapshot,
44
- SurfaceInlineSegment,
45
43
  TableOp,
46
44
  } from "../api/public-types";
47
45
  import {
@@ -51,7 +49,7 @@ import {
51
49
  storyTargetsEqual,
52
50
  type TransactionMapping,
53
51
  } from "../core/selection/mapping.ts";
54
- import { applyFormattingOperationToDocument } from "../core/commands/formatting-commands.ts";
52
+ import type { FormattingOperation } from "../core/commands/formatting-commands.ts";
55
53
  import {
56
54
  applyParagraphStyleToDocument,
57
55
  applyTableStyleToDocument,
@@ -220,178 +218,15 @@ export function getRuntimeStyleCatalog(
220
218
  // Formatting (flat + suggesting-mode)
221
219
  // ---------------------------------------------------------------------------
222
220
 
223
- type FormattingOperation =
224
- | { type: "toggle"; mark: "bold" | "italic" | "underline" | "strikethrough" | "superscript" | "subscript" }
225
- | { type: "set-font-family"; fontFamily: string | null }
226
- | { type: "set-font-size"; size: number | null }
227
- | { type: "set-text-color"; color: string | null }
228
- | { type: "set-highlight-color"; color: string | null }
229
- | { type: "set-alignment"; alignment: FormattingAlignment }
230
- | { type: "indent" }
231
- | { type: "outdent" };
232
-
233
221
  export function applyRuntimeFormattingOperation(
234
222
  runtime: WordReviewEditorRuntime,
235
223
  operation: FormattingOperation,
236
224
  ): void {
237
- if (isSelectionSuggesting(runtime)) {
238
- if (applySuggestingFormattingOperation(runtime, operation)) {
239
- return;
240
- }
241
- }
242
- if (emitSuggestingUnsupportedMutation(runtime, getFormattingOperationCommandName(operation))) {
243
- return;
244
- }
245
- const context = getStoryMutationContext(runtime, getFormattingOperationCommandName(operation));
246
- if (!context) {
247
- return;
248
- }
249
-
250
- const result = applyFormattingOperationToDocument(
251
- context.localDocument,
252
- context.localSnapshot,
253
- operation,
254
- );
255
- dispatchStoryMutationResult(
256
- runtime,
257
- context,
258
- {
259
- ...result,
260
- selection: toRuntimeSelectionSnapshot(result.selection),
261
- },
262
- context.timestamp,
263
- );
264
- }
265
-
266
- function applySuggestingFormattingOperation(
267
- runtime: WordReviewEditorRuntime,
268
- operation: FormattingOperation,
269
- ): boolean {
270
- const commandName = getFormattingOperationCommandName(operation);
271
- const context = getStoryMutationContext(runtime, commandName);
272
- if (!context) {
273
- return true;
274
- }
275
- if (context.activeStory.kind !== "main") {
276
- runtime.emitBlockedCommand(commandName, [{
277
- code: "suggesting_unsupported",
278
- message: `"${commandName}" is not supported in suggesting mode for this story.`,
279
- }]);
280
- return true;
281
- }
282
-
283
- if (operation.type === "set-alignment" || operation.type === "indent" || operation.type === "outdent") {
284
- const paragraphContext = resolveActiveParagraphContext(context.localSnapshot);
285
- if (!paragraphContext) {
286
- return true;
287
- }
288
- const beforeXml = buildParagraphPropertyBeforeXml(paragraphContext.paragraph);
289
- const result = applyFormattingOperationToDocument(
290
- context.localDocument,
291
- context.localSnapshot,
292
- operation,
293
- );
294
- if (!result.changed) {
295
- return true;
296
- }
297
- const nextDocument = appendPropertyChangeSuggestion(
298
- result.document,
299
- {
300
- from: paragraphContext.paragraph.from,
301
- to: paragraphContext.paragraph.to,
302
- },
303
- {
304
- originalRevisionType: "pPrChange",
305
- xmlTag: "pPrChange",
306
- beforeXml,
307
- semanticKind: "paragraph-property-change",
308
- storyTarget: context.activeStory,
309
- authorId: runtime.getDefaultAuthorId?.(),
310
- },
311
- context.timestamp,
312
- );
313
- dispatchStoryMutationResult(
314
- runtime,
315
- context,
316
- {
317
- changed: true,
318
- document: nextDocument,
319
- selection: toRuntimeSelectionSnapshot(result.selection),
320
- },
321
- context.timestamp,
322
- );
323
- return true;
324
- }
325
-
326
- const segment = findSingleSelectedTextSegment(context.localSnapshot);
327
- if (!segment) {
328
- runtime.emitBlockedCommand(commandName, [{
329
- code: "suggesting_unsupported",
330
- message: `"${commandName}" requires one bounded text segment in suggesting mode.`,
331
- }]);
332
- return true;
333
- }
334
- const beforeXml = buildRunPropertyBeforeXml(segment);
335
- const result = applyFormattingOperationToDocument(
336
- context.localDocument,
337
- context.localSnapshot,
338
- operation,
339
- );
340
- if (!result.changed) {
341
- return true;
342
- }
343
- const nextDocument = appendPropertyChangeSuggestion(
344
- result.document,
345
- {
346
- from: segment.from,
347
- to: segment.to,
348
- },
349
- {
350
- originalRevisionType: "rPrChange",
351
- xmlTag: "rPrChange",
352
- beforeXml,
353
- semanticKind: "formatting-change",
354
- storyTarget: context.activeStory,
355
- authorId: runtime.getDefaultAuthorId?.(),
356
- },
357
- context.timestamp,
358
- );
359
- dispatchStoryMutationResult(
360
- runtime,
361
- context,
362
- {
363
- changed: true,
364
- document: nextDocument,
365
- selection: toRuntimeSelectionSnapshot(result.selection),
366
- },
367
- context.timestamp,
368
- );
369
- return true;
370
- }
371
-
372
- function getFormattingOperationCommandName(operation: FormattingOperation): string {
373
- switch (operation.type) {
374
- case "toggle":
375
- return `toggle${operation.mark.charAt(0).toUpperCase()}${operation.mark.slice(1)}`;
376
- case "set-font-family":
377
- return "setFontFamily";
378
- case "set-font-size":
379
- return "setFontSize";
380
- case "set-text-color":
381
- return "setTextColor";
382
- case "set-highlight-color":
383
- return "setHighlightColor";
384
- case "set-alignment":
385
- return "setAlignment";
386
- case "indent":
387
- return "indent";
388
- case "outdent":
389
- return "outdent";
390
- }
225
+ runtime.applyFormattingOperation(operation);
391
226
  }
392
227
 
393
228
  // ---------------------------------------------------------------------------
394
- // Suggesting-mode property-change plumbing
229
+ // Suggesting-mode guard helper for commands without bounded redline support
395
230
  // ---------------------------------------------------------------------------
396
231
 
397
232
  function emitSuggestingUnsupportedMutation(
@@ -409,192 +244,6 @@ function emitSuggestingUnsupportedMutation(
409
244
  return true;
410
245
  }
411
246
 
412
- function appendPropertyChangeSuggestion(
413
- document: EditorSessionState["canonicalDocument"],
414
- anchor: { from: number; to: number },
415
- input: {
416
- originalRevisionType: "rPrChange" | "pPrChange";
417
- xmlTag: "rPrChange" | "pPrChange";
418
- beforeXml: string;
419
- semanticKind: "formatting-change" | "paragraph-property-change";
420
- storyTarget: EditorStoryTarget;
421
- authorId?: string;
422
- },
423
- timestamp: string,
424
- ): EditorSessionState["canonicalDocument"] {
425
- const existing = document.review.revisions;
426
- const changeId = createRuntimeSuggestionChangeId(existing, timestamp);
427
- const resolvedAuthorId = input.authorId ?? "unknown";
428
- return {
429
- ...document,
430
- review: {
431
- ...document.review,
432
- revisions: {
433
- ...existing,
434
- [changeId]: {
435
- changeId,
436
- kind: "property-change",
437
- anchor: createRangeAnchor(anchor.from, anchor.to, { start: 1, end: -1 }),
438
- authorId: resolvedAuthorId,
439
- createdAt: timestamp,
440
- warningIds: [],
441
- metadata: {
442
- source: "runtime",
443
- storyTarget: input.storyTarget,
444
- suggestionId: changeId,
445
- semanticKind: input.semanticKind,
446
- originalRevisionType: input.originalRevisionType,
447
- propertyChangeData: {
448
- xmlTag: input.xmlTag,
449
- beforeXml: input.beforeXml,
450
- },
451
- },
452
- status: "open",
453
- },
454
- },
455
- },
456
- };
457
- }
458
-
459
- function createRuntimeSuggestionChangeId(
460
- existing: EditorSessionState["canonicalDocument"]["review"]["revisions"],
461
- timestamp: string,
462
- ): string {
463
- const base = `change-${timestamp.replace(/[^0-9]/gu, "")}`;
464
- let counter = Object.keys(existing).length + 1;
465
- let candidate = `${base}-p${counter}`;
466
- while (existing[candidate]) {
467
- counter += 1;
468
- candidate = `${base}-p${counter}`;
469
- }
470
- return candidate;
471
- }
472
-
473
- function findSingleSelectedTextSegment(
474
- snapshot: Pick<RuntimeRenderSnapshot, "surface" | "selection">,
475
- ): Extract<SurfaceInlineSegment, { kind: "text" }> | null {
476
- if (!snapshot.surface || snapshot.selection.activeRange.kind !== "range" || snapshot.selection.isCollapsed) {
477
- return null;
478
- }
479
- const selectionFrom = Math.min(snapshot.selection.anchor, snapshot.selection.head);
480
- const selectionTo = Math.max(snapshot.selection.anchor, snapshot.selection.head);
481
- const segments = collectSelectedTextSegments(snapshot.surface.blocks, selectionFrom, selectionTo);
482
- if (segments.length !== 1) {
483
- return null;
484
- }
485
- const [segment] = segments;
486
- if (!segment || segment.from !== selectionFrom || segment.to !== selectionTo) {
487
- return null;
488
- }
489
- return segment;
490
- }
491
-
492
- function collectSelectedTextSegments(
493
- blocks: readonly SurfaceBlockSnapshot[],
494
- selectionFrom: number,
495
- selectionTo: number,
496
- output: Array<Extract<SurfaceInlineSegment, { kind: "text" }>> = [],
497
- ): Array<Extract<SurfaceInlineSegment, { kind: "text" }>> {
498
- for (const block of blocks) {
499
- if (block.kind === "paragraph") {
500
- for (const segment of block.segments) {
501
- if (
502
- segment.kind === "text" &&
503
- rangesOverlap(selectionFrom, selectionTo, segment.from, segment.to)
504
- ) {
505
- output.push(segment);
506
- }
507
- }
508
- continue;
509
- }
510
- if (block.kind === "table") {
511
- for (const row of block.rows) {
512
- for (const cell of row.cells) {
513
- collectSelectedTextSegments(cell.content, selectionFrom, selectionTo, output);
514
- }
515
- }
516
- continue;
517
- }
518
- if (block.kind === "sdt_block") {
519
- collectSelectedTextSegments(block.children, selectionFrom, selectionTo, output);
520
- }
521
- }
522
- return output;
523
- }
524
-
525
- function rangesOverlap(
526
- leftFrom: number,
527
- leftTo: number,
528
- rightFrom: number,
529
- rightTo: number,
530
- ): boolean {
531
- return leftFrom < rightTo && rightFrom < leftTo;
532
- }
533
-
534
- function buildRunPropertyBeforeXml(
535
- segment: Extract<SurfaceInlineSegment, { kind: "text" }>,
536
- ): string {
537
- const parts: string[] = [];
538
- const marks = new Set(segment.marks ?? []);
539
- if (marks.has("bold")) parts.push("<w:b/>");
540
- if (marks.has("italic")) parts.push("<w:i/>");
541
- if (marks.has("underline")) parts.push("<w:u w:val=\"single\"/>");
542
- if (marks.has("strikethrough")) parts.push("<w:strike/>");
543
- if (marks.has("superscript")) parts.push("<w:vertAlign w:val=\"superscript\"/>");
544
- if (marks.has("subscript")) parts.push("<w:vertAlign w:val=\"subscript\"/>");
545
- if (segment.markAttrs?.fontFamily) {
546
- parts.push(`<w:rFonts w:ascii="${escapeAttributeXml(segment.markAttrs.fontFamily)}" w:hAnsi="${escapeAttributeXml(segment.markAttrs.fontFamily)}"/>`);
547
- }
548
- if (segment.markAttrs?.fontSize !== undefined) {
549
- parts.push(`<w:sz w:val="${segment.markAttrs.fontSize}"/>`);
550
- }
551
- if (segment.markAttrs?.textColor) {
552
- parts.push(`<w:color w:val="${escapeAttributeXml(segment.markAttrs.textColor)}"/>`);
553
- }
554
- if (segment.markAttrs?.backgroundColor) {
555
- parts.push(`<w:shd w:val="clear" w:color="auto" w:fill="${escapeAttributeXml(segment.markAttrs.backgroundColor)}"/>`);
556
- }
557
- return `<w:rPr>${parts.join("")}</w:rPr>`;
558
- }
559
-
560
- function buildParagraphPropertyBeforeXml(
561
- paragraph: Extract<SurfaceBlockSnapshot, { kind: "paragraph" }>,
562
- ): string {
563
- const parts: string[] = [];
564
- if (paragraph.styleId) {
565
- parts.push(`<w:pStyle w:val="${escapeAttributeXml(paragraph.styleId)}"/>`);
566
- }
567
- if (paragraph.numbering) {
568
- parts.push(
569
- `<w:numPr><w:ilvl w:val="${paragraph.numbering.level}"/><w:numId w:val="${escapeAttributeXml(
570
- paragraph.numbering.numberingInstanceId.replace(/^num:/u, ""),
571
- )}"/></w:numPr>`,
572
- );
573
- }
574
- if (paragraph.alignment) {
575
- parts.push(`<w:jc w:val="${escapeAttributeXml(paragraph.alignment)}"/>`);
576
- }
577
- if (paragraph.indentation) {
578
- const attrs: string[] = [];
579
- if (paragraph.indentation.left !== undefined) attrs.push(`w:left="${paragraph.indentation.left}"`);
580
- if (paragraph.indentation.right !== undefined) attrs.push(`w:right="${paragraph.indentation.right}"`);
581
- if (paragraph.indentation.firstLine !== undefined) attrs.push(`w:firstLine="${paragraph.indentation.firstLine}"`);
582
- if (paragraph.indentation.hanging !== undefined) attrs.push(`w:hanging="${paragraph.indentation.hanging}"`);
583
- if (attrs.length > 0) {
584
- parts.push(`<w:ind ${attrs.join(" ")}/>`);
585
- }
586
- }
587
- return `<w:pPr>${parts.join("")}</w:pPr>`;
588
- }
589
-
590
- function escapeAttributeXml(value: string): string {
591
- return value
592
- .replace(/&/g, "&amp;")
593
- .replace(/</g, "&lt;")
594
- .replace(/>/g, "&gt;")
595
- .replace(/"/g, "&quot;");
596
- }
597
-
598
247
  // ---------------------------------------------------------------------------
599
248
  // List toggle / paragraph style / table style
600
249
  // ---------------------------------------------------------------------------
@@ -1098,6 +1098,7 @@ function createLoadingRuntimeBridge(input: {
1098
1098
  getFontEntry: (name: string) =>
1099
1099
  input.sessionState.canonicalDocument.fontTable?.fonts[name],
1100
1100
  replaceText: () => undefined,
1101
+ applyFormattingOperation: () => undefined,
1101
1102
  applyScopeReplacement: () => undefined,
1102
1103
  insertFragment: () => undefined,
1103
1104
  copy: () => undefined,
@@ -1133,6 +1134,13 @@ function createLoadingRuntimeBridge(input: {
1133
1134
  addCommentReply: () => {
1134
1135
  throw createLoadingBoundaryError(input.snapshot.documentId, "comment");
1135
1136
  },
1137
+ getCommentThreadForChange: () => null,
1138
+ ensureCommentThreadForChange: () => {
1139
+ throw createLoadingBoundaryError(input.snapshot.documentId, "comment");
1140
+ },
1141
+ addReplyToChange: () => {
1142
+ throw createLoadingBoundaryError(input.snapshot.documentId, "comment");
1143
+ },
1136
1144
  editCommentBody: () => undefined,
1137
1145
  addScope: () => {
1138
1146
  throw createLoadingBoundaryError(input.snapshot.documentId, "scope");