-
Notifications
You must be signed in to change notification settings - Fork 0
/
createMarkAffinityPlugin.ts
115 lines (100 loc) · 3.22 KB
/
createMarkAffinityPlugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {
createPluginFactory,
isSelectionExpanded,
MARK_CODE,
} from '@udecode/plate';
import { getMarkBoundary } from './getMarkBoundary';
import { getMarkBoundaryAffinity } from './getMarkBoundaryAffinity';
import { setMarkBoundaryAffinity } from './setMarkBoundaryAffinity';
import { MarkBoundary } from './types';
const markBoundaryHasMark = (markBoundary: MarkBoundary, mark: string) => {
const [backwardLeafEntry, forwardLeafEntry] = markBoundary;
return (
(backwardLeafEntry && backwardLeafEntry[0][mark]) ||
(forwardLeafEntry && forwardLeafEntry[0][mark])
);
};
export const KEY_MARK_AFFINITY = 'mark-affinity';
export const createMarkAffinityPlugin = createPluginFactory({
key: KEY_MARK_AFFINITY,
withOverrides: (editor) => {
const { deleteBackward, move } = editor;
/**
* On backspace, if the deletion results in the cursor being at a mark
* boundary, then the affinity should be forward. If the deletion removes
* a character from the left mark, then the affinity should be backward.
*/
editor.deleteBackward = (unit) => {
if (
unit === 'character' &&
editor.selection &&
!isSelectionExpanded(editor)
) {
const [leftMarkEntryBefore] = getMarkBoundary(editor) ?? [null];
const removingFromLeftMark =
leftMarkEntryBefore && leftMarkEntryBefore[0].text.length > 1;
deleteBackward(unit);
const afterMarkBoundary = getMarkBoundary(editor);
if (afterMarkBoundary) {
setMarkBoundaryAffinity(
editor,
afterMarkBoundary,
removingFromLeftMark ? 'backward' : 'forward'
);
}
return;
}
deleteBackward(unit);
};
editor.move = (options) => {
const {
unit = 'character',
distance = 1,
reverse = false,
} = options || {};
if (
unit === 'character' &&
distance === 1 &&
editor.selection &&
!isSelectionExpanded(editor)
) {
const beforeMarkBoundary = getMarkBoundary(editor);
/**
* If the cursor is at the start or end of a list of text nodes and
* inside a code mark, then moving outside the mark should set the
* affinity accordingly.
*/
if (
beforeMarkBoundary &&
markBoundaryHasMark(beforeMarkBoundary, MARK_CODE) &&
beforeMarkBoundary[reverse ? 0 : 1] === null &&
getMarkBoundaryAffinity(editor, beforeMarkBoundary) ===
(reverse ? 'forward' : 'backward')
) {
setMarkBoundaryAffinity(
editor,
beforeMarkBoundary,
reverse ? 'backward' : 'forward'
);
return;
}
move(options);
const afterMarkBoundary = getMarkBoundary(editor);
/**
* If the move places the cursor at a mark boundary, then the affinity
* should be set to the direction the cursor came from.
*/
if (afterMarkBoundary) {
setMarkBoundaryAffinity(
editor,
afterMarkBoundary,
reverse ? 'forward' : 'backward'
);
}
return;
}
move(options);
};
return editor;
},
});