@magic-marker/prosemirror-suggest-changes 0.1.8

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +425 -0
  3. package/dist/addMarkStep.d.ts +12 -0
  4. package/dist/addMarkStep.js +17 -0
  5. package/dist/addNodeMarkStep.d.ts +11 -0
  6. package/dist/addNodeMarkStep.js +36 -0
  7. package/dist/attrStep.d.ts +11 -0
  8. package/dist/attrStep.js +33 -0
  9. package/dist/commands.d.ts +64 -0
  10. package/dist/commands.js +314 -0
  11. package/dist/decorations.d.ts +3 -0
  12. package/dist/decorations.js +73 -0
  13. package/dist/features/joinBlocks/__tests__/blockJoin.playwright.test.d.ts +14 -0
  14. package/dist/features/joinBlocks/__tests__/crossBlockReplace.test.d.ts +1 -0
  15. package/dist/features/joinBlocks/__tests__/getZWSPPairsInRange.test.d.ts +1 -0
  16. package/dist/features/joinBlocks/__tests__/multiStepBlockJoin.test.d.ts +1 -0
  17. package/dist/features/joinBlocks/__tests__/nestedBlockJoin.test.d.ts +1 -0
  18. package/dist/features/joinBlocks/__tests__/paragraphBackspace.test.d.ts +1 -0
  19. package/dist/features/joinBlocks/__tests__/playwrightHelpers.d.ts +143 -0
  20. package/dist/features/joinBlocks/__tests__/testHelpers.d.ts +106 -0
  21. package/dist/features/joinBlocks/index.d.ts +3 -0
  22. package/dist/features/joinBlocks/index.js +64 -0
  23. package/dist/features/joinBlocks/types.d.ts +11 -0
  24. package/dist/features/joinBlocks/types.js +1 -0
  25. package/dist/features/joinBlocks/utils/boundary.d.ts +10 -0
  26. package/dist/features/joinBlocks/utils/boundary.js +147 -0
  27. package/dist/features/joinBlocks/utils/getZWSPPairsInRange.d.ts +10 -0
  28. package/dist/features/joinBlocks/utils/getZWSPPairsInRange.js +57 -0
  29. package/dist/findSuggestionMarkEnd.d.ts +2 -0
  30. package/dist/findSuggestionMarkEnd.js +38 -0
  31. package/dist/generateId.d.ts +5 -0
  32. package/dist/generateId.js +24 -0
  33. package/dist/index.d.ts +4 -0
  34. package/dist/index.js +4 -0
  35. package/dist/plugin.d.ts +8 -0
  36. package/dist/plugin.js +38 -0
  37. package/dist/rebasePos.d.ts +9 -0
  38. package/dist/rebasePos.js +10 -0
  39. package/dist/removeMarkStep.d.ts +12 -0
  40. package/dist/removeMarkStep.js +17 -0
  41. package/dist/removeNodeMarkStep.d.ts +11 -0
  42. package/dist/removeNodeMarkStep.js +30 -0
  43. package/dist/replaceAroundStep.d.ts +12 -0
  44. package/dist/replaceAroundStep.js +96 -0
  45. package/dist/replaceStep.d.ts +35 -0
  46. package/dist/replaceStep.js +247 -0
  47. package/dist/schema.d.ts +9 -0
  48. package/dist/schema.js +139 -0
  49. package/dist/testing/difficultyMark.d.ts +2 -0
  50. package/dist/testing/testBuilders.d.ts +11 -0
  51. package/dist/utils.d.ts +11 -0
  52. package/dist/utils.js +20 -0
  53. package/dist/withSuggestChanges.d.ts +27 -0
  54. package/dist/withSuggestChanges.js +114 -0
  55. package/package.json +83 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Handle with Care Collective
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,425 @@
1
+ # @handlewithcare/prosemirror-suggest-changes
2
+
3
+ Check out
4
+ [the demo](https://handlewithcarecollective.github.io/prosemirror-suggest-changes)!
5
+
6
+ Development of this library is sponsored by the kind folks at
7
+ [dskrpt.de](https://dskrpt.de/)!
8
+
9
+ ## Installation
10
+
11
+ Install `@handlewithcare/prosemirror-suggest-changes` and its peer dependencies:
12
+
13
+ npm:
14
+
15
+ ```sh
16
+ npm install @handlewithcare/prosemirror-suggest-changes prosemirror-view prosemirror-transform prosemirror-state prosemirror-model
17
+ ```
18
+
19
+ yarn:
20
+
21
+ ```sh
22
+ yarn add @handlewithcare/prosemirror-suggest-changes prosemirror-view prosemirror-transform prosemirror-state prosemirror-model
23
+ ```
24
+
25
+ <!-- toc -->
26
+
27
+ - [Usage](#usage)
28
+ - [How it works](#how-it-works)
29
+ - [API](#api)
30
+ - [Schema](#schema)
31
+ - [`insertion`](#insertion)
32
+ - [`deletion`](#deletion)
33
+ - [`modification`](#modification)
34
+ - [`addSuggestionMarks`](#addsuggestionmarks)
35
+ - [Commands](#commands)
36
+ - [`selectSuggestion`](#selectsuggestion)
37
+ - [`revertSuggestion`](#revertsuggestion)
38
+ - [`revertSuggestions`](#revertsuggestions)
39
+ - [`revertSuggestionsInRange`](#revertsuggestionsinrange)
40
+ - [`applySuggestion`](#applysuggestion)
41
+ - [`applySuggestions`](#applysuggestions)
42
+ - [`applySuggestionsInRange`](#applysuggestionsinrange)
43
+ - [`enableSuggestChanges`](#enablesuggestchanges)
44
+ - [`disableSuggestChanges`](#disablesuggestchanges)
45
+ - [`toggleSuggestChanges`](#togglesuggestchanges)
46
+ - [Plugin](#plugin)
47
+ - [`suggestChanges`](#suggestchanges)
48
+ - [`suggestChangesKey`](#suggestchangeskey)
49
+ - [`isSuggestChangesEnabled`](#issuggestchangesenabled)
50
+ - [`dispatchTransaction` Decorator](#dispatchtransaction-decorator)
51
+ - [`withSuggestChanges`](#withsuggestchanges)
52
+
53
+ <!-- tocstop -->
54
+
55
+ ## Usage
56
+
57
+ First, add the suggestion marks to your schema:
58
+
59
+ ```ts
60
+ import { addSuggestionMarks } from "@handlewithcare/prosemirror-suggest-changes";
61
+
62
+ export const schema = new Schema({
63
+ nodes: {
64
+ ...nodes,
65
+ doc: {
66
+ ...nodes.doc,
67
+ // We need to allow these marks as block marks as well,
68
+ // to support block-level suggestions, like inserting a
69
+ // new list item
70
+ marks: "insertion modification deletion",
71
+ },
72
+ },
73
+ marks: addSuggestionMarks(marks),
74
+ });
75
+ ```
76
+
77
+ Then, add the plugin to your editor state:
78
+
79
+ ```ts
80
+ import { suggestChanges } from "@handlewithcare/prosemirror-suggest-changes";
81
+
82
+ const editorState = EditorState.create({
83
+ schema,
84
+ doc,
85
+ plugins: [
86
+ // ... your other plugins
87
+ suggestChanges(),
88
+ ],
89
+ });
90
+ ```
91
+
92
+ Use the `dispatchTransaction` decorator to intercept and transform transactions,
93
+ and add suggestion decorations:
94
+
95
+ ```ts
96
+ import {
97
+ withSuggestChanges,
98
+ getSuggestionDecorations,
99
+ } from "@handlewithcare/prosemirror-suggest-changes";
100
+
101
+ const editorEl = document.getElementById("editor")!;
102
+
103
+ const view = new EditorView(editorEl, {
104
+ state: editorState,
105
+ decorations: getSuggestionDecorations,
106
+ dispatchTransaction: withSuggestChanges(),
107
+ });
108
+ ```
109
+
110
+ And finally, use the commands to control the suggest changes state, apply
111
+ suggestions, and revert suggestions. Here’s a sample view plugin that renders a
112
+ simple menu with some suggestion-related commands:
113
+
114
+ ```ts
115
+ import {
116
+ toggleSuggestChanges,
117
+ applySuggestions,
118
+ revertSuggestions,
119
+ isSuggestChangesEnabled,
120
+ } from "@handlewithcare/prosemirror-suggest-changes";
121
+
122
+ const suggestChangesViewPlugin = new Plugin({
123
+ view(view) {
124
+ const toggleButton = document.createElement("button");
125
+ toggleButton.appendChild(document.createTextNode("Enable suggestions"));
126
+ toggleButton.addEventListener("click", () => {
127
+ toggleSuggestChanges(view.state, view.dispatch);
128
+ view.focus();
129
+ });
130
+
131
+ const applyAllButton = document.createElement("button");
132
+ applyAllButton.appendChild(document.createTextNode("Apply all"));
133
+ applyAllButton.addEventListener("click", () => {
134
+ applySuggestions(view.state, view.dispatch);
135
+ view.focus();
136
+ });
137
+
138
+ const revertAllButton = document.createElement("button");
139
+ revertAllButton.appendChild(document.createTextNode("Revert all"));
140
+ revertAllButton.addEventListener("click", () => {
141
+ revertSuggestions(view.state, view.dispatch);
142
+ view.focus();
143
+ });
144
+
145
+ const commandsContainer = document.createElement("div");
146
+ commandsContainer.append(applyAllButton, revertAllButton);
147
+
148
+ const container = document.createElement("div");
149
+ container.classList.add("menu");
150
+ container.append(toggleButton, commandsContainer);
151
+
152
+ view.dom.parentElement?.prepend(container);
153
+
154
+ return {
155
+ update() {
156
+ if (isSuggestChangesEnabled(view.state)) {
157
+ toggleButton.replaceChildren(
158
+ document.createTextNode("Disable suggestions"),
159
+ );
160
+ } else {
161
+ toggleButton.replaceChildren(
162
+ document.createTextNode("Enable suggestions"),
163
+ );
164
+ }
165
+ },
166
+ destroy() {
167
+ container.remove();
168
+ },
169
+ };
170
+ },
171
+ });
172
+ ```
173
+
174
+ ## How it works
175
+
176
+ This library provides three mark types:
177
+
178
+ - `insertion` represents newly inserted content, including new text content and
179
+ new block nodes
180
+ - `deletion` represents content that is marked as deleted, including text and
181
+ block nodes
182
+ - `modification` represents nodes whose marks or attrs have changed, but whose
183
+ content has not changed
184
+
185
+ Additionally, this library provides:
186
+
187
+ - A plugin, which keeps track of whether suggestions are enabled or not
188
+ - A decoration set factory, which renders pilcrows (¶) to make it clear to users
189
+ when block nodes have been deleted or inserted
190
+ - A set of commands (`applySuggestions`, `revertSuggestions`, `applySuggestion`,
191
+ etc), for working with suggestions
192
+ - A "`dispatchTransaction` decorator", `withSuggestChanges`
193
+
194
+ `withSuggestChanges` is a function that optionally takes a `dispatchTransaction`
195
+ function and returns a decorated `dispatchTransaction` function. This decorated
196
+ function will, when suggestions are enabled, intercept transactions before they
197
+ are applied to the state, and produce transformed transactions that suggest the
198
+ intended changes, instead of directly applying them. For example, a transaction
199
+ that attempts to delete the text between positions 2 and 5 in the document will
200
+ be replaced with a transaction that adds the `deletion` mark to the text between
201
+ positions 2 and 5.
202
+
203
+ If you already have a custom `dispatchTransaction` implementation, you can pass
204
+ it to `withSuggestChanges`. Otherwise, it will rely on the default
205
+ implementation (`view.setState(view.state.apply(tr))`).
206
+
207
+ ```ts
208
+ const view = new EditorView(editorEl, {
209
+ state: editorState,
210
+ plugins,
211
+ decorations: getSuggestionDecorations,
212
+ dispatchTransaction: withSuggestChanges(
213
+ /** An example dispatchTransaction that integrates with an external redux store */
214
+ function dispatchTransaction(this: EditorView, tr: Transaction) {
215
+ store.dispatch(transactionDispatched({ tr }));
216
+ },
217
+ ),
218
+ });
219
+ ```
220
+
221
+ ## API
222
+
223
+ ### Schema
224
+
225
+ #### `insertion`
226
+
227
+ Represents newly inserted content, including new text content and new block
228
+ nodes
229
+
230
+ ```ts
231
+ const insertion: MarkSpec;
232
+ ```
233
+
234
+ #### `deletion`
235
+
236
+ Represents content that is marked as deleted, including text and block nodes
237
+
238
+ ```ts
239
+ const deletion: MarkSpec;
240
+ ```
241
+
242
+ #### `modification`
243
+
244
+ Represents nodes whose marks or attrs have changed, but whose content has not
245
+ changed
246
+
247
+ ```ts
248
+ const modification: MarkSpec;
249
+ ```
250
+
251
+ #### `addSuggestionMarks`
252
+
253
+ Add the deletion, insertion, and modification marks to the provided MarkSpec
254
+ map.
255
+
256
+ ```ts
257
+ function addSuggestionMarks<Marks extends string>(
258
+ marks: Record<Marks, MarkSpec>,
259
+ ): Record<Marks | "deletion" | "insertion" | "modification", MarkSpec>;
260
+ ```
261
+
262
+ ### Commands
263
+
264
+ #### `selectSuggestion`
265
+
266
+ Command that updates the selection to cover an existing change.
267
+
268
+ ```ts
269
+ function selectSuggestion(suggestionId: number): Command;
270
+ ```
271
+
272
+ #### `revertSuggestion`
273
+
274
+ Command that reverts a given tracked change in a document.
275
+
276
+ This means that all content within the insertion mark will be deleted. The
277
+ deletion mark will be removed, and their contents left in the doc. Modifications
278
+ tracked in modification marks will be reverted.
279
+
280
+ ```ts
281
+ function revertSuggestion(suggestionId: number): Command;
282
+ ```
283
+
284
+ #### `revertSuggestions`
285
+
286
+ Command that reverts all tracked changes in a document.
287
+
288
+ This means that all content within insertion marks will be deleted. Deletion
289
+ marks will be removed, and their contents left in the doc. Modifications tracked
290
+ in modification marks will be reverted.
291
+
292
+ ```ts
293
+ const revertSuggestions: Command;
294
+ ```
295
+
296
+ #### `revertSuggestionsInRange`
297
+
298
+ Command that reverts all tracked changes between two positions in the document.
299
+
300
+ If `from` is not supplied, it will default to the beginning of the document. If
301
+ `to` is not supplied, it will default to the end of the document.
302
+
303
+ This means that all content within deletion marks will be deleted. Insertion
304
+ marks and modification marks will be removed, and their contents left in the
305
+ doc.
306
+
307
+ ```ts
308
+ function revertSuggestionsInRange(from?: number, to?: number): Command;
309
+ ```
310
+
311
+ #### `applySuggestion`
312
+
313
+ Command that applies a given tracked change to a document.
314
+
315
+ This means that all content within the deletion mark will be deleted. The
316
+ insertion mark and modification mark will be removed, and their contents left in
317
+ the doc.
318
+
319
+ ```ts
320
+ function applySuggestion(suggestionId: number): Command;
321
+ ```
322
+
323
+ #### `applySuggestions`
324
+
325
+ Command that applies all tracked changes in a document.
326
+
327
+ This means that all content within deletion marks will be deleted. Insertion
328
+ marks and modification marks will be removed, and their contents left in the
329
+ doc.
330
+
331
+ ```ts
332
+ const applySuggestions: Command;
333
+ ```
334
+
335
+ #### `applySuggestionsInRange`
336
+
337
+ Command that applies all tracked changes between two positions in the document.
338
+
339
+ If `from` is not supplied, it will default to the beginning of the document. If
340
+ `to` is not supplied, it will default to the end of the document.
341
+
342
+ This means that all content within deletion marks will be deleted. Insertion
343
+ marks and modification marks will be removed, and their contents left in the
344
+ doc.
345
+
346
+ ```ts
347
+ function applySuggestionsInRange(from?: number, to?: number): Command;
348
+ ```
349
+
350
+ #### `enableSuggestChanges`
351
+
352
+ Command that enables suggest changes
353
+
354
+ ```ts
355
+ const enableSuggestChanges: Command;
356
+ ```
357
+
358
+ #### `disableSuggestChanges`
359
+
360
+ Command that disables suggest changes
361
+
362
+ ```ts
363
+ const disableSuggestChanges: Command;
364
+ ```
365
+
366
+ #### `toggleSuggestChanges`
367
+
368
+ Command that toggles suggest changes on or off
369
+
370
+ ```ts
371
+ const toggleSuggestChanges: Command;
372
+ ```
373
+
374
+ ### Plugin
375
+
376
+ #### `suggestChanges`
377
+
378
+ A plugin that tracks whether suggest changes is enabled. It also provides
379
+ decorations that are useful for clarifying suggestions, such as pilcrows to mark
380
+ when paragraph breaks have been deleted or inserted.
381
+
382
+ ```ts
383
+ function suggestChanges(): Plugin<{ enabled: boolean }>;
384
+ ```
385
+
386
+ #### `suggestChangesKey`
387
+
388
+ A plugin key for the `suggestChanges` plugin
389
+
390
+ ```ts
391
+ const suggestChangesKey: PluginKey<{ enabled: boolean }>;
392
+ ```
393
+
394
+ #### `isSuggestChangesEnabled`
395
+
396
+ A helper function to check whether suggest changes is enabled.
397
+
398
+ ```ts
399
+ function isSuggestChangesEnabled(state: EditorState): boolean;
400
+ ```
401
+
402
+ ### `dispatchTransaction` Decorator
403
+
404
+ #### `withSuggestChanges`
405
+
406
+ A `dispatchTransaction` decorator. Wrap your existing `dispatchTransaction`
407
+ function with `withSuggestChanges`, or pass no arguments to use the default
408
+ implementation (`view.setState(view.state.apply(tr))`).
409
+
410
+ The result is a `dispatchTransaction` function that will intercept and modify
411
+ incoming transactions when suggest changes is enabled. These modified
412
+ transactions will suggest changes instead of directly applying them, e.g. by
413
+ marking a range with the deletion mark rather than removing it from the
414
+ document.
415
+
416
+ ```ts
417
+ function withSuggestChanges(
418
+ dispatchTransaction?: EditorView["dispatch"],
419
+ generateId?: (schema: Schema, doc?: Node) => SuggestionId,
420
+ ): EditorView["dispatch"];
421
+ ```
422
+
423
+ `generateId` can be used to customize the unique ids assigned to suggestion
424
+ marks. If undefined, the default implementation (an auto-incrementing integer)
425
+ will be used.
@@ -0,0 +1,12 @@
1
+ import { type Node } from "prosemirror-model";
2
+ import { type EditorState, type Transaction } from "prosemirror-state";
3
+ import { type AddMarkStep, type Step } from "prosemirror-transform";
4
+ import { type SuggestionId } from "./generateId.js";
5
+ /**
6
+ * Transform an add mark step into its equivalent tracked steps.
7
+ *
8
+ * Add mark steps are treated as replace steps in this model. An
9
+ * equivalent replace step will be generated, and then processed via
10
+ * trackReplaceStep().
11
+ */
12
+ export declare function trackAddMarkStep(trackedTransaction: Transaction, state: EditorState, doc: Node, step: AddMarkStep, prevSteps: Step[], suggestionId: SuggestionId): boolean;
@@ -0,0 +1,17 @@
1
+ import { replaceStep } from "prosemirror-transform";
2
+ import { applySuggestionsToRange } from "./commands.js";
3
+ import { suggestReplaceStep } from "./replaceStep.js";
4
+ /**
5
+ * Transform an add mark step into its equivalent tracked steps.
6
+ *
7
+ * Add mark steps are treated as replace steps in this model. An
8
+ * equivalent replace step will be generated, and then processed via
9
+ * trackReplaceStep().
10
+ */ export function trackAddMarkStep(trackedTransaction, state, doc, step, prevSteps, suggestionId) {
11
+ const applied = step.apply(doc).doc;
12
+ if (!applied) return false;
13
+ const slice = applySuggestionsToRange(applied, step.from, step.to);
14
+ const replace = replaceStep(doc, step.from, step.to, slice);
15
+ if (!replace) return false;
16
+ return suggestReplaceStep(trackedTransaction, state, doc, replace, prevSteps, suggestionId);
17
+ }
@@ -0,0 +1,11 @@
1
+ import { type Node } from "prosemirror-model";
2
+ import { type EditorState, type Transaction } from "prosemirror-state";
3
+ import { type AddNodeMarkStep, type Step } from "prosemirror-transform";
4
+ import { type SuggestionId } from "./generateId.js";
5
+ /**
6
+ * Transform an add node mark step into its equivalent tracked steps.
7
+ *
8
+ * Add node mark steps are processed normally, and then a modification
9
+ * mark is added to the node as well, to track the change.
10
+ */
11
+ export declare function trackAddNodeMarkStep(trackedTransaction: Transaction, state: EditorState, _doc: Node, step: AddNodeMarkStep, prevSteps: Step[], suggestionId: SuggestionId): boolean;
@@ -0,0 +1,36 @@
1
+ import { rebasePos } from "./rebasePos.js";
2
+ import { getSuggestionMarks } from "./utils.js";
3
+ /**
4
+ * Transform an add node mark step into its equivalent tracked steps.
5
+ *
6
+ * Add node mark steps are processed normally, and then a modification
7
+ * mark is added to the node as well, to track the change.
8
+ */ export function trackAddNodeMarkStep(trackedTransaction, state, _doc, step, prevSteps, suggestionId) {
9
+ const { modification } = getSuggestionMarks(state.schema);
10
+ const rebasedPos = rebasePos(step.pos, prevSteps, trackedTransaction.steps);
11
+ const $pos = trackedTransaction.doc.resolve(rebasedPos);
12
+ const node = $pos.nodeAfter;
13
+ let marks = node?.marks ?? [];
14
+ const existingMods = marks.filter((mark)=>mark.type === modification && mark.attrs["type"] === "mark" && step.mark.type.excludes(state.schema.markFromJSON(mark.attrs["newValue"]).type));
15
+ existingMods.forEach((mark)=>{
16
+ marks = mark.removeFromSet(marks);
17
+ });
18
+ let newMarks = step.mark.addToSet(marks);
19
+ let previousValue = null;
20
+ for (const mark of marks){
21
+ if (!newMarks.some((m)=>m.eq(mark))) {
22
+ previousValue = mark;
23
+ break;
24
+ }
25
+ }
26
+ newMarks = modification.create({
27
+ id: suggestionId,
28
+ type: "mark",
29
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
30
+ previousValue: previousValue?.toJSON(),
31
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
32
+ newValue: step.mark.toJSON()
33
+ }).addToSet(newMarks);
34
+ trackedTransaction.setNodeMarkup(rebasedPos, null, null, newMarks);
35
+ return true;
36
+ }
@@ -0,0 +1,11 @@
1
+ import { type Node } from "prosemirror-model";
2
+ import { type EditorState, type Transaction } from "prosemirror-state";
3
+ import { type AttrStep, type Step } from "prosemirror-transform";
4
+ import { type SuggestionId } from "./generateId.js";
5
+ /**
6
+ * Transform an attr mark step into its equivalent tracked steps.
7
+ *
8
+ * Attr steps are processed normally, and then a modification
9
+ * mark is added to the node as well, to track the change.
10
+ */
11
+ export declare function trackAttrStep(trackedTransaction: Transaction, state: EditorState, _doc: Node, step: AttrStep, prevSteps: Step[], suggestionId: SuggestionId): boolean;
@@ -0,0 +1,33 @@
1
+ import { rebasePos } from "./rebasePos.js";
2
+ import { getSuggestionMarks } from "./utils.js";
3
+ /**
4
+ * Transform an attr mark step into its equivalent tracked steps.
5
+ *
6
+ * Attr steps are processed normally, and then a modification
7
+ * mark is added to the node as well, to track the change.
8
+ */ export function trackAttrStep(trackedTransaction, state, _doc, step, prevSteps, suggestionId) {
9
+ const { modification } = getSuggestionMarks(state.schema);
10
+ const rebasedPos = rebasePos(step.pos, prevSteps, trackedTransaction.steps);
11
+ const $pos = trackedTransaction.doc.resolve(rebasedPos);
12
+ const node = $pos.nodeAfter;
13
+ let marks = node?.marks ?? [];
14
+ const existingMod = marks.find((mark)=>mark.type === modification && mark.attrs["type"] === "attr" && mark.attrs["attrName"] === step.attr);
15
+ if (existingMod) {
16
+ marks = existingMod.removeFromSet(marks);
17
+ }
18
+ marks = modification.create({
19
+ id: suggestionId,
20
+ type: "attr",
21
+ attrName: step.attr,
22
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
23
+ previousValue: node?.attrs[step.attr],
24
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
25
+ newValue: step.value
26
+ }).addToSet(marks);
27
+ trackedTransaction.setNodeMarkup(rebasedPos, null, // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
28
+ {
29
+ ...node?.attrs,
30
+ [step.attr]: step.value
31
+ }, marks);
32
+ return true;
33
+ }
@@ -0,0 +1,64 @@
1
+ import { type Node } from "prosemirror-model";
2
+ import { type Command, type EditorState } from "prosemirror-state";
3
+ import { type EditorView } from "prosemirror-view";
4
+ import { type SuggestionId } from "./generateId.js";
5
+ export declare function applySuggestionsToNode(node: Node): Node;
6
+ export declare function applySuggestionsToRange(doc: Node, from: number, to: number): import("prosemirror-model").Slice;
7
+ /**
8
+ * Command that applies all tracked changes in a document.
9
+ *
10
+ * This means that all content within deletion marks will be deleted.
11
+ * Insertion marks and modification marks will be removed, and their
12
+ * contents left in the doc.
13
+ */
14
+ export declare function applySuggestions(state: EditorState, dispatch?: EditorView["dispatch"]): boolean;
15
+ /**
16
+ * Command that applies all tracked changes in specified range.
17
+ *
18
+ * This means that all content within deletion marks will be deleted.
19
+ * Insertion marks and modification marks will be removed, and their
20
+ * contents left in the doc.
21
+ */
22
+ export declare function applySuggestionsInRange(from?: number, to?: number): Command;
23
+ /**
24
+ * Command that applies a given tracked change to a document.
25
+ *
26
+ * This means that all content within the deletion mark will be deleted.
27
+ * The insertion mark and modification mark will be removed, and their
28
+ * contents left in the doc.
29
+ */
30
+ export declare function applySuggestion(suggestionId: SuggestionId, from?: number, to?: number): Command;
31
+ /**
32
+ * Command that reverts all tracked changes in a document.
33
+ *
34
+ * This means that all content within insertion marks will be deleted.
35
+ * Deletion marks will be removed, and their contents left in the doc.
36
+ * Modifications tracked in modification marks will be reverted.
37
+ */
38
+ export declare function revertSuggestions(state: EditorState, dispatch?: EditorView["dispatch"]): boolean;
39
+ /**
40
+ * Command that reverts all tracked changes in specified range.
41
+ *
42
+ * This means that all content within insertion marks will be deleted.
43
+ * Deletion marks will be removed, and their contents left in the doc.
44
+ * Modifications tracked in modification marks will be reverted.
45
+ */
46
+ export declare function revertSuggestionsInRange(from?: number, to?: number): Command;
47
+ /**
48
+ * Command that reverts a given tracked change in a document.
49
+ *
50
+ * This means that all content within the insertion mark will be deleted.
51
+ * The deletion mark will be removed, and their contents left in the doc.
52
+ * Modifications tracked in modification marks will be reverted.
53
+ */
54
+ export declare function revertSuggestion(suggestionId: SuggestionId, from?: number, to?: number): Command;
55
+ /**
56
+ * Command that updates the selection to cover an existing change.
57
+ */
58
+ export declare function selectSuggestion(suggestionId: SuggestionId): Command;
59
+ /** Command that enables suggest changes */
60
+ export declare function enableSuggestChanges(state: EditorState, dispatch?: EditorView["dispatch"]): boolean;
61
+ /** Command that disables suggest changes */
62
+ export declare function disableSuggestChanges(state: EditorState, dispatch?: EditorView["dispatch"]): boolean;
63
+ /** Command that toggles suggest changes on or off */
64
+ export declare function toggleSuggestChanges(state: EditorState, dispatch?: EditorView["dispatch"]): boolean;