@magic-marker/prosemirror-suggest-changes 0.3.3-wrap-unwrap.0 → 0.3.3-wrap-unwrap.2

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 (113) hide show
  1. package/dist/__tests__/playwrightPage.d.ts +8 -1
  2. package/dist/commands.d.ts +1 -3
  3. package/dist/commands.js +133 -54
  4. package/dist/ensureSelectionPlugin.js +2 -2
  5. package/dist/features/wrapUnwrap/addIdAttr.d.ts +2 -0
  6. package/dist/features/wrapUnwrap/addIdAttr.js +62 -0
  7. package/dist/features/wrapUnwrap/buildMaterializedPaths.d.ts +3 -0
  8. package/dist/features/wrapUnwrap/buildMaterializedPaths.js +71 -0
  9. package/dist/features/wrapUnwrap/constants.d.ts +3 -0
  10. package/dist/features/wrapUnwrap/constants.js +7 -0
  11. package/dist/features/wrapUnwrap/generateUniqueNodeId.d.ts +1 -0
  12. package/dist/features/wrapUnwrap/generateUniqueNodeId.js +6 -0
  13. package/dist/features/wrapUnwrap/getNodeId.d.ts +2 -0
  14. package/dist/features/wrapUnwrap/getNodeId.js +5 -0
  15. package/dist/features/wrapUnwrap/revertStructureSuggestions.d.ts +9 -0
  16. package/dist/features/wrapUnwrap/revertStructureSuggestions.js +433 -0
  17. package/dist/features/wrapUnwrap/sameParentChain.d.ts +2 -0
  18. package/dist/features/wrapUnwrap/sameParentChain.js +4 -0
  19. package/dist/features/wrapUnwrap/structureChangesPlugin.d.ts +7 -0
  20. package/dist/features/wrapUnwrap/structureChangesPlugin.js +174 -0
  21. package/dist/features/wrapUnwrap/types.d.ts +44 -0
  22. package/dist/features/wrapUnwrap/types.js +13 -0
  23. package/dist/features/wrapUnwrap/uniqueNodeIdsPlugin.d.ts +17 -0
  24. package/dist/features/wrapUnwrap/uniqueNodeIdsPlugin.js +98 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.js +2 -0
  27. package/dist/replaceAroundStep.js +1 -6
  28. package/dist/replaceStep.d.ts +1 -1
  29. package/dist/replaceStep.js +0 -5
  30. package/dist/testing/e2eTestSchema.d.ts +2 -0
  31. package/dist/testing/testBuilders.d.ts +1 -1
  32. package/dist/withSuggestChanges.d.ts +5 -1
  33. package/dist/withSuggestChanges.js +44 -2
  34. package/package.json +2 -2
  35. package/src/features/wrapUnwrap/README.md +96 -167
  36. package/dist/contentBetween.d.ts +0 -2
  37. package/dist/contentBetween.js +0 -33
  38. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.data.d.ts +0 -38
  39. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.test.d.ts +0 -1
  40. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.data.d.ts +0 -45
  41. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.playwright.test.d.ts +0 -1
  42. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.test.d.ts +0 -1
  43. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.data.d.ts +0 -38
  44. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.playwright.test.d.ts +0 -1
  45. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.test.d.ts +0 -1
  46. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.data.d.ts +0 -38
  47. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.playwright.test.d.ts +0 -1
  48. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.test.d.ts +0 -1
  49. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.data.d.ts +0 -38
  50. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.playwright.test.d.ts +0 -1
  51. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.test.d.ts +0 -1
  52. package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.data.d.ts +0 -54
  53. package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.playwright.test.d.ts +0 -1
  54. package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.test.d.ts +0 -1
  55. package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.data.d.ts +0 -48
  56. package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.playwright.test.d.ts +0 -1
  57. package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.test.d.ts +0 -1
  58. package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.data.d.ts +0 -74
  59. package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.playwright.test.d.ts +0 -1
  60. package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.test.d.ts +0 -1
  61. package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.data.d.ts +0 -71
  62. package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.playwright.test.d.ts +0 -1
  63. package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.test.d.ts +0 -1
  64. package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.data.d.ts +0 -54
  65. package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.playwright.test.d.ts +0 -1
  66. package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.test.d.ts +0 -1
  67. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.data.d.ts +0 -181
  68. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.page.d.ts +0 -30
  69. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.playwright.test.d.ts +0 -1
  70. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.test.d.ts +0 -1
  71. package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.data.d.ts +0 -51
  72. package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.playwright.test.d.ts +0 -1
  73. package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.test.d.ts +0 -1
  74. package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.data.d.ts +0 -74
  75. package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.playwright.test.d.ts +0 -1
  76. package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.test.d.ts +0 -1
  77. package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.data.d.ts +0 -71
  78. package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.playwright.test.d.ts +0 -1
  79. package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.test.d.ts +0 -1
  80. package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.data.d.ts +0 -114
  81. package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.playwright.test.d.ts +0 -1
  82. package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.test.d.ts +0 -1
  83. package/dist/features/wrapUnwrap/__tests__/testUtils.d.ts +0 -5
  84. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.data.d.ts +0 -44
  85. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.playwright.test.d.ts +0 -1
  86. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.test.d.ts +0 -1
  87. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.data.d.ts +0 -38
  88. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.playwright.test.d.ts +0 -1
  89. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.test.d.ts +0 -1
  90. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.data.d.ts +0 -46
  91. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.playwright.test.d.ts +0 -1
  92. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.test.d.ts +0 -1
  93. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.data.d.ts +0 -57
  94. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.playwright.test.d.ts +0 -1
  95. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.test.d.ts +0 -1
  96. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.data.d.ts +0 -45
  97. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.playwright.test.d.ts +0 -1
  98. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.test.d.ts +0 -1
  99. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.data.d.ts +0 -44
  100. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.playwright.test.d.ts +0 -1
  101. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.test.d.ts +0 -1
  102. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.data.d.ts +0 -44
  103. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.playwright.test.d.ts +0 -1
  104. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.test.d.ts +0 -1
  105. package/dist/features/wrapUnwrap/addStructureMark.d.ts +0 -41
  106. package/dist/features/wrapUnwrap/addStructureMark.js +0 -15
  107. package/dist/features/wrapUnwrap/findMatchingNodeSides.d.ts +0 -15
  108. package/dist/features/wrapUnwrap/findMatchingNodeSides.js +0 -133
  109. package/dist/features/wrapUnwrap/handleStructureStep.d.ts +0 -4
  110. package/dist/features/wrapUnwrap/handleStructureStep.js +0 -174
  111. package/dist/features/wrapUnwrap/revertStructureSuggestion.d.ts +0 -44
  112. package/dist/features/wrapUnwrap/revertStructureSuggestion.js +0 -374
  113. /package/dist/features/wrapUnwrap/__tests__/{blockquoteUnwrapAllNodes.playwright.test.d.ts → listStructure.playwright.test.d.ts} +0 -0
