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

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/commands.d.ts +3 -1
  2. package/dist/commands.js +14 -2
  3. package/dist/contentBetween.d.ts +2 -0
  4. package/dist/contentBetween.js +33 -0
  5. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.data.d.ts +38 -0
  6. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.playwright.test.d.ts +1 -0
  7. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.test.d.ts +1 -0
  8. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.data.d.ts +45 -0
  9. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.playwright.test.d.ts +1 -0
  10. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.test.d.ts +1 -0
  11. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.data.d.ts +38 -0
  12. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.playwright.test.d.ts +1 -0
  13. package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.test.d.ts +1 -0
  14. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.data.d.ts +38 -0
  15. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.playwright.test.d.ts +1 -0
  16. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.test.d.ts +1 -0
  17. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.data.d.ts +38 -0
  18. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.playwright.test.d.ts +1 -0
  19. package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.test.d.ts +1 -0
  20. package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.data.d.ts +54 -0
  21. package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.playwright.test.d.ts +1 -0
  22. package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.test.d.ts +1 -0
  23. package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.data.d.ts +48 -0
  24. package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.playwright.test.d.ts +1 -0
  25. package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.test.d.ts +1 -0
  26. package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.data.d.ts +74 -0
  27. package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.playwright.test.d.ts +1 -0
  28. package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.test.d.ts +1 -0
  29. package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.data.d.ts +71 -0
  30. package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.playwright.test.d.ts +1 -0
  31. package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.test.d.ts +1 -0
  32. package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.data.d.ts +54 -0
  33. package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.playwright.test.d.ts +1 -0
  34. package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.test.d.ts +1 -0
  35. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.data.d.ts +181 -0
  36. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.page.d.ts +30 -0
  37. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.playwright.test.d.ts +1 -0
  38. package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.test.d.ts +1 -0
  39. package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.data.d.ts +51 -0
  40. package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.playwright.test.d.ts +1 -0
  41. package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.test.d.ts +1 -0
  42. package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.data.d.ts +74 -0
  43. package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.playwright.test.d.ts +1 -0
  44. package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.test.d.ts +1 -0
  45. package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.data.d.ts +71 -0
  46. package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.playwright.test.d.ts +1 -0
  47. package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.test.d.ts +1 -0
  48. package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.data.d.ts +114 -0
  49. package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.playwright.test.d.ts +1 -0
  50. package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.test.d.ts +1 -0
  51. package/dist/features/wrapUnwrap/__tests__/testUtils.d.ts +5 -0
  52. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.data.d.ts +44 -0
  53. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.playwright.test.d.ts +1 -0
  54. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.test.d.ts +1 -0
  55. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.data.d.ts +38 -0
  56. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.playwright.test.d.ts +1 -0
  57. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.test.d.ts +1 -0
  58. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.data.d.ts +46 -0
  59. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.playwright.test.d.ts +1 -0
  60. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.test.d.ts +1 -0
  61. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.data.d.ts +57 -0
  62. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.playwright.test.d.ts +1 -0
  63. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.test.d.ts +1 -0
  64. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.data.d.ts +45 -0
  65. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.playwright.test.d.ts +1 -0
  66. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.test.d.ts +1 -0
  67. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.data.d.ts +44 -0
  68. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.playwright.test.d.ts +1 -0
  69. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.test.d.ts +1 -0
  70. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.data.d.ts +44 -0
  71. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.playwright.test.d.ts +1 -0
  72. package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.test.d.ts +1 -0
  73. package/dist/features/wrapUnwrap/addStructureMark.d.ts +41 -0
  74. package/dist/features/wrapUnwrap/addStructureMark.js +15 -0
  75. package/dist/features/wrapUnwrap/findMatchingNodeSides.d.ts +15 -0
  76. package/dist/features/wrapUnwrap/findMatchingNodeSides.js +133 -0
  77. package/dist/features/wrapUnwrap/handleStructureStep.d.ts +4 -0
  78. package/dist/features/wrapUnwrap/handleStructureStep.js +174 -0
  79. package/dist/features/wrapUnwrap/revertStructureSuggestion.d.ts +44 -0
  80. package/dist/features/wrapUnwrap/revertStructureSuggestion.js +374 -0
  81. package/dist/generateId.js +2 -2
  82. package/dist/index.d.ts +1 -1
  83. package/dist/index.js +1 -1
  84. package/dist/rebaseStep.d.ts +9 -0
  85. package/dist/rebaseStep.js +11 -0
  86. package/dist/replaceAroundStep.js +6 -1
  87. package/dist/replaceStep.js +5 -0
  88. package/dist/schema.d.ts +2 -1
  89. package/dist/schema.js +37 -1
  90. package/dist/testing/testBuilders.d.ts +1 -2
  91. package/dist/utils.d.ts +1 -0
  92. package/dist/utils.js +6 -2
  93. package/package.json +1 -1
  94. package/src/features/wrapUnwrap/README.md +198 -0
