@beyondwork/docx-react-component 1.0.132 → 1.0.134

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 (94) hide show
  1. package/dist/api/public-types.cjs +161 -68
  2. package/dist/api/public-types.d.cts +1 -1
  3. package/dist/api/public-types.d.ts +1 -1
  4. package/dist/api/public-types.js +3 -3
  5. package/dist/api/v3.cjs +9878 -7387
  6. package/dist/api/v3.d.cts +2 -2
  7. package/dist/api/v3.d.ts +2 -2
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{chunk-QUTVR72L.js → chunk-3YR47WTD.js} +296 -587
  10. package/dist/{chunk-RYMMKOFI.js → chunk-5KTJKTNE.js} +32 -0
  11. package/dist/{chunk-UP2KDOYE.js → chunk-74R5B2EZ.js} +6 -2
  12. package/dist/{chunk-6736GA6J.js → chunk-7Y6JCIK3.js} +1 -1
  13. package/dist/{chunk-43JAPM2F.js → chunk-EBSI6VQX.js} +546 -144
  14. package/dist/{chunk-JVTDBX67.js → chunk-EFEW7BTT.js} +2 -2
  15. package/dist/{chunk-YUHNDEV5.js → chunk-ESEEWELA.js} +3534 -1870
  16. package/dist/{chunk-XYTWOJII.js → chunk-IJD6D7HU.js} +745 -103
  17. package/dist/{chunk-UFPBYJMA.js → chunk-INLRCC4N.js} +2 -2
  18. package/dist/{chunk-N5FTU4HZ.js → chunk-MQ5GAJ54.js} +68 -39
  19. package/dist/{chunk-W2I47J2Q.js → chunk-NJFKPDNG.js} +216 -2
  20. package/dist/{chunk-LPLJZJT2.js → chunk-O4EDZR44.js} +131 -70
  21. package/dist/{chunk-4HGFJ6Z2.js → chunk-PZIEOEJZ.js} +1 -1
  22. package/dist/{chunk-C5LXKR54.js → chunk-QTRJLKR2.js} +1 -1
  23. package/dist/{chunk-SZ6BJA4Q.js → chunk-REFHJ2FN.js} +3 -3
  24. package/dist/{chunk-ZDYGRO2Z.js → chunk-RP76USJE.js} +1 -1
  25. package/dist/{chunk-RBWJHRNP.js → chunk-T66OS7MN.js} +8 -3
  26. package/dist/{chunk-ALWXYGXP.js → chunk-V2JF42SI.js} +2 -2
  27. package/dist/{chunk-CDEZGLQ3.js → chunk-VA24T4EB.js} +1 -1
  28. package/dist/{chunk-6TLZ6CMP.js → chunk-WDDFU2N2.js} +2 -2
  29. package/dist/{chunk-U3UMKA7B.js → chunk-XBQFDBXE.js} +1 -1
  30. package/dist/core/commands/formatting-commands.d.cts +1 -1
  31. package/dist/core/commands/formatting-commands.d.ts +1 -1
  32. package/dist/core/commands/image-commands.cjs +32 -0
  33. package/dist/core/commands/image-commands.d.cts +1 -1
  34. package/dist/core/commands/image-commands.d.ts +1 -1
  35. package/dist/core/commands/image-commands.js +5 -5
  36. package/dist/core/commands/section-layout-commands.d.cts +1 -1
  37. package/dist/core/commands/section-layout-commands.d.ts +1 -1
  38. package/dist/core/commands/style-commands.d.cts +1 -1
  39. package/dist/core/commands/style-commands.d.ts +1 -1
  40. package/dist/core/commands/table-structure-commands.cjs +32 -0
  41. package/dist/core/commands/table-structure-commands.d.cts +1 -1
  42. package/dist/core/commands/table-structure-commands.d.ts +1 -1
  43. package/dist/core/commands/table-structure-commands.js +4 -4
  44. package/dist/core/commands/text-commands.cjs +99 -38
  45. package/dist/core/commands/text-commands.d.cts +12 -1
  46. package/dist/core/commands/text-commands.d.ts +12 -1
  47. package/dist/core/commands/text-commands.js +5 -5
  48. package/dist/core/selection/mapping.d.cts +1 -1
  49. package/dist/core/selection/mapping.d.ts +1 -1
  50. package/dist/core/state/editor-state.d.cts +1 -1
  51. package/dist/core/state/editor-state.d.ts +1 -1
  52. package/dist/index.cjs +5365 -2298
  53. package/dist/index.d.cts +4 -4
  54. package/dist/index.d.ts +4 -4
  55. package/dist/index.js +388 -63
  56. package/dist/io/docx-session.cjs +7 -2
  57. package/dist/io/docx-session.d.cts +3 -3
  58. package/dist/io/docx-session.d.ts +3 -3
  59. package/dist/io/docx-session.js +4 -4
  60. package/dist/legal.js +3 -3
  61. package/dist/{loader-MAa8VpzW.d.cts → loader-CK3lZy4h.d.cts} +2 -2
  62. package/dist/{loader-CfpeEPAa.d.ts → loader-CQXplstv.d.ts} +2 -2
  63. package/dist/{public-types-KBS6JnOs.d.cts → public-types-BR1SYK2F.d.cts} +783 -189
  64. package/dist/{public-types-Cjs8glST.d.ts → public-types-DXNZVKrS.d.ts} +783 -189
  65. package/dist/public-types.cjs +161 -68
  66. package/dist/public-types.d.cts +1 -1
  67. package/dist/public-types.d.ts +1 -1
  68. package/dist/public-types.js +3 -3
  69. package/dist/runtime/collab.d.cts +2 -2
  70. package/dist/runtime/collab.d.ts +2 -2
  71. package/dist/runtime/document-runtime.cjs +1597 -444
  72. package/dist/runtime/document-runtime.d.cts +1 -1
  73. package/dist/runtime/document-runtime.d.ts +1 -1
  74. package/dist/runtime/document-runtime.js +14 -14
  75. package/dist/{session-CkoH8FoY.d.ts → session-C9UjrhJF.d.ts} +2 -2
  76. package/dist/{session-wwe0Gib-.d.cts → session-CSbwkgII.d.cts} +2 -2
  77. package/dist/session.cjs +7 -2
  78. package/dist/session.d.cts +4 -4
  79. package/dist/session.d.ts +4 -4
  80. package/dist/session.js +5 -5
  81. package/dist/tailwind.cjs +451 -650
  82. package/dist/tailwind.d.cts +1 -1
  83. package/dist/tailwind.d.ts +1 -1
  84. package/dist/tailwind.js +7 -7
  85. package/dist/{types-B3SGRW0w.d.cts → types-CZtAueri.d.cts} +1 -1
  86. package/dist/{types-CH7NWqVL.d.ts → types-RzkCXDNV.d.ts} +1 -1
  87. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +2 -2
  88. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +2 -2
  89. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  90. package/dist/ui-tailwind.cjs +451 -650
  91. package/dist/ui-tailwind.d.cts +3 -2
  92. package/dist/ui-tailwind.d.ts +3 -2
  93. package/dist/ui-tailwind.js +7 -7
  94. package/package.json +1 -1
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-M6XR534O.js";
12
12
  import {
13
13
  buildBookmarkNameMap
14
- } from "./chunk-ZDYGRO2Z.js";
14
+ } from "./chunk-RP76USJE.js";
15
15
  import {
16
16
  deleteSelectionOrBackward,
17
17
  deleteSelectionOrForward,
@@ -22,7 +22,7 @@ import {
22
22
  insertText,
23
23
  outdentParagraphAtSelection,
24
24
  splitParagraph
25
- } from "./chunk-SZ6BJA4Q.js";
25
+ } from "./chunk-REFHJ2FN.js";
26
26
  import {
27
27
  applyFormattingOperationToDocument,
28
28
  applyTextMarkOperationToDocumentRange,
@@ -32,29 +32,30 @@ import {
32
32
  insertImage,
33
33
  repositionFloatingImage,
34
34
  resizeImage
35
- } from "./chunk-UFPBYJMA.js";
35
+ } from "./chunk-INLRCC4N.js";
36
36
  import {
37
37
  applyTextTransaction
38
- } from "./chunk-N5FTU4HZ.js";
38
+ } from "./chunk-MQ5GAJ54.js";
39
39
  import {
40
40
  applyTableStructureOperationForEditableTarget,
41
41
  removeCellFromRow,
42
42
  removeTableRowPure
43
- } from "./chunk-6TLZ6CMP.js";
43
+ } from "./chunk-WDDFU2N2.js";
44
44
  import {
45
45
  resolveParagraphScope
46
- } from "./chunk-C5LXKR54.js";
46
+ } from "./chunk-QTRJLKR2.js";
47
47
  import {
48
48
  buildGeometryDebugEntry,
49
49
  collectLineBoxesForRegion,
50
50
  createGeometryFacet
51
- } from "./chunk-UP2KDOYE.js";
51
+ } from "./chunk-74R5B2EZ.js";
52
52
  import {
53
53
  AI_ACTION_POLICIES,
54
54
  allocateNumberingInstance,
55
55
  buildFormattingDebugEntry,
56
56
  cloneNumberingCatalog,
57
57
  collectScopeLocations,
58
+ computeScopeStoryLayout,
58
59
  createDocumentOutlineSnapshot,
59
60
  createDocumentSectionSnapshots,
60
61
  createScopeCompilerService,
@@ -64,19 +65,25 @@ import {
64
65
  findAllScopesAt,
65
66
  findBookmarkNameForOffset,
66
67
  findDocumentSectionSnapshot,
68
+ findOwningBlockSlotAtPosition,
69
+ findParagraphSlotAtPosition,
67
70
  findScopesIntersecting,
68
71
  findTextMatches,
69
72
  findTextWithStyleMatches,
70
73
  getListKind,
74
+ inlineLengthForScopeCoordinates,
71
75
  rebuildFieldRegistry,
76
+ removeScopeMarkersFromBlockList,
77
+ replaceParagraphChildrenAtPath,
72
78
  resolveEditableCommandTarget,
73
79
  resolveEditableTableStructureTarget,
74
80
  resolveEditableTextTarget,
75
81
  resolveHeadingPath,
76
82
  resolveScope,
83
+ sameScopeParagraphPath,
77
84
  serializeFragmentToWordML,
78
85
  setStartOverride
79
- } from "./chunk-XYTWOJII.js";
86
+ } from "./chunk-IJD6D7HU.js";
80
87
  import {
81
88
  ISSUE_METADATA_ID,
82
89
  LAYOUT_ENGINE_VERSION,
@@ -114,7 +121,7 @@ import {
114
121
  setWorkspaceMode,
115
122
  setZoomLevel,
116
123
  snapCommentAnchorAwayFromTable
117
- } from "./chunk-LPLJZJT2.js";
124
+ } from "./chunk-O4EDZR44.js";
118
125
  import {
119
126
  countLogicalPositions,
120
127
  createPlainText,
@@ -123,6 +130,7 @@ import {
123
130
  serializeTextStory
124
131
  } from "./chunk-QIO6V46H.js";
125
132
  import {
133
+ NO_EDITABLE_TARGETS_INDEX,
126
134
  ThemeColorResolver,
127
135
  createEditorSurfaceSnapshot,
128
136
  createFieldResolver,
@@ -133,7 +141,7 @@ import {
133
141
  replaceStoryBlocks,
134
142
  resolvePageFieldDisplayText,
135
143
  storyTargetKey
136
- } from "./chunk-U3UMKA7B.js";
144
+ } from "./chunk-XBQFDBXE.js";
137
145
  import {
138
146
  createCommentSidebarProjection,
139
147
  createCommentStoreFromRuntimeComments
@@ -157,12 +165,12 @@ import {
157
165
  persistedSnapshotFromEditorSessionState,
158
166
  remapRevisionStore,
159
167
  setRevisionStatus
160
- } from "./chunk-4HGFJ6Z2.js";
168
+ } from "./chunk-PZIEOEJZ.js";
161
169
  import {
162
170
  isSupportedFieldFamily,
163
171
  parseTocLevelRange,
164
172
  resolveRefFieldText
165
- } from "./chunk-RBWJHRNP.js";
173
+ } from "./chunk-T66OS7MN.js";
166
174
  import {
167
175
  collectEditableTargetRefs,
168
176
  collectEditableTargetRefsForStoryBlockRanges,
@@ -171,7 +179,7 @@ import {
171
179
  createHeaderFooterStoryKey,
172
180
  sha256TextHex,
173
181
  validateEditableTargetRef
174
- } from "./chunk-RYMMKOFI.js";
182
+ } from "./chunk-5KTJKTNE.js";
175
183
  import {
176
184
  setActiveSerializeTelemetryBus
177
185
  } from "./chunk-FM4K4XFJ.js";