@@ -1,8 +1,9 @@
1
1
  import { type Locator, type Page } from "@playwright/test";
2
2
  export declare class EditorPage {
3
3
  readonly page: Page;
4
+ readonly deletionMarksVisibility: "hidden" | "visible";
4
5
  private readonly selectors;
5
- constructor(page: Page);
6
+ constructor(page: Page, deletionMarksVisibility?: "hidden" | "visible");
6
7
  get editor(): Locator;
7
8
  getParagraphText(index: number): Promise<string>;
8
9
  getParagraphCount(): Promise<number>;
@@ -12,4 +13,10 @@ export declare class EditorPage {
12
13
  head: number;
13
14
  }>;
14
15
  getDOMTextContentOfChildAtIndex(index: number): Promise<string>;
16
+ getDocJSON(): Promise<object>;
17
+ getCurrentAndExpectedDoc(expectedDocJSON: object): Promise<{
18
+ currentDoc: import("prosemirror-model").Node;
19
+ expectedDoc: import("prosemirror-model").Node;
20
+ }>;
21
+ revertAll(): Promise<void>;
15
22
  }
@@ -51,9 +51,7 @@ export declare function revertSuggestionsInRange(from?: number, to?: number): Co
51
51
  * The deletion mark will be removed, and their contents left in the doc.