@@ -0,0 +1,46 @@
1
+ export declare const initialDoc: import("prosemirror-model").Node & {
2
+ tag: {
3
+ [tag: string]: number;
4
+ };
5
+ };
6
+ export declare const finalDoc: import("prosemirror-model").Node & {
7
+ tag: {
8
+ [tag: string]: number;
9
+ };
10
+ };
11
+ export declare const finalDocWithMarks: import("prosemirror-model").Node & {
12
+ tag: {
13
+ [tag: string]: number;
14
+ };
15
+ };
16
+ export declare const steps: {
17
+ stepType: string;
18
+ from: number;
19
+ to: number;
20
+ gapFrom: number;
21
+ gapTo: number;
22
+ insert: number;
23
+ slice: {
24
+ content: {
25
+ type: string;
26
+ content: {
27
+ type: string;
28
+ content: {
29
+ type: string;
30
+ }[];
31
+ }[];
32
+ }[];
33
+ openStart: number;
34
+ openEnd: number;
35
+ };
36
+ structure: boolean;
37
+ }[];
38
+ export declare const inverseSteps: {
39
+ stepType: string;
40
+ from: number;
41
+ to: number;
42
+ gapFrom: number;
43
+ gapTo: number;
44
+ insert: number;
45
+ structure: boolean;
46
+ }[];
@@ -0,0 +1,57 @@
1
+ export declare const initialDoc: import("prosemirror-model").Node & {
2
+ tag: {
3
+ [tag: string]: number;
4
+ };
5
+ };
6
+ export declare const finalDoc: import("prosemirror-model").Node & {
7
+ tag: {
8
+ [tag: string]: number;
9
+ };
10
+ };
11
+ export declare const finalDocWithMarks: import("prosemirror-model").Node & {
12
+ tag: {
13
+ [tag: string]: number;
14
+ };
15
+ };
16
+ export declare const steps: {
17
+ stepType: string;
18
+ from: number;
19
+ to: number;
20
+ gapFrom: number;
21
+ gapTo: number;
22
+ insert: number;
23
+ slice: {
24
+ content: {
25
+ type: string;
26
+ content: {
27
+ type: string;
28
+ content: {
29
+ type: string;
30
+ }[];
31
+ }[];
32
+ }[];
33
+ openStart: number;
34
+ };
35
+ structure: boolean;
36
+ }[];
37
+ export declare const inverseSteps: {
38
+ stepType: string;
39
+ from: number;
40
+ to: number;
41
+ gapFrom: number;
42
+ gapTo: number;
43
+ insert: number;
44
+ slice: {
45
+ content: {
46
+ type: string;
47
+ content: {
48
+ type: string;
49
+ content: {
50
+ type: string;
51
+ }[];
52
+ }[];
53
+ }[];
54
+ openStart: number;
55
+ };
56
+ structure: boolean;
57
+ }[];
@@ -0,0 +1,45 @@
1
+ export declare const initialDoc: import("prosemirror-model").Node & {
2
+ tag: {
3
+ [tag: string]: number;
4
+ };
5
+ };
6
+ export declare const finalDoc: import("prosemirror-model").Node & {
7
+ tag: {
8
+ [tag: string]: number;
9
+ };
10
+ };
11
+ export declare const finalDocWithMarks: import("prosemirror-model").Node & {
12
+ tag: {
13
+ [tag: string]: number;
14
+ };
15
+ };
16
+ export declare const steps: {
17
+ stepType: string;
18
+ from: number;
19
+ to: number;
20
+ gapFrom: number;
21
+ gapTo: number;
22
+ insert: number;
23
+ slice: {
24
+ content: {
25
+ type: string;
26
+ }[];
27
+ openStart: number;
28
+ };
29
+ structure: boolean;
30
+ }[];
31
+ export declare const inverseSteps: {
32
+ stepType: string;
33
+ from: number;
34
+ to: number;
35
+ gapFrom: number;
36
+ gapTo: number;
37
+ insert: number;
38
+ slice: {
39
+ content: {
40
+ type: string;
41
+ }[];
42
+ openStart: number;
43
+ };
44
+ structure: boolean;
45
+ }[];
@@ -0,0 +1,44 @@
1
+ export declare const initialDoc: import("prosemirror-model").Node & {
2
+ tag: {
3
+ [tag: string]: number;
4
+ };
5
+ };
6
+ export declare const finalDoc: import("prosemirror-model").Node & {
7
+ tag: {
8
+ [tag: string]: number;
9
+ };
10
+ };
11
+ export declare const finalDocWithMarks: import("prosemirror-model").Node & {
12
+ tag: {
13
+ [tag: string]: number;
14
+ };
15
+ };
16
+ export declare const steps: {
17
+ stepType: string;
18
+ from: number;
19
+ to: number;
20
+ gapFrom: number;
21
+ gapTo: number;
22
+ insert: number;
23
+ slice: {
24
+ content: {
25
+ type: string;
26
+ content: {
27
+ type: string;
28
+ content: {
29
+ type: string;
30
+ }[];
31
+ }[];
32
+ }[];
33
+ };
34
+ structure: boolean;
35
+ }[];
36
+ export declare const inverseSteps: {
37
+ stepType: string;
38
+ from: number;
39
+ to: number;
40
+ gapFrom: number;
41
+ gapTo: number;
42
+ insert: number;
43
+ structure: boolean;
44
+ }[];
@@ -0,0 +1,44 @@
1
+ export declare const initialDoc: import("prosemirror-model").Node & {
2
+ tag: {
3
+ [tag: string]: number;
4
+ };
5
+ };
6
+ export declare const finalDoc: import("prosemirror-model").Node & {
7
+ tag: {
8
+ [tag: string]: number;
9
+ };
10
+ };
11
+ export declare const finalDocWithMarks: import("prosemirror-model").Node & {
12
+ tag: {
13
+ [tag: string]: number;
14
+ };
15
+ };
16
+ export declare const steps: {
17
+ stepType: string;
18
+ from: number;
19
+ to: number;
20
+ gapFrom: number;
21
+ gapTo: number;
22
+ insert: number;
23
+ slice: {
24
+ content: {
25
+ type: string;
26
+ content: {
27
+ type: string;
28
+ content: {
29
+ type: string;
30
+ }[];
31
+ }[];
32
+ }[];
33
+ };
34
+ structure: boolean;
35
+ }[];
36
+ export declare const inverseSteps: {
37
+ stepType: string;
38
+ from: number;
39
+ to: number;
40
+ gapFrom: number;
41
+ gapTo: number;
42
+ insert: number;
43
+ structure: boolean;
44
+ }[];
@@ -0,0 +1,41 @@
1
+ import { type Transaction } from "prosemirror-state";
2
+ import { type SuggestionId } from "../../generateId.js";
3
+ import { type MatchingNodeSide } from "./findMatchingNodeSides.js";
4
+ import { type Slice } from "prosemirror-model";
5
+ type ReplaceAroundData = {
6
+ type: "replaceAround";
7
+ slice: Slice;
8
+ insert: number;
9
+ structure: boolean;
10
+ debug?: object;
11
+ } & ({
12
+ value: "gapFrom";
13
+ position: MatchingNodeSide;
14
+ fromOffset: number;
15
+ } | {
16
+ value: "gapTo";
17
+ position: MatchingNodeSide;
18
+ toOffset: number;
19
+ } | {
20
+ value: "from";
21
+ position: MatchingNodeSide;
22
+ gapFromOffset: number;
23
+ } | {
24
+ value: "to";
25
+ position: MatchingNodeSide;
26
+ gapToOffset: number;
27
+ });
28
+ type ReplaceData = {
29
+ type: "replace";
30
+ slice: Slice;
31
+ structure: boolean;
32
+ debug?: object;
33
+ } & ({
34
+ value: "from";
35
+ position: MatchingNodeSide;
36
+ } | {
37
+ value: "to";
38
+ position: MatchingNodeSide;
39
+ });
40
+ export declare function addStructureMark(suggestionId: SuggestionId, pos: number, payload: ReplaceAroundData | ReplaceData, transaction: Transaction): void;
41
+ export {};
@@ -0,0 +1,15 @@
1
+ import { getSuggestionMarks } from "../../utils.js";
2
+ export function addStructureMark(suggestionId, pos, payload, transaction) {
3
+ const { structure } = getSuggestionMarks(transaction.doc.type.schema);
4
+ transaction.addNodeMark(pos, structure.create({
5
+ id: suggestionId,
6
+ data: {
7
+ ...payload,
8
+ slice: payload.slice.toJSON()
9
+ }
10
+ }));
11
+ console.log("added structure mark", {
12
+ suggestionId,
13
+ payload
14
+ });
15
+ }
@@ -0,0 +1,15 @@
1
+ import { type Node, type NodeRange } from "prosemirror-model";
2
+ export type MatchingNodeSide = "start" | "innerStart" | "end" | "innerEnd";
3
+ export declare function findMatchingNodeSides(doc: Node, range: NodeRange, positions: {
4
+ from: number;
5
+ to: number;
6
+ }): {
7
+ from: {
8
+ side: MatchingNodeSide;
9
+ pos: number;
10
+ };
11
+ to: {
12
+ side: MatchingNodeSide;
13
+ pos: number;
14
+ };
15
+ };
@@ -0,0 +1,133 @@
1
+ export function findMatchingNodeSides(doc, range, positions) {
2
+ // we make 2 passes
3
+ // we visit every node in range, and look at its starting (startPos) and inner starting (innerStartPos) positions
4
+ // (starting - at the start of the node, outside of it, inner starting - inside the node right after its opening token)
5
+ // we see if "from" and/or "to" match "startPos" or "innerStartPos"
6
+ // (if "from" matches "startPos" or "innerStartPos", we quickly check if "to" matches "endPos" or "innerEndPos",
7
+ // this prioritizes the best case scenario when both "from" and "to" are located at the same node)
8
+ // second pass we visit every node in range and look at its ending positions in the similar fashion
9
+ let fromSide = null;
10
+ let toSide = null;
11
+ let fromNode = null;
12
+ let toNode = null;
13
+ let fromPos = null;
14
+ let toPos = null;
15
+ doc.nodesBetween(range.start, range.end, (node, pos)=>{
16
+ if (node.isInline) return true;
17
+ const startPos = pos;
18
+ const innerStartPos = pos + 1;
19
+ // is from at startPos?
20
+ if (fromSide === null && startPos === positions.from) {
21
+ fromSide = "start";
22
+ fromNode = node;
23
+ fromPos = pos;
24
+ }
25
+ // is from at innerStart pos?
26
+ if (fromSide === null && innerStartPos === positions.from) {
27
+ fromSide = "innerStart";
28
+ fromNode = node;
29
+ fromPos = pos;
30
+ }
31
+ // if we have found from at the starting position of this node, try to find to at the ending positions
32
+ if (startPos === positions.from || innerStartPos === positions.from) {
33
+ const endPos = pos + node.nodeSize;
34
+ const innerEndPos = pos + node.nodeSize - 1;
35
+ // is to at endPos?
36
+ if (toSide === null && endPos === positions.to) {
37
+ toSide = "end";
38
+ toNode = node;
39
+ toPos = pos;
40
+ }
41
+ // is to at innerEndPos?
42
+ if (toSide === null && innerEndPos === positions.to) {
43
+ toSide = "innerEnd";
44
+ toNode = node;
45
+ toPos = pos;
46
+ }
47
+ }
48
+ // is to at startPos?
49
+ if (toSide === null && startPos === positions.to) {
50
+ toSide = "start";
51
+ toNode = node;
52
+ toPos = pos;
53
+ }
54
+ // is to at innerStart pos?
55
+ if (toSide === null && innerStartPos === positions.to) {
56
+ toSide = "innerStart";
57
+ toNode = node;
58
+ toPos = pos;
59
+ }
60
+ return true;
61
+ });
62
+ doc.nodesBetween(range.start, range.end, (node, pos)=>{
63
+ if (node.isInline) return true;
64
+ const endPos = pos + node.nodeSize;
65
+ const innerEndPos = pos + node.nodeSize - 1;
66
+ // is from at endPos?
67
+ if (fromSide === null && endPos === positions.from) {
68
+ fromSide = "end";
69
+ fromNode = node;
70
+ fromPos = pos;
71
+ }
72
+ // is from at innerEndPos?
73
+ if (fromSide === null && innerEndPos === positions.from) {
74
+ fromSide = "innerEnd";
75
+ fromNode = node;
76
+ fromPos = pos;
77
+ }
78
+ // is to at endPos?
79
+ if (toSide === null && endPos === positions.to) {
80
+ toSide = "end";
81
+ toNode = node;
82
+ toPos = pos;
83
+ }
84
+ // is to at innerEndPos?
85
+ if (toSide === null && innerEndPos === positions.to) {
86
+ toSide = "innerEnd";
87
+ toNode = node;
88
+ toPos = pos;
89
+ }
90
+ return true;
91
+ });
92
+ if (fromSide === null || toSide === null || fromPos === null || toPos === null) {
93
+ console.error("Not all positions found", {
94
+ positions,
95
+ range,
96
+ from: {
97
+ side: fromSide,
98
+ pos: fromPos,
99
+ node: fromNode
100
+ },
101
+ to: {
102
+ side: toSide,
103
+ pos: toPos,
104
+ node: toNode
105
+ }
106
+ });
107
+ throw new Error("Not all positions found");
108
+ }
109
+ console.log("found matching node sides", {
110
+ positions,
111
+ range,
112
+ from: {
113
+ side: fromSide,
114
+ pos: fromPos,
115
+ node: fromNode
116
+ },
117
+ to: {
118
+ side: toSide,
119
+ pos: toPos,
120
+ node: toNode
121
+ }
122
+ });
123
+ return {
124
+ from: {
125
+ side: fromSide,
126
+ pos: fromPos
127
+ },
128
+ to: {
129
+ side: toSide,
130
+ pos: toPos
131
+ }
132
+ };
133
+ }
@@ -0,0 +1,4 @@
1
+ import { type Step } from "prosemirror-transform";
2
+ import { type Transaction } from "prosemirror-state";
3
+ import { type SuggestionId } from "../../generateId.js";
4
+ export declare function handleStructureStep(trackedTransaction: Transaction, step: Step, prevSteps: Step[], suggestionId: SuggestionId): boolean;
@@ -0,0 +1,174 @@
1
+ import { ReplaceAroundStep, ReplaceStep, Transform } from "prosemirror-transform";
2
+ import { contentBetween } from "../../contentBetween.js";
3
+ import { rebaseStep } from "../../rebaseStep.js";
4
+ import { findMatchingNodeSides } from "./findMatchingNodeSides.js";
5
+ import { addStructureMark } from "./addStructureMark.js";
6
+ export function handleStructureStep(trackedTransaction, step, prevSteps, suggestionId) {
7
+ if (step instanceof ReplaceAroundStep) {
8
+ return handleReplaceAroundStep(trackedTransaction, step, prevSteps, suggestionId);
9
+ }
10
+ if (step instanceof ReplaceStep) {
11
+ return handleReplaceStep(trackedTransaction, step, prevSteps, suggestionId);
12
+ }
13
+ return false;
14
+ }
15
+ function handleReplaceAroundStep(trackedTransaction, step, prevSteps, suggestionId) {
16
+ // consider step structure if structure === true or there is no content in from-gapFrom and gapTo-to
17
+ // inspired by https://github.com/ProseMirror/prosemirror-transform/blob/1.11.0/src/replace_step.ts#L110
18
+ const isStructureStep = step.structure || !(contentBetween(trackedTransaction.doc, step.from, step.gapFrom) || contentBetween(trackedTransaction.doc, step.gapTo, step.to));
19
+ if (!isStructureStep) return false;
20
+ console.groupCollapsed(`handle structure ReplaceAround step from = ${step.from.toString()}, to = ${step.to.toString()}, gapFrom = ${step.gapFrom.toString()}, gapTo = ${step.gapTo.toString()}`);
21
+ const rebasedStep = rebaseStep(step, prevSteps, trackedTransaction.steps);
22
+ if (!rebasedStep || !(rebasedStep instanceof ReplaceAroundStep)) {
23
+ throw new Error("Failed to rebase replace around step: unexpected step type");
24
+ }
25
+ const docBeforeStep = trackedTransaction.doc;
26
+ trackedTransaction.step(rebasedStep);
27
+ const inverseStep = rebasedStep.invert(docBeforeStep);
28
+ console.log({
29
+ step,
30
+ rebasedStep,
31
+ inverseStep
32
+ });
33
+ if (!(inverseStep instanceof ReplaceAroundStep)) {
34
+ throw new Error("Failed to invert replace around step: unexpected step type");
35
+ }
36
+ const inverseFrom = inverseStep.from;
37
+ const inverseTo = inverseStep.to;
38
+ const $inverseFrom = trackedTransaction.doc.resolve(inverseFrom);
39
+ const $inverseTo = trackedTransaction.doc.resolve(inverseTo);
40
+ const inverseGapFrom = inverseStep.gapFrom;
41
+ const inverseGapTo = inverseStep.gapTo;
42
+ const $inverseGapFrom = trackedTransaction.doc.resolve(inverseGapFrom);
43
+ const $inverseGapTo = trackedTransaction.doc.resolve(inverseGapTo);
44
+ const inverseBlockRange = $inverseFrom.blockRange($inverseTo);
45
+ const inverseGapBlockRange = $inverseGapFrom.blockRange($inverseGapTo);
46
+ if (!inverseBlockRange || !inverseGapBlockRange) {
47
+ throw new Error("Failed to get inverse block range: unexpected range");
48
+ }
49
+ const slice = inverseStep.slice;
50
+ const insert = inverseStep.insert;
51
+ // positive number - subtract from gapFrom later to reconstruct "from"
52
+ const fromOffset = inverseGapFrom - inverseFrom;
53
+ // positive number - add to gapTo on reverse to reconstruct "to"
54
+ const toOffset = inverseTo - inverseGapTo;
55
+ // positive number - add to from later to reconstruct "gapFrom"
56
+ const gapFromOffset = inverseGapFrom - inverseFrom;
57
+ // positive number - subtract from to later to reconstruct "gapTo"
58
+ const gapToOffset = inverseTo - inverseGapTo;
59
+ const isInverseStepStructural = inverseStep.structure;
60
+ const gapFromToSides = findMatchingNodeSides(trackedTransaction.doc, inverseGapBlockRange, {
61
+ from: inverseGapFrom,
62
+ to: inverseGapTo
63
+ });
64
+ addStructureMark(suggestionId, gapFromToSides.from.pos, {
65
+ type: "replaceAround",
66
+ slice,
67
+ insert,
68
+ structure: isInverseStepStructural,
69
+ value: "gapFrom",
70
+ position: gapFromToSides.from.side,
71
+ fromOffset
72
+ }, trackedTransaction);
73
+ addStructureMark(suggestionId, gapFromToSides.to.pos, {
74
+ type: "replaceAround",
75
+ slice,
76
+ insert,
77
+ structure: isInverseStepStructural,
78
+ value: "gapTo",
79
+ position: gapFromToSides.to.side,
80
+ toOffset
81
+ }, trackedTransaction);
82
+ const fromToSides = findMatchingNodeSides(trackedTransaction.doc, inverseBlockRange, {
83
+ from: inverseFrom,
84
+ to: inverseTo
85
+ });
86
+ addStructureMark(suggestionId, fromToSides.from.pos, {
87
+ type: "replaceAround",
88
+ slice,
89
+ insert,
90
+ structure: isInverseStepStructural,
91
+ value: "from",
92
+ position: fromToSides.from.side,
93
+ gapFromOffset
94
+ }, trackedTransaction);
95
+ addStructureMark(suggestionId, fromToSides.to.pos, {
96
+ type: "replaceAround",
97
+ slice,
98
+ insert,
99
+ structure: isInverseStepStructural,
100
+ value: "to",
101
+ position: fromToSides.to.side,
102
+ gapToOffset
103
+ }, trackedTransaction);
104
+ return true;
105
+ }
106
+ function handleReplaceStep(trackedTransaction, step, prevSteps, suggestionId) {
107
+ const isStructureStep = step.structure || !contentBetween(trackedTransaction.doc, step.from, step.to);
108
+ if (!isStructureStep) return false;
109
+ // handle this step as structure step
110
+ console.groupCollapsed(`handle structure Replace step from = ${step.from.toString()}, to = ${step.to.toString()}`);
111
+ const rebasedStep = rebaseStep(step, prevSteps, trackedTransaction.steps);
112
+ if (!rebasedStep || !(rebasedStep instanceof ReplaceStep)) {
113
+ throw new Error("Failed to rebase replace step: unexpected step type");
114
+ }
115
+ const transform = new Transform(trackedTransaction.doc);
116
+ const $stepFromBefore = trackedTransaction.doc.resolve(rebasedStep.from);
117
+ const $stepToBefore = trackedTransaction.doc.resolve(rebasedStep.to);
118
+ console.log({
119
+ $stepFromBefore,
120
+ $stepToBefore
121
+ });
122
+ transform.step(rebasedStep);
123
+ const $stepFromAfter = transform.doc.resolve(transform.mapping.map($stepFromBefore.pos));
124
+ const $stepToAfter = transform.doc.resolve(transform.mapping.map($stepToBefore.pos));
125
+ console.log({
126
+ $stepFromAfter,
127
+ $stepToAfter
128
+ });
129
+ // detect join inside textblock so we can bail out
130
+ // those are not handled with structure marks, those are handled with a ZWSP deletion mark
131
+ if (!$stepFromBefore.sameParent($stepToBefore) && $stepFromAfter.sameParent($stepToAfter) && $stepFromAfter.pos === $stepToAfter.pos && $stepFromAfter.parent.isTextblock) {
132
+ console.log("this is a join inside textblock");
133
+ console.groupEnd();
134
+ return false;
135
+ }
136
+ if (!$stepFromBefore.sameParent($stepToBefore) && $stepFromAfter.sameParent($stepToAfter) && $stepFromAfter.pos === $stepToAfter.pos && !$stepFromAfter.parent.isTextblock) {
137
+ console.log("this is a join inside non-textblock");
138
+ }
139
+ const docBeforeStep = trackedTransaction.doc;
140
+ trackedTransaction.step(rebasedStep);
141
+ const inverseStep = rebasedStep.invert(docBeforeStep);
142
+ if (!(inverseStep instanceof ReplaceStep)) {
143
+ throw new Error("Failed to invert replace step: unexpected step type");
144
+ }
145
+ const inverseFrom = inverseStep.from;
146
+ const inverseTo = inverseStep.to;
147
+ const $inverseFrom = trackedTransaction.doc.resolve(inverseFrom);
148
+ const $inverseTo = trackedTransaction.doc.resolve(inverseTo);
149
+ const inverseBlockRange = $inverseFrom.blockRange($inverseTo);
150
+ if (!inverseBlockRange) {
151
+ throw new Error("Failed to get inverse block range: unexpected range");
152
+ }
153
+ const slice = inverseStep.slice;
154
+ const isInverseStepStructural = inverseStep.structure || !contentBetween(trackedTransaction.doc, inverseFrom, inverseTo);
155
+ const fromToSides = findMatchingNodeSides(trackedTransaction.doc, inverseBlockRange, {
156
+ from: inverseFrom,
157
+ to: inverseTo
158
+ });
159
+ addStructureMark(suggestionId, fromToSides.from.pos, {
160
+ type: "replace",
161
+ slice,
162
+ structure: isInverseStepStructural,
163
+ value: "from",
164
+ position: fromToSides.from.side
165
+ }, trackedTransaction);
166
+ addStructureMark(suggestionId, fromToSides.to.pos, {
167
+ type: "replace",
168
+ slice,
169
+ structure: isInverseStepStructural,
170
+ value: "to",
171
+ position: fromToSides.to.side
172
+ }, trackedTransaction);
173
+ return true;
174
+ }