-
-
Notifications
You must be signed in to change notification settings - Fork 613
/
withNodeID.ts
102 lines (88 loc) · 2.55 KB
/
withNodeID.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
import { cloneDeep } from 'lodash';
import { Element, Node, NodeEntry } from 'slate';
import { HistoryEditor } from 'slate-history';
import { isDescendant } from '../../queries/index';
import { defaultsDeepToNodes } from '../../transforms/defaultsDeepToNodes';
import { mergeDeepToNodes } from '../../transforms/mergeDeepToNodes';
import { QueryOptions } from '../../types/QueryOptions.types';
export interface WithNodeIDProps extends QueryOptions {
// Key used for the id. Default is `id`.
idKey?: string;
// ID factory, e.g. `uuid`
idCreator?: Function;
// Filter `Text` nodes.
filterText?: boolean;
// The existing ID is still reset even if the ID already exists. Default is `false`.
resetExistingID?: boolean;
}
/**
* Enables support for inserting nodes with an id key.
*/
export const withNodeID = ({
idKey = 'id',
idCreator = () => Date.now(),
filterText = true,
resetExistingID = false,
filter = () => true,
allow,
exclude,
}: WithNodeIDProps = {}) => <T extends HistoryEditor>(e: T) => {
const editor = e as T & { removedIDs: Set<any> };
const { apply } = editor;
const idPropsCreator = () => ({ [idKey]: idCreator() });
editor.removedIDs = new Set();
editor.apply = (operation) => {
if (operation.type === 'insert_node') {
const newFilter = (entry: NodeEntry<Node>) => {
const [node] = entry;
return filter(entry) && filterText
? Element.isElement(node)
: isDescendant(node);
};
const node = cloneDeep(operation.node);
// it will not overwrite ids once it's set as it's read-only
const applyDeepToNodes = resetExistingID
? mergeDeepToNodes
: defaultsDeepToNodes;
applyDeepToNodes({
node,
source: idPropsCreator,
query: {
filter: newFilter,
allow,
exclude,
},
});
return apply({
...operation,
node,
});
}
if (
operation.type === 'split_node' &&
(!filterText || operation.properties.type)
) {
let id = operation.properties[idKey];
if (editor.removedIDs.has(id)) {
editor.removedIDs.delete(id);
} else {
id = idCreator();
}
return apply({
...operation,
properties: {
...operation.properties,
[idKey]: id,
},
});
}
if (
operation.type === 'merge_node' &&
(!filterText || operation.properties.type)
) {
editor.removedIDs.add(operation.properties.id);
}
return apply(operation);
};
return editor;
};