52
52
  * Modifications tracked in modification marks will be reverted.
53
53
  */
54
- export declare function revertSuggestion(suggestionId: SuggestionId, from?: number, to?: number, opts?: {
55
- structure: boolean;
56
- }): Command;
54
+ export declare function revertSuggestion(suggestionId: SuggestionId, from?: number, to?: number): Command;
57
55
  /**
58
56
  * Command that updates the selection to cover an existing change.
59
57
  */
package/dist/commands.js CHANGED
@@ -5,7 +5,7 @@ import { suggestChangesKey } from "./plugin.js";
5
5
  import { getSuggestionMarks } from "./utils.js";
6
6
  import { ZWSP } from "./constants.js";
7
7
  import { maybeRevertJoinMark } from "./features/joinOnDelete/index.js";
8
- import { applyStructureSuggestion, isStructureSuggestion, revertAllStructureSuggestions, revertStructureSuggestion } from "./features/wrapUnwrap/revertStructureSuggestion.js";
8
+ import { applyAllStructureSuggestions, applyAllStructureSuggestionsOnNode, applyOneStructureSuggestion, revertAllStructureSuggestions, revertAllStructureSuggestionsOnNode, revertOneStructureSuggestion } from "./features/wrapUnwrap/revertStructureSuggestions.js";
9
9
  /**
10
10
  * Given a node and a transform, add a set of steps to the
11
11
  * transform that applies all marks of type markTypeToApply
@@ -135,20 +135,34 @@ function applyModificationsToTransform(node, tr, dir, suggestionId, from, to) {
135
135
  }
136
136
  export function applySuggestionsToNode(node) {
137
137
  const { deletion, insertion } = getSuggestionMarks(node.type.schema);
138
- const transform = new Transform(node);
139
- applySuggestionsToTransform(node, transform, insertion, deletion);
140
- applyModificationsToTransform(node, transform, 1);
141
- return transform.doc;
138
+ // first, create a structure transform that applies all structure changes on the given node
139
+ const structureTransform = applyAllStructureSuggestionsOnNode(node);
140
+ // then start a clear transform from the document where the structure changes are applied
141
+ const suggestionsTransform = new Transform(structureTransform.doc);
142
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion);
143
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1);
144
+ // replay suggestion transform on top of the structure transform
145
+ suggestionsTransform.steps.forEach((step)=>{
146
+ structureTransform.step(step);
147
+ });
148
+ return structureTransform.doc;
142
149
  }
143
150
  export function applySuggestionsToRange(doc, from, to) {
151
+ const { deletion, insertion } = getSuggestionMarks(doc.type.schema);
144
152
  // blockRange can only return null if a predicate is provided
145
153
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
146
154
  const nodeRange = doc.resolve(from).blockRange(doc.resolve(to));
147
- const { deletion, insertion } = getSuggestionMarks(doc.type.schema);
148
- const transform = new Transform(doc);
149
- applySuggestionsToTransform(doc, transform, insertion, deletion, undefined, nodeRange.start, nodeRange.end);
150
- applyModificationsToTransform(doc, transform, 1, undefined, nodeRange.start, nodeRange.end);
151
- return transform.doc.slice(transform.mapping.map(from), transform.mapping.map(to));
155
+ // create a structure transform that applies all structure changes on the given node range
156
+ const structureTransform = applyAllStructureSuggestionsOnNode(doc, nodeRange.start, nodeRange.end);
157
+ // then start a clear transform from the document where the structure changes are applied
158
+ const suggestionsTransform = new Transform(structureTransform.doc);
159
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion, undefined, nodeRange.start, nodeRange.end);
160
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1, undefined, nodeRange.start, nodeRange.end);
161
+ // replay suggestion transform on top of the structure transform
162
+ suggestionsTransform.steps.forEach((step)=>{
163
+ structureTransform.step(step);
164
+ });
165
+ return structureTransform.doc.slice(structureTransform.mapping.map(from), structureTransform.mapping.map(to));
152
166
  }
153
167
  /**
154
168
  * Command that applies all tracked changes in a document.
@@ -158,13 +172,26 @@ export function applySuggestionsToRange(doc, from, to) {
158
172
  * contents left in the doc.
159
173
  */ export function applySuggestions(state, dispatch) {
160
174
  const { deletion, insertion } = getSuggestionMarks(state.schema);
161
- const tr = state.tr;
162
- applySuggestionsToTransform(state.doc, tr, insertion, deletion);
163
- applyModificationsToTransform(tr.doc, tr, 1);
164
- tr.setMeta(suggestChangesKey, {
175
+ // create a structure transform that applies all structure changes on the given document
176
+ const structureTransform = applyAllStructureSuggestions(state.doc);
177
+ // then start a clear transform from the document where the structure changes are applied
178
+ const suggestionsTransform = new Transform(structureTransform.doc);
179
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion);
180
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1);
181
+ // replay suggestion transform on top of the structure transform
182
+ suggestionsTransform.steps.forEach((step)=>{
183
+ structureTransform.step(step);
184
+ });
185
+ // apply the structure transform to the transaction
186
+ const transaction = state.tr;
187
+ structureTransform.steps.forEach((step)=>{
188
+ transaction.step(step);
189
+ });
190
+ if (!transaction.steps.length) return false;
191
+ transaction.setMeta(suggestChangesKey, {
165
192
  skip: true
166
193
  });
167
- dispatch?.(tr);
194
+ dispatch?.(transaction);
168
195
  return true;
169
196
  }
