@lexical/react 0.7.8 → 0.8.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/DEPRECATED_useLexical.dev.js +3 -4
- package/DEPRECATED_useLexicalCanShowPlaceholder.dev.js +1 -3
- package/DEPRECATED_useLexicalCharacterLimit.dev.js +7 -39
- package/DEPRECATED_useLexicalEditor.dev.js +1 -3
- package/DEPRECATED_useLexicalPlainText.dev.js +4 -1
- package/DEPRECATED_useLexicalRichText.dev.js +4 -1
- package/LexicalAutoEmbedPlugin.dev.js +0 -11
- package/LexicalAutoFocusPlugin.dev.js +0 -1
- package/LexicalAutoLinkPlugin.dev.js +7 -50
- package/LexicalBlockWithAlignableContents.d.ts +1 -1
- package/LexicalBlockWithAlignableContents.dev.js +0 -11
- package/LexicalCharacterLimitPlugin.dev.js +7 -46
- package/LexicalCheckListPlugin.dev.js +10 -48
- package/LexicalClearEditorPlugin.dev.js +1 -1
- package/LexicalCollaborationContext.dev.js +0 -3
- package/LexicalCollaborationPlugin.dev.js +11 -36
- package/LexicalCollaborationPlugin.prod.js +9 -9
- package/LexicalComposer.dev.js +6 -10
- package/LexicalComposerContext.dev.js +0 -6
- package/LexicalContentEditable.d.ts +16 -25
- package/LexicalContentEditable.dev.js +10 -14
- package/LexicalContentEditable.js.flow +15 -20
- package/LexicalContentEditable.prod.js +3 -3
- package/LexicalDecoratorBlockNode.dev.js +0 -5
- package/LexicalHashtagPlugin.dev.js +73 -43
- package/LexicalHorizontalRuleNode.dev.js +0 -22
- package/LexicalHorizontalRulePlugin.dev.js +0 -4
- package/LexicalLinkPlugin.dev.js +4 -10
- package/LexicalListPlugin.dev.js +1 -9
- package/LexicalListPlugin.prod.js +2 -2
- package/LexicalMarkdownShortcutPlugin.dev.js +2 -2
- package/LexicalNestedComposer.dev.js +8 -11
- package/LexicalNestedComposer.prod.js +3 -3
- package/LexicalNodeEventPlugin.dev.js +5 -3
- package/LexicalOnChangePlugin.dev.js +1 -1
- package/LexicalPlainTextPlugin.dev.js +8 -12
- package/LexicalRichTextPlugin.dev.js +8 -12
- package/LexicalTabIndentationPlugin.dev.js +1 -3
- package/LexicalTableOfContents__EXPERIMENTAL.dev.js +5 -33
- package/LexicalTablePlugin.dev.js +5 -19
- package/LexicalTreeView.dev.js +13 -62
- package/LexicalTreeView.prod.js +13 -13
- package/LexicalTypeaheadMenuPlugin.dev.js +7 -96
- package/package.json +19 -19
- package/shared/useYjsCollaboration.d.ts +1 -1
- package/useLexicalEditable.dev.js +1 -5
- package/useLexicalIsTextContentEmpty.dev.js +1 -0
- package/useLexicalNodeSelection.dev.js +0 -7
- package/useLexicalSubscription.dev.js +1 -3
|
@@ -22,6 +22,7 @@ var plainText = require('@lexical/plain-text');
|
|
|
22
22
|
* LICENSE file in the root directory of this source tree.
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
|
+
|
|
25
26
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -41,12 +42,10 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
41
42
|
* LICENSE file in the root directory of this source tree.
|
|
42
43
|
*
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
45
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
46
46
|
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing()));
|
|
47
47
|
return currentCanShowPlaceholder;
|
|
48
48
|
}
|
|
49
|
-
|
|
50
49
|
function useCanShowPlaceholder(editor) {
|
|
51
50
|
const [canShowPlaceholder, setCanShowPlaceholder] = React.useState(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
52
51
|
useLayoutEffect(() => {
|
|
@@ -54,7 +53,6 @@ function useCanShowPlaceholder(editor) {
|
|
|
54
53
|
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
55
54
|
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
56
55
|
}
|
|
57
|
-
|
|
58
56
|
resetCanShowPlaceholder();
|
|
59
57
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
60
58
|
resetCanShowPlaceholder();
|
|
@@ -73,8 +71,9 @@ function useCanShowPlaceholder(editor) {
|
|
|
73
71
|
*
|
|
74
72
|
*/
|
|
75
73
|
function useDecorators(editor, ErrorBoundary) {
|
|
76
|
-
const [decorators, setDecorators] = React.useState(() => editor.getDecorators());
|
|
74
|
+
const [decorators, setDecorators] = React.useState(() => editor.getDecorators());
|
|
77
75
|
|
|
76
|
+
// Subscribe to changes
|
|
78
77
|
useLayoutEffect(() => {
|
|
79
78
|
return editor.registerDecoratorListener(nextDecorators => {
|
|
80
79
|
reactDom.flushSync(() => {
|
|
@@ -87,12 +86,12 @@ function useDecorators(editor, ErrorBoundary) {
|
|
|
87
86
|
// nothing will be rendered on initial pass. We can get around that by
|
|
88
87
|
// ensuring that we set the value.
|
|
89
88
|
setDecorators(editor.getDecorators());
|
|
90
|
-
}, [editor]);
|
|
89
|
+
}, [editor]);
|
|
91
90
|
|
|
91
|
+
// Return decorators defined as React Portals
|
|
92
92
|
return React.useMemo(() => {
|
|
93
93
|
const decoratedPortals = [];
|
|
94
94
|
const decoratorKeys = Object.keys(decorators);
|
|
95
|
-
|
|
96
95
|
for (let i = 0; i < decoratorKeys.length; i++) {
|
|
97
96
|
const nodeKey = decoratorKeys[i];
|
|
98
97
|
const reactDecorator = /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
@@ -101,12 +100,10 @@ function useDecorators(editor, ErrorBoundary) {
|
|
|
101
100
|
fallback: null
|
|
102
101
|
}, decorators[nodeKey]));
|
|
103
102
|
const element = editor.getElementByKey(nodeKey);
|
|
104
|
-
|
|
105
103
|
if (element !== null) {
|
|
106
104
|
decoratedPortals.push( /*#__PURE__*/reactDom.createPortal(reactDecorator, element));
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
|
-
|
|
110
107
|
return decoratedPortals;
|
|
111
108
|
}, [ErrorBoundary, decorators, editor]);
|
|
112
109
|
}
|
|
@@ -120,7 +117,9 @@ function useDecorators(editor, ErrorBoundary) {
|
|
|
120
117
|
*/
|
|
121
118
|
function usePlainTextSetup(editor) {
|
|
122
119
|
useLayoutEffect(() => {
|
|
123
|
-
return utils.mergeRegister(plainText.registerPlainText(editor), dragon.registerDragonSupport(editor));
|
|
120
|
+
return utils.mergeRegister(plainText.registerPlainText(editor), dragon.registerDragonSupport(editor));
|
|
121
|
+
|
|
122
|
+
// We only do this for init
|
|
124
123
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
125
124
|
}, [editor]);
|
|
126
125
|
}
|
|
@@ -144,18 +143,15 @@ function PlainTextPlugin({
|
|
|
144
143
|
content: placeholder
|
|
145
144
|
}), decorators);
|
|
146
145
|
}
|
|
147
|
-
|
|
148
146
|
function Placeholder({
|
|
149
147
|
content
|
|
150
148
|
}) {
|
|
151
149
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
152
150
|
const showPlaceholder = useCanShowPlaceholder(editor);
|
|
153
151
|
const editable = useLexicalEditable();
|
|
154
|
-
|
|
155
152
|
if (!showPlaceholder) {
|
|
156
153
|
return null;
|
|
157
154
|
}
|
|
158
|
-
|
|
159
155
|
if (typeof content === 'function') {
|
|
160
156
|
return content(editable);
|
|
161
157
|
} else {
|
|
@@ -22,6 +22,7 @@ var richText = require('@lexical/rich-text');
|
|
|
22
22
|
* LICENSE file in the root directory of this source tree.
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
|
+
|
|
25
26
|
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -41,12 +42,10 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
41
42
|
* LICENSE file in the root directory of this source tree.
|
|
42
43
|
*
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
45
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
46
46
|
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing()));
|
|
47
47
|
return currentCanShowPlaceholder;
|
|
48
48
|
}
|
|
49
|
-
|
|
50
49
|
function useCanShowPlaceholder(editor) {
|
|
51
50
|
const [canShowPlaceholder, setCanShowPlaceholder] = React.useState(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
52
51
|
useLayoutEffect(() => {
|
|
@@ -54,7 +53,6 @@ function useCanShowPlaceholder(editor) {
|
|
|
54
53
|
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
55
54
|
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
56
55
|
}
|
|
57
|
-
|
|
58
56
|
resetCanShowPlaceholder();
|
|
59
57
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
60
58
|
resetCanShowPlaceholder();
|
|
@@ -73,8 +71,9 @@ function useCanShowPlaceholder(editor) {
|
|
|
73
71
|
*
|
|
74
72
|
*/
|
|
75
73
|
function useDecorators(editor, ErrorBoundary) {
|
|
76
|
-
const [decorators, setDecorators] = React.useState(() => editor.getDecorators());
|
|
74
|
+
const [decorators, setDecorators] = React.useState(() => editor.getDecorators());
|
|
77
75
|
|
|
76
|
+
// Subscribe to changes
|
|
78
77
|
useLayoutEffect(() => {
|
|
79
78
|
return editor.registerDecoratorListener(nextDecorators => {
|
|
80
79
|
reactDom.flushSync(() => {
|
|
@@ -87,12 +86,12 @@ function useDecorators(editor, ErrorBoundary) {
|
|
|
87
86
|
// nothing will be rendered on initial pass. We can get around that by
|
|
88
87
|
// ensuring that we set the value.
|
|
89
88
|
setDecorators(editor.getDecorators());
|
|
90
|
-
}, [editor]);
|
|
89
|
+
}, [editor]);
|
|
91
90
|
|
|
91
|
+
// Return decorators defined as React Portals
|
|
92
92
|
return React.useMemo(() => {
|
|
93
93
|
const decoratedPortals = [];
|
|
94
94
|
const decoratorKeys = Object.keys(decorators);
|
|
95
|
-
|
|
96
95
|
for (let i = 0; i < decoratorKeys.length; i++) {
|
|
97
96
|
const nodeKey = decoratorKeys[i];
|
|
98
97
|
const reactDecorator = /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
@@ -101,12 +100,10 @@ function useDecorators(editor, ErrorBoundary) {
|
|
|
101
100
|
fallback: null
|
|
102
101
|
}, decorators[nodeKey]));
|
|
103
102
|
const element = editor.getElementByKey(nodeKey);
|
|
104
|
-
|
|
105
103
|
if (element !== null) {
|
|
106
104
|
decoratedPortals.push( /*#__PURE__*/reactDom.createPortal(reactDecorator, element));
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
|
-
|
|
110
107
|
return decoratedPortals;
|
|
111
108
|
}, [ErrorBoundary, decorators, editor]);
|
|
112
109
|
}
|
|
@@ -120,7 +117,9 @@ function useDecorators(editor, ErrorBoundary) {
|
|
|
120
117
|
*/
|
|
121
118
|
function useRichTextSetup(editor) {
|
|
122
119
|
useLayoutEffect(() => {
|
|
123
|
-
return utils.mergeRegister(richText.registerRichText(editor), dragon.registerDragonSupport(editor));
|
|
120
|
+
return utils.mergeRegister(richText.registerRichText(editor), dragon.registerDragonSupport(editor));
|
|
121
|
+
|
|
122
|
+
// We only do this for init
|
|
124
123
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
125
124
|
}, [editor]);
|
|
126
125
|
}
|
|
@@ -144,18 +143,15 @@ function RichTextPlugin({
|
|
|
144
143
|
content: placeholder
|
|
145
144
|
}), decorators);
|
|
146
145
|
}
|
|
147
|
-
|
|
148
146
|
function Placeholder({
|
|
149
147
|
content
|
|
150
148
|
}) {
|
|
151
149
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
152
150
|
const showPlaceholder = useCanShowPlaceholder(editor);
|
|
153
151
|
const editable = useLexicalEditable();
|
|
154
|
-
|
|
155
152
|
if (!showPlaceholder) {
|
|
156
153
|
return null;
|
|
157
154
|
}
|
|
158
|
-
|
|
159
155
|
if (typeof content === 'function') {
|
|
160
156
|
return content(editable);
|
|
161
157
|
} else {
|
|
@@ -17,22 +17,20 @@ var react = require('react');
|
|
|
17
17
|
* LICENSE file in the root directory of this source tree.
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
|
+
|
|
20
21
|
/**
|
|
21
22
|
* This plugin adds the ability to indent content using the tab key. Generally, we don't
|
|
22
23
|
* recommend using this plugin as it could negatively affect acessibility for keyboard
|
|
23
24
|
* users, causing focus to become trapped within the editor.
|
|
24
25
|
*/
|
|
25
|
-
|
|
26
26
|
function TabIndentationPlugin() {
|
|
27
27
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
28
28
|
react.useEffect(() => {
|
|
29
29
|
return editor.registerCommand(lexical.KEY_TAB_COMMAND, event => {
|
|
30
30
|
const selection = lexical.$getSelection();
|
|
31
|
-
|
|
32
31
|
if (!lexical.$isRangeSelection(selection)) {
|
|
33
32
|
return false;
|
|
34
33
|
}
|
|
35
|
-
|
|
36
34
|
event.preventDefault();
|
|
37
35
|
return editor.dispatchCommand(event.shiftKey ? lexical.OUTDENT_CONTENT_COMMAND : lexical.INDENT_CONTENT_COMMAND, undefined);
|
|
38
36
|
}, lexical.COMMAND_PRIORITY_EDITOR);
|
|
@@ -18,50 +18,39 @@ var react = require('react');
|
|
|
18
18
|
* LICENSE file in the root directory of this source tree.
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
|
-
|
|
22
21
|
function toEntry(heading) {
|
|
23
22
|
return [heading.getKey(), heading.getTextContent(), heading.getTag()];
|
|
24
23
|
}
|
|
25
|
-
|
|
26
24
|
function $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents) {
|
|
27
25
|
if (newHeading === null) {
|
|
28
26
|
return currentTableOfContents;
|
|
29
27
|
}
|
|
30
|
-
|
|
31
28
|
const newEntry = toEntry(newHeading);
|
|
32
29
|
let newTableOfContents = [];
|
|
33
|
-
|
|
34
30
|
if (prevHeading === null) {
|
|
35
31
|
newTableOfContents = [newEntry, ...currentTableOfContents];
|
|
36
32
|
} else {
|
|
37
33
|
for (let i = 0; i < currentTableOfContents.length; i++) {
|
|
38
34
|
const key = currentTableOfContents[i][0];
|
|
39
35
|
newTableOfContents.push(currentTableOfContents[i]);
|
|
40
|
-
|
|
41
36
|
if (key === prevHeading.getKey() && key !== newHeading.getKey()) {
|
|
42
37
|
newTableOfContents.push(newEntry);
|
|
43
38
|
}
|
|
44
39
|
}
|
|
45
40
|
}
|
|
46
|
-
|
|
47
41
|
return newTableOfContents;
|
|
48
42
|
}
|
|
49
|
-
|
|
50
43
|
function $deleteHeadingFromTableOfContents(key, currentTableOfContents) {
|
|
51
44
|
const newTableOfContents = [];
|
|
52
|
-
|
|
53
45
|
for (const heading of currentTableOfContents) {
|
|
54
46
|
if (heading[0] !== key) {
|
|
55
47
|
newTableOfContents.push(heading);
|
|
56
48
|
}
|
|
57
49
|
}
|
|
58
|
-
|
|
59
50
|
return newTableOfContents;
|
|
60
51
|
}
|
|
61
|
-
|
|
62
52
|
function $updateHeadingInTableOfContents(heading, currentTableOfContents) {
|
|
63
53
|
const newTableOfContents = [];
|
|
64
|
-
|
|
65
54
|
for (const oldHeading of currentTableOfContents) {
|
|
66
55
|
if (oldHeading[0] === heading.getKey()) {
|
|
67
56
|
newTableOfContents.push(toEntry(heading));
|
|
@@ -69,38 +58,30 @@ function $updateHeadingInTableOfContents(heading, currentTableOfContents) {
|
|
|
69
58
|
newTableOfContents.push(oldHeading);
|
|
70
59
|
}
|
|
71
60
|
}
|
|
72
|
-
|
|
73
61
|
return newTableOfContents;
|
|
74
62
|
}
|
|
63
|
+
|
|
75
64
|
/**
|
|
76
65
|
* Returns the updated table of contents, placing the given `heading` before the given `prevHeading`. If `prevHeading`
|
|
77
66
|
* is undefined, `heading` is placed at the start of table of contents
|
|
78
67
|
*/
|
|
79
|
-
|
|
80
|
-
|
|
81
68
|
function $updateHeadingPosition(prevHeading, heading, currentTableOfContents) {
|
|
82
69
|
const newTableOfContents = [];
|
|
83
70
|
const newEntry = toEntry(heading);
|
|
84
|
-
|
|
85
71
|
if (!prevHeading) {
|
|
86
72
|
newTableOfContents.push(newEntry);
|
|
87
73
|
}
|
|
88
|
-
|
|
89
74
|
for (const oldHeading of currentTableOfContents) {
|
|
90
75
|
if (oldHeading[0] === heading.getKey()) {
|
|
91
76
|
continue;
|
|
92
77
|
}
|
|
93
|
-
|
|
94
78
|
newTableOfContents.push(oldHeading);
|
|
95
|
-
|
|
96
79
|
if (prevHeading && oldHeading[0] === prevHeading.getKey()) {
|
|
97
80
|
newTableOfContents.push(newEntry);
|
|
98
81
|
}
|
|
99
82
|
}
|
|
100
|
-
|
|
101
83
|
return newTableOfContents;
|
|
102
84
|
}
|
|
103
|
-
|
|
104
85
|
function LexicalTableOfContentsPlugin({
|
|
105
86
|
children
|
|
106
87
|
}) {
|
|
@@ -112,61 +93,52 @@ function LexicalTableOfContentsPlugin({
|
|
|
112
93
|
editor.getEditorState().read(() => {
|
|
113
94
|
const root = lexical.$getRoot();
|
|
114
95
|
const rootChildren = root.getChildren();
|
|
115
|
-
|
|
116
96
|
for (const child of rootChildren) {
|
|
117
97
|
if (richText.$isHeadingNode(child)) {
|
|
118
98
|
currentTableOfContents.push([child.getKey(), child.getTextContent(), child.getTag()]);
|
|
119
99
|
}
|
|
120
100
|
}
|
|
121
|
-
|
|
122
101
|
setTableOfContents(currentTableOfContents);
|
|
123
|
-
});
|
|
102
|
+
});
|
|
124
103
|
|
|
104
|
+
// Listen to updates to heading mutations and update state
|
|
125
105
|
const removeHeaderMutationListener = editor.registerMutationListener(richText.HeadingNode, mutatedNodes => {
|
|
126
106
|
editor.getEditorState().read(() => {
|
|
127
107
|
for (const [nodeKey, mutation] of mutatedNodes) {
|
|
128
108
|
if (mutation === 'created') {
|
|
129
109
|
const newHeading = lexical.$getNodeByKey(nodeKey);
|
|
130
|
-
|
|
131
110
|
if (newHeading !== null) {
|
|
132
111
|
let prevHeading = newHeading.getPreviousSibling();
|
|
133
|
-
|
|
134
112
|
while (prevHeading !== null && !richText.$isHeadingNode(prevHeading)) {
|
|
135
113
|
prevHeading = prevHeading.getPreviousSibling();
|
|
136
114
|
}
|
|
137
|
-
|
|
138
115
|
currentTableOfContents = $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents);
|
|
139
116
|
}
|
|
140
117
|
} else if (mutation === 'destroyed') {
|
|
141
118
|
currentTableOfContents = $deleteHeadingFromTableOfContents(nodeKey, currentTableOfContents);
|
|
142
119
|
} else if (mutation === 'updated') {
|
|
143
120
|
const newHeading = lexical.$getNodeByKey(nodeKey);
|
|
144
|
-
|
|
145
121
|
if (newHeading !== null) {
|
|
146
122
|
let prevHeading = newHeading.getPreviousSibling();
|
|
147
|
-
|
|
148
123
|
while (prevHeading !== null && !richText.$isHeadingNode(prevHeading)) {
|
|
149
124
|
prevHeading = prevHeading.getPreviousSibling();
|
|
150
125
|
}
|
|
151
|
-
|
|
152
126
|
currentTableOfContents = $updateHeadingPosition(prevHeading, newHeading, currentTableOfContents);
|
|
153
127
|
}
|
|
154
128
|
}
|
|
155
129
|
}
|
|
156
|
-
|
|
157
130
|
setTableOfContents(currentTableOfContents);
|
|
158
131
|
});
|
|
159
|
-
});
|
|
132
|
+
});
|
|
160
133
|
|
|
134
|
+
// Listen to text node mutation updates
|
|
161
135
|
const removeTextNodeMutationListener = editor.registerMutationListener(lexical.TextNode, mutatedNodes => {
|
|
162
136
|
editor.getEditorState().read(() => {
|
|
163
137
|
for (const [nodeKey, mutation] of mutatedNodes) {
|
|
164
138
|
if (mutation === 'updated') {
|
|
165
139
|
const currNode = lexical.$getNodeByKey(nodeKey);
|
|
166
|
-
|
|
167
140
|
if (currNode !== null) {
|
|
168
141
|
const parentNode = currNode.getParentOrThrow();
|
|
169
|
-
|
|
170
142
|
if (richText.$isHeadingNode(parentNode)) {
|
|
171
143
|
currentTableOfContents = $updateHeadingInTableOfContents(parentNode, currentTableOfContents);
|
|
172
144
|
setTableOfContents(currentTableOfContents);
|
|
@@ -26,65 +26,53 @@ function TablePlugin() {
|
|
|
26
26
|
throw Error(`TablePlugin: TableNode, TableCellNode or TableRowNode not registered on editor`);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
|
|
30
29
|
return editor.registerCommand(table.INSERT_TABLE_COMMAND, ({
|
|
31
30
|
columns,
|
|
32
31
|
rows,
|
|
33
32
|
includeHeaders
|
|
34
33
|
}) => {
|
|
35
34
|
const selection = lexical.$getSelection();
|
|
36
|
-
|
|
37
35
|
if (!lexical.$isRangeSelection(selection)) {
|
|
38
36
|
return true;
|
|
39
37
|
}
|
|
40
|
-
|
|
41
38
|
const focus = selection.focus;
|
|
42
39
|
const focusNode = focus.getNode();
|
|
43
|
-
|
|
44
40
|
if (focusNode !== null) {
|
|
45
41
|
const tableNode = table.$createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders);
|
|
46
|
-
|
|
47
42
|
if (lexical.$isRootOrShadowRoot(focusNode)) {
|
|
48
43
|
const target = focusNode.getChildAtIndex(focus.offset);
|
|
49
|
-
|
|
50
44
|
if (target !== null) {
|
|
51
45
|
target.insertBefore(tableNode);
|
|
52
46
|
} else {
|
|
53
47
|
focusNode.append(tableNode);
|
|
54
48
|
}
|
|
55
|
-
|
|
56
49
|
tableNode.insertBefore(lexical.$createParagraphNode());
|
|
57
50
|
} else {
|
|
58
51
|
const topLevelNode = focusNode.getTopLevelElementOrThrow();
|
|
59
52
|
topLevelNode.insertAfter(tableNode);
|
|
60
53
|
}
|
|
61
|
-
|
|
62
54
|
tableNode.insertAfter(lexical.$createParagraphNode());
|
|
63
55
|
const firstCell = tableNode.getFirstChildOrThrow().getFirstChildOrThrow();
|
|
64
56
|
firstCell.select();
|
|
65
57
|
}
|
|
66
|
-
|
|
67
58
|
return true;
|
|
68
59
|
}, lexical.COMMAND_PRIORITY_EDITOR);
|
|
69
60
|
}, [editor]);
|
|
70
61
|
react.useEffect(() => {
|
|
71
62
|
const tableSelections = new Map();
|
|
72
|
-
|
|
73
63
|
const initializeTableNode = tableNode => {
|
|
74
64
|
const nodeKey = tableNode.getKey();
|
|
75
65
|
const tableElement = editor.getElementByKey(nodeKey);
|
|
76
|
-
|
|
77
66
|
if (tableElement && !tableSelections.has(nodeKey)) {
|
|
78
67
|
const tableSelection = table.applyTableHandlers(tableNode, tableElement, editor);
|
|
79
68
|
tableSelections.set(nodeKey, tableSelection);
|
|
80
69
|
}
|
|
81
|
-
};
|
|
82
|
-
// won't be initialized from mutation[create] listener. Instead doing it here,
|
|
83
|
-
|
|
70
|
+
};
|
|
84
71
|
|
|
72
|
+
// Plugins might be loaded _after_ initial content is set, hence existing table nodes
|
|
73
|
+
// won't be initialized from mutation[create] listener. Instead doing it here,
|
|
85
74
|
editor.getEditorState().read(() => {
|
|
86
75
|
const tableNodes = lexical.$nodesOfType(table.TableNode);
|
|
87
|
-
|
|
88
76
|
for (const tableNode of tableNodes) {
|
|
89
77
|
if (table.$isTableNode(tableNode)) {
|
|
90
78
|
initializeTableNode(tableNode);
|
|
@@ -96,14 +84,12 @@ function TablePlugin() {
|
|
|
96
84
|
if (mutation === 'created') {
|
|
97
85
|
editor.getEditorState().read(() => {
|
|
98
86
|
const tableNode = lexical.$getNodeByKey(nodeKey);
|
|
99
|
-
|
|
100
87
|
if (table.$isTableNode(tableNode)) {
|
|
101
88
|
initializeTableNode(tableNode);
|
|
102
89
|
}
|
|
103
90
|
});
|
|
104
91
|
} else if (mutation === 'destroyed') {
|
|
105
92
|
const tableSelection = tableSelections.get(nodeKey);
|
|
106
|
-
|
|
107
93
|
if (tableSelection !== undefined) {
|
|
108
94
|
tableSelection.removeListeners();
|
|
109
95
|
tableSelections.delete(nodeKey);
|
|
@@ -112,9 +98,9 @@ function TablePlugin() {
|
|
|
112
98
|
}
|
|
113
99
|
});
|
|
114
100
|
return () => {
|
|
115
|
-
unregisterMutationListener();
|
|
101
|
+
unregisterMutationListener();
|
|
102
|
+
// Hook might be called multiple times so cleaning up tables listeners as well,
|
|
116
103
|
// as it'll be reinitialized during recurring call
|
|
117
|
-
|
|
118
104
|
for (const [, tableSelection] of tableSelections) {
|
|
119
105
|
tableSelection.removeListeners();
|
|
120
106
|
}
|