@@ -521,9 +529,11 @@ function applyRevisionAction(options) {
521
529
  );
522
530
  }
523
531
  const slice = story.units.slice(range.from, range.to);
524
- if (slice.some(
525
- (unit) => unit.kind === "paragraph_break" || unit.kind === "opaque_block" || unit.kind === "structural_block"
526
- )) {
532
+ const touchesStructuralContent = slice.some(
533
+ (unit) => unit.kind === "opaque_block" || unit.kind === "structural_block"
534
+ );
535
+ const touchesParagraphBoundary = slice.some((unit) => unit.kind === "paragraph_break");
536
+ if (touchesStructuralContent || touchesParagraphBoundary && !canApplyRuntimeTextBlockDeletion(revision, options.intent)) {
527
537
  return skippedResult(
528
538
  options,
529
539
  "structural-range",
@@ -531,7 +541,7 @@ function applyRevisionAction(options) {
531
541
  );
532
542
  }
533
543
  if (slice.some(
534
- (unit) => unit.kind === "image" || unit.kind === "opaque_inline"
544
+ (unit) => unit.kind === "image" || unit.kind === "opaque_inline" || unit.kind === "protected_inline"
535
545
  )) {
536
546
  return skippedResult(
537
547
  options,
@@ -586,6 +596,9 @@ function applyRevisionAction(options) {
586
596
  detachedRevisionIds: findNewDetachedRevisionIds(options.store, nextStore)
587
597
  };
588
598
  }
599
+ function canApplyRuntimeTextBlockDeletion(revision, intent) {
600
+ return revision.metadata.source === "runtime" && (intent === "accept" && revision.kind === "deletion" && (revision.metadata.semanticKind === "replacement" || revision.metadata.semanticKind === "deletion") || intent === "reject" && revision.kind === "insertion" && (revision.metadata.semanticKind === "replacement" || revision.metadata.semanticKind === "structural-change"));
601
+ }
589
602
  function applyPairedMoveAction(options, revision) {
590
603
  const resultingStatus = toResultingStatus(options.intent);
591
604
  return {
@@ -2022,13 +2035,14 @@ function mapRecordAnchor(anchor, mapping) {
2022
2035
  return toPublicAnchorProjection(mapAnchor(toInternalAnchorProjection(anchor), mapping));
2023
2036
  }
2024
2037
  function withCommandTextTarget(context, command) {
2025
- if (!command.textTarget || context.textTarget === command.textTarget) {
2026
- return context;
2038
+ let next = context;
2039
+ if (next.precomputedSurface === void 0 && next.renderSnapshot?.surface !== void 0) {
2040
+ next = { ...next, precomputedSurface: next.renderSnapshot.surface };
2027
2041
  }
2028
- return {
2029
- ...context,
2030
- textTarget: command.textTarget
2031
- };
2042
+ if (command.textTarget && next.textTarget !== command.textTarget) {
2043
+ next = { ...next, textTarget: command.textTarget };
2044
+ }
2045
+ return next;
2032
2046
  }
2033
2047
  function listCommandContext(context) {
2034
2048
  return {
@@ -2227,6 +2241,11 @@ function executeEditorCommand(state, command, context) {
2227
2241
  );
2228
2242
  return buildDocumentReplaceTransaction(state, context, result);
2229
2243
  }
2244
+ case "fragment.insert-tracked": {
2245
+ const result = applySuggestingFragmentInsert(state, command.fragment, context);
2246
+ if (result) return result;
2247
+ return createTransaction(state, { historyBoundary: "skip", markDirty: false });
2248
+ }
2230
2249
  case "runtime.set-read-only":
2231
2250
  return createTransaction(
2232
2251
  {
@@ -3472,7 +3491,7 @@ function applyTextCommand(state, timestamp, apply) {
3472
3491
  const reviewState = remapReviewStateAfterContentChange(
3473
3492
  state,
3474
3493
  result.document,
3475
- result.mapping
3494
+ result.mapping ?? createEmptyMapping()
3476
3495
  );
3477
3496
  const scopeTagTouches = collectScopeTagTouches(
3478
3497
  state.document.review.comments,
@@ -3812,6 +3831,38 @@ function isSingleParagraphSuggestingRange(document, from, to) {
3812
3831
  );
3813
3832
  return ranges.some((range) => from >= range.start && to <= range.end);
3814
3833
  }
3834
+ function isTextOnlySuggestingRange(document, from, to) {
3835
+ const story = parseTextStory(document.content);
3836
+ const range = normalizeTextStoryRange(story, from, to);
3837
+ if (!range) {
3838
+ return isSingleParagraphSuggestingRange(document, from, to);
3839
+ }
3840
+ const rootStoryTextOnly = story.units.slice(range.from, range.to).every(isSuggestingTextReplacementUnit);
3841
+ if (rootStoryTextOnly) return true;
3842
+ return isSingleParagraphSuggestingRange(document, from, to);
3843
+ }
3844
+ function normalizeTextStoryRange(story, from, to) {
3845
+ const start = Math.min(from, to);
3846
+ const end = Math.max(from, to);
3847
+ if (start < 0 || end > story.size) return null;
3848
+ return { from: start, to: end };
3849
+ }
3850
+ function isSuggestingTextReplacementUnit(unit) {
3851
+ switch (unit.kind) {
3852
+ case "text":
3853
+ case "tab":
3854
+ case "hard_break":
3855
+ case "paragraph_break":
3856
+ case "scope_marker":
3857
+ return true;
3858
+ case "protected_inline":
3859
+ case "image":
3860
+ case "opaque_inline":
3861
+ case "opaque_block":
3862
+ case "structural_block":
3863
+ return false;
3864
+ }
3865
+ }
3815
3866
  function collectSuggestingParagraphRanges(blocks, startCursor, output, addRootParagraphBoundaries) {
3816
3867
  let cursor = startCursor;
3817
3868
  for (let index = 0; index < blocks.length; index += 1) {
@@ -3884,10 +3935,10 @@ function applySuggestingInsert(state, text, context, formatting) {
3884
3935
  const from = Math.min(selection.anchor, selection.head);
3885
3936
  const to = Math.max(selection.anchor, selection.head);
3886
3937
  const isCollapsed = from === to;
3887
- if (!isCollapsed && !isSingleParagraphSuggestingRange(state.document, from, to)) {
3938
+ if (!isCollapsed && !isTextOnlySuggestingRange(state.document, from, to)) {
3888
3939
  return createSuggestingUnsupportedTransaction(
3889
3940
  state,
3890
- "Suggesting mode does not yet support multi-paragraph replacement ranges."
3941
+ "Suggesting mode text replacement ranges must contain only editable text and paragraph breaks."
3891
3942
  );
3892
3943
  }
3893
3944
  if (isCollapsed) {
@@ -3996,7 +4047,7 @@ function applySuggestingInsert(state, text, context, formatting) {
3996
4047
  const reviewState = remapReviewStateAfterContentChange(
3997
4048
  state,
3998
4049
  result.document,
3999
- result.mapping
4050
+ result.mapping ?? createEmptyMapping()
4000
4051
  );
4001
4052
  const replacementSuggestionId = createSuggestingRevisionId(
4002
4053
  reviewState.document.review.revisions,
@@ -4061,6 +4112,131 @@ function applySuggestingInsert(state, text, context, formatting) {
4061
4112
  activeCommentId: reviewState.activeCommentId
4062
4113
  }
4063
4114
  },
4115
+ {
4116
+ historyBoundary: "push",
4117
+ markDirty: true,
4118
+ mapping: result.mapping ?? createEmptyMapping(),
4119
+ effects: {
4120
+ ...reviewState.effects,
4121
+ revisionAuthored: { changeId: insertionRevision.changeId, kind: "insertion" }
4122
+ }
4123
+ }
4124
+ );
4125
+ }
4126
+ function applySuggestingFragmentInsert(state, fragment, context) {
4127
+ if (state.readOnly) {
4128
+ return createTransaction(state, { historyBoundary: "skip", markDirty: false });
4129
+ }
4130
+ if (fragment.blocks.length === 0) {
4131
+ return createTransaction(state, { historyBoundary: "skip", markDirty: false });
4132
+ }
4133
+ if (!isTrackableSuggestingFragment(fragment)) {
4134
+ return createSuggestingUnsupportedTransaction(
4135
+ state,
4136
+ "Suggesting mode structured fragment replacement supports paragraph/text fragments only."
4137
+ );
4138
+ }
4139
+ const authorId = context.defaultAuthorId ?? "unknown";
4140
+ const selection = state.selection;
4141
+ const from = Math.min(selection.anchor, selection.head);
4142
+ const to = Math.max(selection.anchor, selection.head);
4143
+ const isCollapsed = from === to;
4144
+ if (!isCollapsed && !isTextOnlySuggestingRange(state.document, from, to)) {
4145
+ return createSuggestingUnsupportedTransaction(
4146
+ state,
4147
+ "Suggesting mode structured fragment replacement ranges must contain only editable text and paragraph breaks."
4148
+ );
4149
+ }
4150
+ const storyBefore = parseTextStory(state.document.content);
4151
+ const insertSelection = createSelectionSnapshot(to, to);
4152
+ const result = structureLayer.applyFragmentInsert(
4153
+ state.document,
4154
+ insertSelection,
4155
+ fragment,
4156
+ context
4157
+ );
4158
+ if (!result.changed) {
4159
+ return createTransaction(state, { historyBoundary: "skip", markDirty: false });
4160
+ }
4161
+ const storyAfter = parseTextStory(result.document.content);
4162
+ const insertedFrom = to;
4163
+ const insertedTo = to + Math.max(0, storyAfter.size - storyBefore.size);
4164
+ if (insertedTo <= insertedFrom) {
4165
+ return createTransaction(state, { historyBoundary: "skip", markDirty: false });
4166
+ }
4167
+ const reviewState = remapReviewStateAfterContentChange(
4168
+ state,
4169
+ result.document,
4170
+ result.mapping ?? createEmptyMapping()
4171
+ );
4172
+ const replacementSuggestionId = !isCollapsed ? createSuggestingRevisionId(
4173
+ reviewState.document.review.revisions,
4174
+ context.timestamp,
4175
+ authorId
4176
+ ) : void 0;
4177
+ let deletionRevision = !isCollapsed ? createAuthoredRevision(
4178
+ reviewState.document.review.revisions,
4179
+ "deletion",
4180
+ from,
4181
+ to,
4182
+ authorId,
4183
+ context.timestamp,
4184
+ createSuggestionMetadata({
4185
+ suggestionId: replacementSuggestionId,
4186
+ semanticKind: "replacement"
4187
+ })
4188
+ ) : void 0;
4189
+ const insertionRevision = createAuthoredRevision(
4190
+ {
4191
+ ...reviewState.document.review.revisions,
4192
+ ...deletionRevision ? { [deletionRevision.changeId]: deletionRevision } : {}
4193
+ },
4194
+ "insertion",
4195
+ insertedFrom,
4196
+ insertedTo,
4197
+ authorId,
4198
+ context.timestamp,
4199
+ createSuggestionMetadata(
4200
+ deletionRevision ? {
4201
+ suggestionId: replacementSuggestionId,
4202
+ semanticKind: "replacement",
4203
+ linkedRevisionIds: [deletionRevision.changeId]
4204
+ } : {
4205
+ semanticKind: "structural-change"
4206
+ }
4207
+ )
4208
+ );
4209
+ if (deletionRevision) {
4210
+ deletionRevision = {
4211
+ ...deletionRevision,
4212
+ metadata: {
4213
+ ...deletionRevision.metadata,
4214
+ linkedRevisionIds: [insertionRevision.changeId]
4215
+ }
4216
+ };
4217
+ }
4218
+ const finalDocument = {
4219
+ ...reviewState.document,
4220
+ review: {
4221
+ ...reviewState.document.review,
4222
+ revisions: {
4223
+ ...reviewState.document.review.revisions,
4224
+ ...deletionRevision ? { [deletionRevision.changeId]: deletionRevision } : {},
4225
+ [insertionRevision.changeId]: insertionRevision
4226
+ }
4227
+ }
4228
+ };
4229
+ return createTransaction(
4230
+ {
4231
+ ...state,
4232
+ document: finalDocument,
4233
+ selection: createSelectionSnapshot(insertedTo, insertedTo),
4234
+ warnings: reviewState.warnings,
4235
+ runtime: {
4236
+ ...state.runtime,
4237
+ activeCommentId: reviewState.activeCommentId
4238
+ }
4239
+ },
4064
4240
  {
4065
4241
  historyBoundary: "push",
4066
4242
  markDirty: true,
@@ -4072,6 +4248,10 @@ function applySuggestingInsert(state, text, context, formatting) {
4072
4248
  }
4073
4249
  );
4074
4250
  }
4251
+ function isTrackableSuggestingFragment(fragment) {
4252
+ const story = parseTextStory({ type: "doc", children: fragment.blocks });
4253
+ return story.units.every(isSuggestingTextReplacementUnit);
4254
+ }
4075
4255
  function applySuggestingDelete(state, direction, context) {
4076
4256
  if (state.readOnly) {
4077
4257
  return createTransaction(state, { historyBoundary: "skip", markDirty: false });
@@ -4081,10 +4261,10 @@ function applySuggestingDelete(state, direction, context) {
4081
4261
  const from = Math.min(selection.anchor, selection.head);
4082
4262
  const to = Math.max(selection.anchor, selection.head);
4083
4263
  const isCollapsed = from === to;
4084
- if (!isCollapsed && !isSingleParagraphSuggestingRange(state.document, from, to)) {
4264
+ if (!isCollapsed && !isTextOnlySuggestingRange(state.document, from, to)) {
4085
4265
  return createSuggestingUnsupportedTransaction(
4086
4266
  state,
4087
- "Suggesting mode does not yet support multi-paragraph deletion ranges."
4267
+ "Suggesting mode text deletion ranges must contain only editable text and paragraph breaks."
4088
4268
  );
4089
4269
  }
4090
4270
  let deleteFrom;
@@ -7232,39 +7412,8 @@ function insertScopeMarkers(document, params) {
7232
7412
  to: normalizedTo
7233
7413
  };
7234
7414
  }
7235
- const paraSlots = [];
7236
- let cursor = 0;
7237
- let fromBlockIndex = -1;
7238
- let fromBlockKind = null;
7239
- let toBlockIndex = -1;
7240
- let toBlockKind = null;
7241
- let storyLength = 0;
7242
- for (let i = 0; i < root.children.length; i += 1) {
7243
- const block = root.children[i];
7244
- const blockFrom = cursor;
7245
- let blockLength;
7246
- if (block.type === "paragraph") {
7247
- blockLength = block.children.reduce(
7248
- (total, child) => total + inlineLength(child),
7249
- 0
7250
- );
7251
- paraSlots.push({ index: i, from: blockFrom, to: blockFrom + blockLength });
7252
- } else {
7253
- blockLength = 1;
7254
- }
7255
- const blockTo = blockFrom + blockLength;
7256
- if (fromBlockIndex === -1 && normalizedFrom >= blockFrom && normalizedFrom <= blockTo) {
7257
- fromBlockIndex = i;
7258
- fromBlockKind = block.type;
7259
- }
7260
- if (toBlockIndex === -1 && normalizedTo >= blockFrom && normalizedTo <= blockTo) {
7261
- toBlockIndex = i;
7262
- toBlockKind = block.type;
7263
- }
7264
- cursor = blockTo;
7265
- if (i < root.children.length - 1) cursor += 1;
7266
- storyLength = cursor;
7267
- }
7415
+ const layout = computeScopeStoryLayout(document);
7416
+ const storyLength = layout.storyLength;
7268
7417
  if (normalizedFrom < 0 || normalizedTo > storyLength) {
7269
7418
  return {
7270
7419
  status: "range-out-of-bounds",
@@ -7274,73 +7423,71 @@ function insertScopeMarkers(document, params) {
7274
7423
  storyLength
7275
7424
  };
7276
7425
  }
7277
- if (fromBlockIndex === -1 || toBlockIndex === -1) {
7278
- return {
7279
- status: "range-out-of-bounds",
7280
- scopeId,
7281
- from: normalizedFrom,
7282
- to: normalizedTo,
7283
- storyLength
7284
- };
7285
- }
7286
- if (fromBlockKind !== "paragraph" || toBlockKind !== "paragraph") {
7287
- const nonParaIndex = fromBlockKind !== "paragraph" ? fromBlockIndex : toBlockIndex;
7288
- const nonParaKind = fromBlockKind !== "paragraph" ? fromBlockKind : toBlockKind;
7426
+ const startSlot = findParagraphSlotAtPosition(
7427
+ layout,
7428
+ normalizedFrom,
7429
+ "start"
7430
+ );
7431
+ const endSlot = findParagraphSlotAtPosition(layout, normalizedTo, "end");
7432
+ if (!startSlot || !endSlot) {
7433
+ const offenderPosition = !startSlot ? normalizedFrom : normalizedTo;
7434
+ const owner = findOwningBlockSlotAtPosition(layout, offenderPosition);
7289
7435
  return {
7290
7436
  status: "non-paragraph-target",
7291
7437
  scopeId,
7292
7438
  from: normalizedFrom,
7293
7439
  to: normalizedTo,
7294
- blockIndex: nonParaIndex,
7295
- blockKind: nonParaKind ?? "unknown"
7440
+ blockIndex: owner?.rootBlockIndex ?? -1,
7441
+ blockKind: owner?.kind ?? "unknown"
7296
7442
  };
7297
7443
  }
7298
- const startSlot = paraSlots.find((s) => s.index === fromBlockIndex);
7299
- const endSlot = paraSlots.find((s) => s.index === toBlockIndex);
7300
- if (startSlot.index === endSlot.index) {
7444
+ if (sameScopeParagraphPath(startSlot.path, endSlot.path)) {
7301
7445
  const newChildren = injectMarkersIntoInlineList(
7302
- root.children[startSlot.index].children,
7446
+ startSlot.paragraph.children,
7303
7447
  scopeId,
7304
7448
  normalizedFrom - startSlot.from,
7305
7449
  normalizedTo - startSlot.from,
7306
7450
  "both"
7307
7451
  );
7308
- const children2 = root.children.map(
7309
- (block, i) => i === startSlot.index ? { ...block, children: newChildren } : block
7452
+ const nextRoot = replaceParagraphChildrenAtPath(
7453
+ root,
7454
+ startSlot.path,
7455
+ newChildren
7310
7456
  );
7311
7457
  return {
7312
7458
  status: "planted",
7313
- document: { ...document, content: { ...root, children: children2 } },
7459
+ document: { ...document, content: nextRoot },
7314
7460
  scopeId,
7315
7461
  plantedRange: { from: normalizedFrom, to: normalizedTo }
7316
7462
  };
7317
7463
  }
7318
- const children = root.children.map((block, i) => {
7319
- if (i === startSlot.index) {
7320
- const newChildren = injectMarkersIntoInlineList(
7321
- block.children,
7322
- scopeId,
7323
- normalizedFrom - startSlot.from,
7324
- Number.POSITIVE_INFINITY,
7325
- "start-only"
7326
- );
7327
- return { ...block, children: newChildren };
7328
- }
7329
- if (i === endSlot.index) {
7330
- const newChildren = injectMarkersIntoInlineList(
7331
- block.children,
7332
- scopeId,
7333
- Number.NEGATIVE_INFINITY,
7334
- normalizedTo - endSlot.from,
7335
- "end-only"
7336
- );
7337
- return { ...block, children: newChildren };
7338
- }
7339
- return block;
7340
- });
7464
+ const startChildren = injectMarkersIntoInlineList(
7465
+ startSlot.paragraph.children,
7466
+ scopeId,
7467
+ normalizedFrom - startSlot.from,
7468
+ Number.POSITIVE_INFINITY,
7469
+ "start-only"
7470
+ );
7471
+ const endChildren = injectMarkersIntoInlineList(
7472
+ endSlot.paragraph.children,
7473
+ scopeId,
7474
+ Number.NEGATIVE_INFINITY,
7475
+ normalizedTo - endSlot.from,
7476
+ "end-only"
7477
+ );
7478
+ const rootWithStart = replaceParagraphChildrenAtPath(
7479
+ root,
7480
+ startSlot.path,
7481
+ startChildren
7482
+ );
7483
+ const rootWithBoth = replaceParagraphChildrenAtPath(
7484
+ rootWithStart,
7485
+ endSlot.path,
7486
+ endChildren
7487
+ );
7341
7488
  return {
7342
7489
  status: "planted",
7343
- document: { ...document, content: { ...root, children } },
7490
+ document: { ...document, content: rootWithBoth },
7344
7491
  scopeId,
7345
7492
  plantedRange: { from: normalizedFrom, to: normalizedTo }
7346
7493
  };
@@ -7348,43 +7495,15 @@ function insertScopeMarkers(document, params) {
7348
7495
  function removeScopeMarkers(document, scopeId) {
7349
7496
  const root = document.content;
7350
7497
  if (!root || root.type !== "doc") return document;
7351
- let mutated = false;
7352
- const children = root.children.map((block) => {
7353
- if (block.type !== "paragraph") return block;
7354
- const kept = block.children.filter((child) => {
7355
- if ((child.type === "scope_marker_start" || child.type === "scope_marker_end") && child.scopeId === scopeId) {
7356
- mutated = true;
7357
- return false;
7358
- }
7359
- return true;
7360
- });
7361
- if (kept.length === block.children.length) return block;
7362
- return { ...block, children: kept };
7363
- });
7364
- if (!mutated) return document;
7498
+ const result = removeScopeMarkersFromBlockList(root.children, scopeId);
7499
+ if (!result.mutated) return document;
7365
7500
  return {
7366
7501
  ...document,
7367
- content: { ...root, children }
7502
+ content: { ...root, children: result.blocks }
7368
7503
  };
7369
7504
  }
7370
7505
  function inlineLength(node) {
7371
- switch (node.type) {
7372
- case "text":
7373
- return Array.from(node.text).length;
7374
- case "hyperlink":
7375
- case "field":
7376
- return node.children.reduce(
7377
- (total, child) => total + inlineLength(child),
7378
- 0
7379
- );
7380
- case "bookmark_start":
7381
- case "bookmark_end":
7382
- case "scope_marker_start":
7383
- case "scope_marker_end":
7384
- return 0;
7385
- default:
7386
- return 1;
7387
- }
7506
+ return inlineLengthForScopeCoordinates(node);
7388
7507
  }
7389
7508
  function injectMarkersIntoInlineList(inlines, scopeId, startOffset, endOffset, mode) {
7390
7509
  const start = { type: "scope_marker_start", scopeId };
@@ -12592,6 +12711,14 @@ function createDocumentRuntime(options) {
12592
12711
  let effectiveMarkupModeProvider;
12593
12712
  const perfCounters = new PerfCounters();
12594
12713
  const hotEditTraces = new HotEditTraceRecorder();
12714
+ const scopeSurfaceTelemetry = {
12715
+ onPrecomputedSurfaceHit: () => {
12716
+ perfCounters.increment("surface.scope.precomputedSurfaceHit");
12717
+ },
12718
+ onScopeSurfaceBuild: () => {
12719
+ perfCounters.increment("surface.scope.builds");
12720
+ }
12721
+ };
12595
12722
  let cachedHotEditPolicy = null;
12596
12723
  function getHotEditPolicy() {
12597
12724
  if (cachedHotEditPolicy?.document === state.document) {
@@ -13040,7 +13167,7 @@ function createDocumentRuntime(options) {
13040
13167
  viewportRangesKey: rangesKey,
13041
13168
  snapshot: surface
13042
13169
  };
13043
- const fullSurface = fullSurfaceForCache ?? (surface.viewportBlockRanges === null ? surface : void 0);
13170
+ const fullSurface = fullSurfaceForCache?.viewportBlockRanges === null ? fullSurfaceForCache : surface.viewportBlockRanges === null ? surface : void 0;
13044
13171
  if (fullSurface) {
13045
13172
  cachedFullSurface = {
13046
13173
  content: state.document.content,
@@ -14603,6 +14730,7 @@ function createDocumentRuntime(options) {
14603
14730
  documentMode: workflowCoordinator.getEffectiveDocumentMode(commandSelection),
14604
14731
  defaultAuthorId: defaultAuthorId ?? void 0,
14605
14732
  renderSnapshot: cachedRenderSnapshot,
14733
+ surfaceTelemetry: scopeSurfaceTelemetry,
14606
14734
  activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
14607
14735
  editableTargetCache: editableTargetBlockCache,
14608
14736
  ...resolvedFragmentTextTarget ? { textTarget: resolvedFragmentTextTarget } : {}
@@ -14695,7 +14823,20 @@ function createDocumentRuntime(options) {
14695
14823
  selection: prepared.selection
14696
14824
  };
14697
14825
  resolvedReplayTextTarget = prepared.textTarget;
14698
- } else if (command.type === "field.refresh" || command.type === "toc.refresh" || command.type === "bookmark.edit-content" || command.type === "hyperlink.update-destination") {
14826
+ } else {
14827
+ const selectedListItemDeleteCommand = createSelectedListItemDeleteReplayCommand({
14828
+ command,
14829
+ document: replayState.document,
14830
+ selection: replayState.selection,
14831
+ surface: replaySnapshot.surface?.blocks ?? [],
14832
+ storyTarget: replayStory,
14833
+ timestamp: context.timestamp
14834
+ });
14835
+ if (selectedListItemDeleteCommand) {
14836
+ executableCommand = selectedListItemDeleteCommand;
14837
+ }
14838
+ }
14839
+ if (command.type === "field.refresh" || command.type === "toc.refresh" || command.type === "bookmark.edit-content" || command.type === "hyperlink.update-destination") {
14699
14840
  const prepared = prepareModeledTargetCommandForExecution(
14700
14841
  command,
14701
14842
  replayState.document,
@@ -14839,7 +14980,20 @@ function createDocumentRuntime(options) {
14839
14980
  selection: prepared.selection
14840
14981
  };
14841
14982
  resolvedReplayTextTarget = prepared.textTarget;
14842
- } else if (command.type === "field.refresh" || command.type === "toc.refresh" || command.type === "bookmark.edit-content" || command.type === "hyperlink.update-destination") {
14983
+ } else {
14984
+ const selectedListItemDeleteCommand = createSelectedListItemDeleteReplayCommand({
14985
+ command,
14986
+ document: stateForCommand.document,
14987
+ selection: stateForCommand.selection,
14988
+ surface: snapshotForCommand.surface?.blocks ?? [],
14989
+ storyTarget: replayStory,
14990
+ timestamp: context.timestamp
14991
+ });
14992
+ if (selectedListItemDeleteCommand) {
14993
+ executableCommand = selectedListItemDeleteCommand;
14994
+ }
14995
+ }
14996
+ if (command.type === "field.refresh" || command.type === "toc.refresh" || command.type === "bookmark.edit-content" || command.type === "hyperlink.update-destination") {
14843
14997
  const prepared = prepareModeledTargetCommandForExecution(
14844
14998
  command,
14845
14999
  stateForCommand.document,
@@ -15260,6 +15414,50 @@ function createDocumentRuntime(options) {
15260
15414
  } catch (error) {
15261
15415
  emitError(toRuntimeError(error));
15262
15416
  }
15417
+ } else if (step.kind === "fragment-replace-tracked" && step.range && step.fragment && Array.isArray(step.fragment.blocks)) {
15418
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
15419
+ if (editableTarget === null) {
15420
+ emit({
15421
+ type: "command_blocked",
15422
+ documentId: state.documentId,
15423
+ command: "applyScopeReplacement",
15424
+ reasons: [{
15425
+ code: "unsupported_surface",
15426
+ message: "Scope replacement editable target no longer resolves."
15427
+ }]
15428
+ });
15429
+ continue;
15430
+ }
15431
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
15432
+ step.range,
15433
+ step.editableTargetHint,
15434
+ editableTarget?.range
15435
+ );
15436
+ const anchor = {
15437
+ kind: "range",
15438
+ from: dispatchRange.from,
15439
+ to: dispatchRange.to,
15440
+ assoc: { start: -1, end: 1 }
15441
+ };
15442
+ const timestamp = clock();
15443
+ try {
15444
+ applyTextCommandInActiveStory(
15445
+ {
15446
+ type: "fragment.insert-tracked",
15447
+ fragment: step.fragment,
15448
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
15449
+ origin: createOrigin("api", timestamp)
15450
+ },
15451
+ {
15452
+ selection: createSelectionFromPublicAnchor(anchor),
15453
+ blockedCommandName: "applyScopeReplacement",
15454
+ documentModeOverride: "suggesting",
15455
+ skipWorkflowGuard: true
15456
+ }
15457
+ );
15458
+ } catch (error) {
15459
+ emitError(toRuntimeError(error));
15460
+ }
15263
15461
  } else if (step.kind === "text-insert-tracked" && step.range && typeof step.text === "string") {
15264
15462
  const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
15265
15463
  if (editableTarget === null) {
@@ -16875,7 +17073,8 @@ function createDocumentRuntime(options) {
16875
17073
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
16876
17074
  }
16877
17075
  const tValidation0 = performance.now();
16878
- const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
17076
+ const patchSourceSurface = getReusableCachedFullSurface(previous.document, activeStory) ?? cachedRenderSnapshot.surface;
17077
+ const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(patchSourceSurface, transaction.mapping) : null;
16879
17078
  const patchedLocalTextSurface = patchedFullLocalTextSurface ? createLocalTextCorridorSurfaceFromFullSurface(patchedFullLocalTextSurface) : null;
16880
17079
  if (patchedLocalTextSurface) {
16881
17080
  cachePatchedLocalTextSurface(
@@ -17219,11 +17418,14 @@ function createDocumentRuntime(options) {
17219
17418
  }
17220
17419
  const listBoundaryDeleteUsesStoryText = targetResolution?.kind === "accepted" && editableTarget?.listAddress?.operationScope === "list-text" && isTopLevelMainStoryBlockPath(editableTarget.blockPath) && selection.isCollapsed && (commandForDispatch.type === "text.delete-backward" && selection.anchor === targetResolution.range.from || commandForDispatch.type === "text.delete-forward" && selection.anchor === targetResolution.range.to);
17221
17420
  const textTarget = targetResolution?.kind === "accepted" && !listBoundaryDeleteUsesStoryText ? targetResolution.textTarget : legacyTextTarget;
17421
+ const fullScopeSurface = cachedFullSurface?.snapshot;
17222
17422
  const context = {
17223
17423
  timestamp,
17224
17424
  documentMode: textOptions.documentModeOverride ?? workflowCoordinator.getEffectiveDocumentMode(selection),
17225
17425
  defaultAuthorId: defaultAuthorId ?? void 0,
17226
17426
  renderSnapshot: cachedRenderSnapshot,
17427
+ surfaceTelemetry: scopeSurfaceTelemetry,
17428
+ ...fullScopeSurface ? { precomputedSurface: fullScopeSurface } : {},
17227
17429
  activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
17228
17430
  editableTargetCache: editableTargetBlockCache,
17229
17431
  activeStorySize: cachedRenderSnapshot.surface?.storySize,
@@ -17238,6 +17440,38 @@ function createDocumentRuntime(options) {
17238
17440
  const preSelection = selection;
17239
17441
  const preActiveStory = activeStory;
17240
17442
  const priorDocument = state.document;
17443
+ const selectedListItemDelete = createSelectedListItemDeleteReplacement({
17444
+ command: commandForDispatch,
17445
+ document: state.document,
17446
+ editableTarget,
17447
+ selection,
17448
+ targetResolution,
17449
+ timestamp
17450
+ });
17451
+ if (selectedListItemDelete && activeStory.kind === "main" && context.documentMode !== "suggesting") {
17452
+ const replacementCommand = {
17453
+ type: "document.replace",
17454
+ document: selectedListItemDelete.document,
17455
+ selection: selectedListItemDelete.selection,
17456
+ mapping: selectedListItemDelete.mapping,
17457
+ protectionSelection: selection,
17458
+ origin: commandForDispatch.origin
17459
+ };
17460
+ const transaction = executeEditorCommand(baseState, replacementCommand, context);
17461
+ commit(transaction);
17462
+ options.onCommandApplied?.(commandForDispatch, transaction, context, {
17463
+ preSelection,
17464
+ activeStory: preActiveStory,
17465
+ priorDocument
17466
+ });
17467
+ return completeDispatch(classifyAck({
17468
+ command: commandForDispatch,
17469
+ opId,
17470
+ priorState: baseState,
17471
+ transaction,
17472
+ newRevisionToken: state.revisionToken
17473
+ }));
17474
+ }
17241
17475
  if (activeStory.kind === "main") {
17242
17476
  const mainTransaction = executeEditorCommand(baseState, commandForDispatch, context);
17243
17477
  commit(mainTransaction);
@@ -17549,6 +17783,7 @@ function createDocumentRuntime(options) {
17549
17783
  documentMode: workflowCoordinator.getEffectiveDocumentMode(state.selection),
17550
17784
  defaultAuthorId: defaultAuthorId ?? void 0,
17551
17785
  renderSnapshot: cachedRenderSnapshot,
17786
+ surfaceTelemetry: scopeSurfaceTelemetry,
17552
17787
  activeStoryKey: canonicalEditableTargetStoryKey(activeStory),
17553
17788
  editableTargetCache: editableTargetBlockCache
17554
17789
  };
@@ -18431,7 +18666,8 @@ function getStoryPlainText(document, storyTarget, cache) {
18431
18666
  const plainText = createEditorSurfaceSnapshot(
18432
18667
  document,
18433
18668
  createSelectionSnapshot(0, 0),
18434
- storyTarget
18669
+ storyTarget,
18670
+ { editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX }
18435
18671
  ).plainText;
18436
18672
  cache.set(key, plainText);
18437
18673
  return plainText;
@@ -20116,6 +20352,172 @@ function stripStoryTarget(selection) {
20116
20352
  function isTopLevelMainStoryBlockPath(blockPath) {
20117
20353
  return typeof blockPath === "string" && /^main\/block\[\d+\]$/u.test(blockPath);
20118
20354
  }
20355
+ function createSelectedListItemDeleteReplacement(input) {
20356
+ const { command, document, editableTarget, selection, targetResolution, timestamp } = input;
20357
+ if (command.type !== "text.delete-backward" && command.type !== "text.delete-forward") {
20358
+ return null;
20359
+ }
20360
+ if (selection.isCollapsed || editableTarget?.listAddress?.operationScope !== "list-text" || targetResolution?.kind !== "accepted") {
20361
+ return null;
20362
+ }
20363
+ const selectionFrom = Math.min(selection.anchor, selection.head);
20364
+ const selectionTo = Math.max(selection.anchor, selection.head);
20365
+ if (selectionFrom !== targetResolution.range.from || selectionTo !== targetResolution.range.to) {
20366
+ return null;
20367
+ }
20368
+ const root = document.content;
20369
+ const replacement = removeNumberedParagraphAtMainStoryPath(root.children, editableTarget.blockPath);
20370
+ if (!replacement) {
20371
+ return null;
20372
+ }
20373
+ const nextDocument = {
20374
+ ...document,
20375
+ updatedAt: timestamp,
20376
+ content: {
20377
+ ...root,
20378
+ children: replacement.blocks
20379
+ }
20380
+ };
20381
+ const nextStorySize = parseTextStory(nextDocument.content).size;
20382
+ const nextAnchor = Math.min(selectionFrom, nextStorySize);
20383
+ return {
20384
+ document: nextDocument,
20385
+ selection: createSelectionSnapshot(nextAnchor, nextAnchor),
20386
+ mapping: {
20387
+ steps: [{
20388
+ from: selectionFrom,
20389
+ to: selectionTo,
20390
+ insertSize: 0
20391
+ }],
20392
+ metadata: {
20393
+ invalidatesStructures: true
20394
+ }
20395
+ }
20396
+ };
20397
+ }
20398
+ function removeNumberedParagraphAtMainStoryPath(blocks, blockPath) {
20399
+ const tokens = parseMainStoryBlockPathTokens(blockPath);
20400
+ if (!tokens) return null;
20401
+ return removeNumberedParagraphFromBlocks(blocks, tokens);
20402
+ }
20403
+ function removeNumberedParagraphFromBlocks(blocks, tokens) {
20404
+ const [token, ...rest] = tokens;
20405
+ if (!token || token.kind !== "block") return null;
20406
+ const block = blocks[token.index];
20407
+ if (!block) return null;
20408
+ if (rest.length === 0) {
20409
+ if (block.type !== "paragraph" || !block.numbering) {
20410
+ return null;
20411
+ }
20412
+ if (blocks.length === 1) {
20413
+ return { blocks: [{ type: "paragraph", children: [] }] };
20414
+ }
20415
+ return {
20416
+ blocks: [
20417
+ ...blocks.slice(0, token.index),
20418
+ ...blocks.slice(token.index + 1)
20419
+ ]
20420
+ };
20421
+ }
20422
+ const next = rest[0];
20423
+ if (block.type === "table" && next?.kind === "row") {
20424
+ const updatedTable = removeNumberedParagraphFromTable(block, rest);
20425
+ if (!updatedTable) return null;
20426
+ return {
20427
+ blocks: [
20428
+ ...blocks.slice(0, token.index),
20429
+ updatedTable,
20430
+ ...blocks.slice(token.index + 1)
20431
+ ]
20432
+ };
20433
+ }
20434
+ if ((block.type === "sdt" || block.type === "custom_xml") && next?.kind === "block") {
20435
+ const updatedChildren = removeNumberedParagraphFromBlocks(block.children, rest);
20436
+ if (!updatedChildren) return null;
20437
+ return {
20438
+ blocks: [
20439
+ ...blocks.slice(0, token.index),
20440
+ { ...block, children: updatedChildren.blocks },
20441
+ ...blocks.slice(token.index + 1)
20442
+ ]
20443
+ };
20444
+ }
20445
+ return null;
20446
+ }
20447
+ function removeNumberedParagraphFromTable(table, tokens) {
20448
+ const [rowToken, cellToken, ...childTokens] = tokens;
20449
+ if (rowToken?.kind !== "row" || cellToken?.kind !== "cell" || childTokens[0]?.kind !== "block") {
20450
+ return null;
20451
+ }
20452
+ const row2 = table.rows[rowToken.index];
20453
+ const cell = row2?.cells[cellToken.index];
20454
+ if (!row2 || !cell) return null;
20455
+ const updatedChildren = removeNumberedParagraphFromBlocks(cell.children, childTokens);
20456
+ if (!updatedChildren) return null;
20457
+ const nextCells = [
20458
+ ...row2.cells.slice(0, cellToken.index),
20459
+ { ...cell, children: updatedChildren.blocks },
20460
+ ...row2.cells.slice(cellToken.index + 1)
20461
+ ];
20462
+ const nextRows = [
20463
+ ...table.rows.slice(0, rowToken.index),
20464
+ { ...row2, cells: nextCells },
20465
+ ...table.rows.slice(rowToken.index + 1)
20466
+ ];
20467
+ return { ...table, rows: nextRows };
20468
+ }
20469
+ function createSelectedListItemDeleteReplayCommand(input) {
20470
+ const { command, document, selection, surface, storyTarget, timestamp } = input;
20471
+ if (command.type !== "text.delete-backward" && command.type !== "text.delete-forward") {
20472
+ return null;
20473
+ }
20474
+ const editableTarget = command.editableTarget;
20475
+ if (!editableTarget) {
20476
+ return null;
20477
+ }
20478
+ const targetResolution = resolveEditableTextTarget({
20479
+ document,
20480
+ selection,
20481
+ surface,
20482
+ target: editableTarget,
20483
+ activeStoryKey: canonicalEditableTargetStoryKey(storyTarget)
20484
+ });
20485
+ const replacement = createSelectedListItemDeleteReplacement({
20486
+ command,
20487
+ document,
20488
+ editableTarget,
20489
+ selection,
20490
+ targetResolution,
20491
+ timestamp
20492
+ });
20493
+ if (!replacement || storyTarget.kind !== "main") {
20494
+ return null;
20495
+ }
20496
+ return {
20497
+ type: "document.replace",
20498
+ document: replacement.document,
20499
+ selection: replacement.selection,
20500
+ mapping: replacement.mapping,
20501
+ protectionSelection: selection,
20502
+ origin: command.origin
20503
+ };
20504
+ }
20505
+ function parseMainStoryBlockPathTokens(blockPath) {
20506
+ const parts = blockPath?.split("/") ?? [];
20507
+ if (parts[0] !== "main" || parts.length < 2) {
20508
+ return null;
20509
+ }
20510
+ const tokens = [];
20511
+ for (const part of parts.slice(1)) {
20512
+ const match = /^(block|row|cell)\[(\d+)\]$/u.exec(part);
20513
+ if (!match) return null;
20514
+ tokens.push({
20515
+ kind: match[1],
20516
+ index: Number.parseInt(match[2], 10)
20517
+ });
20518
+ }
20519
+ return tokens;
20520
+ }
20119
20521
  function toInternalSelectionSnapshot(selection) {
20120
20522
  return {
20121
20523
  anchor: selection.anchor,