170
197
  /**
@@ -176,13 +203,26 @@ export function applySuggestionsToRange(doc, from, to) {
176
203
  */ export function applySuggestionsInRange(from, to) {
177
204
  return (state, dispatch)=>{
178
205
  const { deletion, insertion } = getSuggestionMarks(state.schema);
179
- const tr = state.tr;
180
- applySuggestionsToTransform(state.doc, tr, insertion, deletion, undefined, from, to);
181
- applyModificationsToTransform(tr.doc, tr, 1, undefined, from, to);
182
- tr.setMeta(suggestChangesKey, {
206
+ // create a structure transform that applies all structure changes on the given node range
207
+ const structureTransform = applyAllStructureSuggestionsOnNode(state.doc, from, to);
208
+ // then start a clear transform from the document where the structure changes are applied
209
+ const suggestionsTransform = new Transform(structureTransform.doc);
210
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion, undefined, from, to);
211
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1, undefined, from, to);
212
+ // replay suggestion transform on top of the structure transform
213
+ suggestionsTransform.steps.forEach((step)=>{
214
+ structureTransform.step(step);
215
+ });
216
+ // apply the structure transform to the transaction
217
+ const transaction = state.tr;
218
+ structureTransform.steps.forEach((step)=>{
219
+ transaction.step(step);
220
+ });
221
+ if (!transaction.steps.length) return false;
222
+ transaction.setMeta(suggestChangesKey, {
183
223
  skip: true
184
224
  });
185
- dispatch?.(tr);
225
+ dispatch?.(transaction);
186
226
  return true;
187
227
  };
188
228
  }
