@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.
- package/dist/commands.d.ts +3 -1
- package/dist/commands.js +14 -2
- package/dist/contentBetween.d.ts +2 -0
- package/dist/contentBetween.js +33 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.data.d.ts +38 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapAllNodes.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.data.d.ts +45 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapOneNode.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.data.d.ts +38 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteUnwrapSingleNode.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.data.d.ts +38 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteWrapAllNodes.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.data.d.ts +38 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/blockquoteWrapSingleNode.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.data.d.ts +54 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftLast.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.data.d.ts +48 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftMiddle.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.data.d.ts +74 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftMultipleToTheTop.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.data.d.ts +71 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftNestedOnce.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.data.d.ts +54 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemLiftTop.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.data.d.ts +181 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.page.d.ts +30 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkMultiple.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.data.d.ts +51 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemSinkOneOnce.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.data.d.ts +74 -0
- package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/listItemsLiftMixedLevels.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.data.d.ts +71 -0
- package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/nestedListItemLiftToOuter.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.data.d.ts +114 -0
- package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/nestedListItemsLiftMultipleLevels.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/testUtils.d.ts +5 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.data.d.ts +44 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesToTheTop.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.data.d.ts +38 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftMultipleNodesUp.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.data.d.ts +46 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeFromMiddle.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.data.d.ts +57 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.data.d.ts +45 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeUp.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.data.d.ts +44 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrap.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.data.d.ts +44 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.playwright.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteWrapMultiple.test.d.ts +1 -0
- package/dist/features/wrapUnwrap/addStructureMark.d.ts +41 -0
- package/dist/features/wrapUnwrap/addStructureMark.js +15 -0
- package/dist/features/wrapUnwrap/findMatchingNodeSides.d.ts +15 -0
- package/dist/features/wrapUnwrap/findMatchingNodeSides.js +133 -0
- package/dist/features/wrapUnwrap/handleStructureStep.d.ts +4 -0
- package/dist/features/wrapUnwrap/handleStructureStep.js +174 -0
- package/dist/features/wrapUnwrap/revertStructureSuggestion.d.ts +44 -0
- package/dist/features/wrapUnwrap/revertStructureSuggestion.js +374 -0
- package/dist/generateId.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/rebaseStep.d.ts +9 -0
- package/dist/rebaseStep.js +11 -0
- package/dist/replaceAroundStep.js +6 -1
- package/dist/replaceStep.js +5 -0
- package/dist/schema.d.ts +2 -1
- package/dist/schema.js +37 -1
- package/dist/testing/testBuilders.d.ts +1 -2
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +6 -2
- package/package.json +1 -1
- 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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
+
}[];
|
package/dist/features/wrapUnwrap/__tests__/tripleBlockquoteLiftOneNodeToTheTop.playwright.test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
+
}
|