@@ -194,18 +234,27 @@ export function applySuggestionsToRange(doc, from, to) {
194
234
  * contents left in the doc.
195
235
  */ export function applySuggestion(suggestionId, from, to) {
196
236
  return (state, dispatch)=>{
197
- if (isStructureSuggestion(suggestionId, state.tr)) {
198
- return applyStructureSuggestion(suggestionId)(state, dispatch);
199
- }
200
237
  const { deletion, insertion } = getSuggestionMarks(state.schema);
201
- const tr = state.tr;
202
- applySuggestionsToTransform(state.doc, tr, insertion, deletion, suggestionId, from, to);
203
- applyModificationsToTransform(tr.doc, tr, 1, undefined, from, to);
204
- if (!tr.steps.length) return false;
205
- tr.setMeta(suggestChangesKey, {
238
+ // create a structure transform that applies the given structure change on the given node
239
+ const structureTransform = applyOneStructureSuggestion(state.doc, suggestionId);
240
+ // then start a clear transform from the document where the structure changes are applied
241
+ const suggestionsTransform = new Transform(structureTransform.doc);
242
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, insertion, deletion, suggestionId, from, to);
243
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, 1, undefined, from, to);
244
+ // replay suggestion transform on top of the structure transform
245
+ suggestionsTransform.steps.forEach((step)=>{
246
+ structureTransform.step(step);
247
+ });
248
+ // apply the structure transform to the transaction
249
+ const transaction = state.tr;
250
+ structureTransform.steps.forEach((step)=>{
251
+ transaction.step(step);
252
+ });
253
+ if (!transaction.steps.length) return false;
254
+ transaction.setMeta(suggestChangesKey, {
206
255
  skip: true
207
256
  });
208
- dispatch?.(tr);
257
+ dispatch?.(transaction);
209
258
  return true;
210
259
  };
211
260
  }
@@ -217,15 +266,26 @@ export function applySuggestionsToRange(doc, from, to) {
217
266
  * Modifications tracked in modification marks will be reverted.
218
267
  */ export function revertSuggestions(state, dispatch) {
219
268
  const { deletion, insertion } = getSuggestionMarks(state.schema);
220
- const tr = state.tr;
221
- const doc = state.doc;
222
- revertAllStructureSuggestions(doc, tr);
223
- applySuggestionsToTransform(doc, tr, deletion, insertion);
224
- applyModificationsToTransform(tr.doc, tr, -1);
225
- tr.setMeta(suggestChangesKey, {
269
+ // create a structure transform that reverts all structure changes on the given document
270
+ const structureTransform = revertAllStructureSuggestions(state.doc);
271
+ // then start a clear transform from the document where the structure changes are reverted
272
+ const suggestionsTransform = new Transform(structureTransform.doc);
273
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, deletion, insertion);
274
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, -1);
275
+ // replay suggestion transform on top of the structure transform
276
+ suggestionsTransform.steps.forEach((step)=>{
277
+ structureTransform.step(step);
278
+ });
279
+ // apply the structure transform to the transaction
280
+ const transaction = state.tr;
281
+ structureTransform.steps.forEach((step)=>{
282
+ transaction.step(step);
283
+ });
284
+ if (!transaction.steps.length) return false;
285
+ transaction.setMeta(suggestChangesKey, {
226
286
  skip: true
227
287
  });
228
- dispatch?.(tr);
288
+ dispatch?.(transaction);
229
289
  return true;
230
290
  }
231
291
  /**
@@ -237,13 +297,26 @@ export function applySuggestionsToRange(doc, from, to) {
237
297
  */ export function revertSuggestionsInRange(from, to) {
238
298
  return (state, dispatch)=>{
239
299
  const { deletion, insertion } = getSuggestionMarks(state.schema);
240
- const tr = state.tr;
241
- applySuggestionsToTransform(state.doc, tr, deletion, insertion, undefined, from, to);
242
- applyModificationsToTransform(tr.doc, tr, -1, undefined, from, to);
243
- tr.setMeta(suggestChangesKey, {
300
+ // create a structure transform that reverts all structure changes on the given node range
301
+ const structureTransform = revertAllStructureSuggestionsOnNode(state.doc, from, to);
302
+ // then start a clear transform from the document where the structure changes are reverted
303
+ const suggestionsTransform = new Transform(structureTransform.doc);
304
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, deletion, insertion, undefined, from, to);
305
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, -1, undefined, from, to);
306
+ // replay suggestion transform on top of the structure transform
307
+ suggestionsTransform.steps.forEach((step)=>{
308
+ structureTransform.step(step);
309
+ });
310
+ // apply the structure transform to the transaction
311
+ const transaction = state.tr;
312
+ structureTransform.steps.forEach((step)=>{
313
+ transaction.step(step);
314
+ });
315
+ if (!transaction.steps.length) return false;
316
+ transaction.setMeta(suggestChangesKey, {
244
317
  skip: true
245
318
  });
246
- dispatch?.(tr);
319
+ dispatch?.(transaction);
247
320
  return true;
248
321
  };
249
322
  }
@@ -253,23 +326,29 @@ export function applySuggestionsToRange(doc, from, to) {
253
326
  * This means that all content within the insertion mark will be deleted.
254
327
  * The deletion mark will be removed, and their contents left in the doc.
255
328
  * Modifications tracked in modification marks will be reverted.
256
- */ export function revertSuggestion(suggestionId, from, to, opts) {
329
+ */ export function revertSuggestion(suggestionId, from, to) {
257
330
  return (state, dispatch)=>{
258
- if (opts?.structure === true) {
259
- return revertStructureSuggestion(suggestionId)(state, dispatch);
260
- }
261
- if (opts?.structure !== false && isStructureSuggestion(suggestionId, state.tr)) {
262
- return revertStructureSuggestion(suggestionId)(state, dispatch);
263
- }
264
331
  const { deletion, insertion } = getSuggestionMarks(state.schema);
265
- const tr = state.tr;
266
- applySuggestionsToTransform(state.doc, tr, deletion, insertion, suggestionId, from, to);
267
- if (!tr.steps.length) return false;
268
- tr.setMeta(suggestChangesKey, {
332
+ // create a structure transform that reverts the given structure change on the given node
333
+ const structureTransform = revertOneStructureSuggestion(state.doc, suggestionId);
334
+ // then start a clear transform from the document where the structure changes are reverted
335
+ const suggestionsTransform = new Transform(structureTransform.doc);
336
+ applySuggestionsToTransform(suggestionsTransform.doc, suggestionsTransform, deletion, insertion, suggestionId, from, to);
337
+ applyModificationsToTransform(suggestionsTransform.doc, suggestionsTransform, -1, undefined, from, to);
338
+ // replay suggestion transform on top of the structure transform
339
+ suggestionsTransform.steps.forEach((step)=>{
340
+ structureTransform.step(step);
341
+ });
342
+ // apply the structure transform to the transaction
343
+ const transaction = state.tr;
344
+ structureTransform.steps.forEach((step)=>{
345
+ transaction.step(step);
346
+ });
347
+ if (!transaction.steps.length) return false;
348
+ transaction.setMeta(suggestChangesKey, {
269
349
  skip: true
270
350
  });
271
- applyModificationsToTransform(tr.doc, tr, -1, undefined, from, to);
272
- dispatch?.(tr);
351
+ dispatch?.(transaction);
273
352
  return true;
274
353
  };
275
354
  }
@@ -1,7 +1,7 @@
1
1
  import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
2
2
  import { getSuggestionMarks } from "./utils.js";
3
3
  import { ZWSP } from "./constants.js";
4
- const TRACE_ENABLED = false;
4
+ const TRACE_ENABLED = true;
5
5
  function trace(...args) {
6
6
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
7
7
  if (!TRACE_ENABLED) return;
@@ -63,7 +63,7 @@ export function ensureSelection() {
63
63
  $newAnchor
64
64
  });
65
65
  trace("appendTransaction", "search for new valid $head...");
66
- let $newHead = getNewValidPos(newState.selection.$head, getDirection(oldState.selection.$head, newState.selection.$head, pluginState));
66
+ let $newHead = newState.selection.empty ? $newAnchor : getNewValidPos(newState.selection.$head, getDirection(oldState.selection.$head, newState.selection.$head, pluginState));
67
67
  trace("appendTransaction", "new valid $head", $newHead?.pos, {
68
68
  $newHead
69
69
  });
@@ -0,0 +1,2 @@
1
+ import { type NodeSpec } from "prosemirror-model";
2
+ export declare const addIdAttr: (nodeSpec: NodeSpec, key: string) => NodeSpec;
@@ -0,0 +1,62 @@
1
+ export const addIdAttr = (nodeSpec, key)=>{
2
+ const { toDOM, parseDOM } = nodeSpec;
3
+ if (!toDOM || !parseDOM) {
4
+ console.warn("addIdAttr", "ignored node", key, "with nodeSpec", nodeSpec);
5
+ return nodeSpec;
6
+ }
7
+ const newNodeSpec = {
8
+ ...nodeSpec,
9
+ attrs: {
10
+ ...nodeSpec.attrs ?? {},
11
+ id: {
12
+ default: null
13
+ }
14
+ },
15
+ toDOM (node) {
16
+ const domOutputSpec = toDOM(node);
17
+ if (!Array.isArray(domOutputSpec)) {
18
+ console.warn("addIdAttr", "domOutputSpec is not an array, id is not added", domOutputSpec);
19
+ return domOutputSpec;
20
+ }
21
+ const id = typeof node.attrs["id"] === "string" ? node.attrs["id"] : null;
22
+ const attrs = domOutputSpec[1];
23
+ if (!Array.isArray(attrs) && typeof attrs === "object" && attrs !== null) {
24
+ const theRest = domOutputSpec.slice(2);
25
+ const result = [
26
+ domOutputSpec[0],
27
+ id ? {
28
+ ...attrs,
29
+ "data-id": id
30
+ } : attrs,
31
+ ...theRest
32
+ ];
33
+ return result;
34
+ }
35
+ const theRest = domOutputSpec.slice(1);
36
+ const result = [
37
+ domOutputSpec[0],
38
+ id ? {
39
+ "data-id": id
40
+ } : {},
41
+ ...theRest
42
+ ];
43
+ return result;
44
+ },
45
+ parseDOM: [
46
+ ...parseDOM.map((tagParseRule)=>({
47
+ ...tagParseRule,
48
+ getAttrs (dom) {
49
+ const id = dom.getAttribute("data-id");
50
+ return tagParseRule.getAttrs ? {
51
+ ...tagParseRule.getAttrs(dom),
52
+ id
53
+ } : {
54
+ id
55
+ };
56
+ }
57
+ }))
58
+ ]
59
+ };
60
+ console.info("addIdAttr", "adding id to node", key, "with nodeSpec", nodeSpec, "new nodeSpec", newNodeSpec);
61
+ return newNodeSpec;
62
+ };
@@ -0,0 +1,3 @@
1
+ import { type MaterializedPaths } from "./types.js";
2
+ import { type Node } from "prosemirror-model";
3
+ export declare function buildMaterializedPaths(doc: Node): MaterializedPaths;
@@ -0,0 +1,71 @@
1
+ import { getNodeId } from "./getNodeId.js";
2
+ export function buildMaterializedPaths(doc) {
3
+ const paths = new Map();
4
+ // add direct doc children first since they have a specific parent signature due to doc not having an ID
5
+ doc.children.forEach((node, index, children)=>{
6
+ const nodeId = getNodeId(node);
7
+ if (nodeId == null) return;
8
+ const leftSibling = children[index - 1];
9
+ const leftSiblingId = leftSibling ? getNodeId(leftSibling) : null;
10
+ const rightSibling = children[index + 1];
11
+ const rightSiblingId = rightSibling ? getNodeId(rightSibling) : null;
12
+ const parent = {
13
+ nodeId: "__doc__",
14
+ nodeType: "__doc__",
15
+ nodeAttrs: {},
16
+ nodeMarks: [],
17
+ childSiblingIds: [
18
+ leftSiblingId,
19
+ rightSiblingId
20
+ ],
21
+ childIndex: index
22
+ };
23
+ paths.set(nodeId, {
24
+ nodeType: node.type.name,
25
+ chain: [
26
+ parent
27
+ ]
28
+ });
29
+ });
30
+ // now add the rest of the nodes
31
+ doc.descendants((node, _pos, parent, childIndex)=>{
32
+ if (node.isText) return false;
33
+ const nodeId = getNodeId(node);
34
+ if (nodeId == null) return true;
35
+ // this is to avoid processing direct doc children twice
36
+ if (paths.has(nodeId)) return true;
37
+ if (parent == null) return true;
38
+ const parentId = getNodeId(parent);
39
+ if (parentId == null) return true;
40
+ // by definition, for any node it's parent chain should already exist
41
+ // because we go downwards
42
+ const parentChain = paths.get(parentId);
43
+ if (parentChain == null) return true;
44
+ const leftSibling = parent.children[childIndex - 1];
45
+ const leftSiblingId = leftSibling ? getNodeId(leftSibling) : null;
46
+ const rightSibling = parent.children[childIndex + 1];
47
+ const rightSiblingId = rightSibling ? getNodeId(rightSibling) : null;
48
+ // (this node parent chain) is (parent chain of the parent node) + (the parent node itself)
49
+ const parentDesc = {
50
+ nodeId: parentId,
51
+ nodeType: parent.type.name,
52
+ nodeAttrs: parent.attrs,
53
+ nodeMarks: parent.marks.map((mark)=>mark.toJSON()),
54
+ childSiblingIds: [
55
+ leftSiblingId,
56
+ rightSiblingId
57
+ ],
58
+ childIndex: childIndex
59
+ };
60
+ const chain = [
61
+ parentDesc,
62
+ ...parentChain.chain
63
+ ];
64
+ paths.set(nodeId, {
65
+ nodeType: node.type.name,
66
+ chain
67
+ });
68
+ return true;
69
+ });
70
+ return paths;
71
+ }
@@ -0,0 +1,3 @@
1
+ export declare const STRUCTURE_CHANGES_ADD_MARKS = "structure-changes-add-mark-type";
2
+ export declare const STRUCTURE_CHANGES_REVERT_MARKS = "structure-changes-revert-mark-type";
3
+ export declare const LIST_NODES: string[];
@@ -0,0 +1,7 @@
1
+ export const STRUCTURE_CHANGES_ADD_MARKS = "structure-changes-add-mark-type";
2
+ export const STRUCTURE_CHANGES_REVERT_MARKS = "structure-changes-revert-mark-type";
3
+ export const LIST_NODES = [
4
+ "orderedList",
5
+ "bulletList",
6
+ "listItem"
7
+ ];
@@ -0,0 +1 @@
1
+ export declare function generateUniqueNodeId(): string;
@@ -0,0 +1,6 @@
1
+ export function generateUniqueNodeId() {
2
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
3
+ return crypto.randomUUID();
4
+ }
5
+ return `node-${Math.random().toString(36).slice(2)}`;
6
+ }
@@ -0,0 +1,2 @@
1
+ import { type Node } from "prosemirror-model";
2
+ export declare function getNodeId(node: Node): string | null;
@@ -0,0 +1,5 @@
1
+ export function getNodeId(node) {
2
+ const nodeId = node.attrs["id"];
3
+ if (typeof nodeId !== "string") return null;
4
+ return nodeId;
5
+ }
@@ -0,0 +1,9 @@
1
+ import { type Node } from "prosemirror-model";
2
+ import { Transform } from "prosemirror-transform";
3
+ import { type SuggestionId } from "../../generateId.js";
4
+ export declare function applyAllStructureSuggestions(node: Node): Transform;
5
+ export declare function revertAllStructureSuggestions(node: Node): Transform;
6
+ export declare function applyOneStructureSuggestion(node: Node, suggestionId: SuggestionId): Transform;
7
+ export declare function revertOneStructureSuggestion(node: Node, suggestionId: SuggestionId): Transform;
8
+ export declare function applyAllStructureSuggestionsOnNode(node: Node, from?: number, to?: number): Transform;
9
+ export declare function revertAllStructureSuggestionsOnNode(node: Node, from?: number, to?: number): Transform;