@lexical/react 0.3.10 → 0.4.1
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 +2 -2
- package/DEPRECATED_useLexical.prod.js +2 -2
- package/DEPRECATED_useLexicalCanShowPlaceholder.dev.js +2 -2
- package/DEPRECATED_useLexicalCanShowPlaceholder.prod.js +2 -2
- package/DEPRECATED_useLexicalEditor.dev.js +2 -2
- package/DEPRECATED_useLexicalEditor.prod.js +2 -2
- package/LexicalAutoEmbedPlugin.d.ts +1 -1
- package/LexicalAutoEmbedPlugin.dev.js +3 -337
- package/LexicalAutoEmbedPlugin.js.flow +72 -0
- package/LexicalAutoEmbedPlugin.prod.js +5 -15
- package/LexicalCheckListPlugin.dev.js +2 -2
- package/LexicalCheckListPlugin.prod.js +2 -2
- package/LexicalCollaborationPlugin.dev.js +2 -1
- package/LexicalCollaborationPlugin.js.flow +1 -16
- package/LexicalComposer.d.ts +1 -1
- package/LexicalComposer.dev.js +3 -3
- package/LexicalComposer.prod.js +3 -3
- package/LexicalContentEditable.dev.js +11 -11
- package/LexicalContentEditable.prod.js +2 -2
- package/LexicalHorizontalRuleNode.dev.js +47 -3
- package/LexicalHorizontalRuleNode.prod.js +5 -3
- package/LexicalMarkdownShortcutPlugin.d.ts +1 -0
- package/LexicalMarkdownShortcutPlugin.dev.js +2 -0
- package/LexicalMarkdownShortcutPlugin.js.flow +2 -0
- package/LexicalMarkdownShortcutPlugin.prod.js +2 -2
- package/LexicalOnChangePlugin.dev.js +1 -1
- package/LexicalOnChangePlugin.js.flow +1 -1
- package/LexicalPlainTextPlugin.dev.js +2 -2
- package/LexicalPlainTextPlugin.prod.js +2 -2
- package/LexicalRichTextPlugin.dev.js +2 -2
- package/LexicalRichTextPlugin.prod.js +2 -2
- package/LexicalTypeaheadMenuPlugin.d.ts +3 -3
- package/LexicalTypeaheadMenuPlugin.dev.js +12 -13
- package/LexicalTypeaheadMenuPlugin.js.flow +99 -0
- package/LexicalTypeaheadMenuPlugin.prod.js +14 -14
- package/package.json +19 -19
|
@@ -39,7 +39,7 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
41
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
42
|
-
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing(), editor.
|
|
42
|
+
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing(), editor.isEditable()));
|
|
43
43
|
return currentCanShowPlaceholder;
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -54,7 +54,7 @@ function useCanShowPlaceholder(editor) {
|
|
|
54
54
|
resetCanShowPlaceholder();
|
|
55
55
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
56
56
|
resetCanShowPlaceholder();
|
|
57
|
-
}), editor.
|
|
57
|
+
}), editor.registerEditableListener(() => {
|
|
58
58
|
resetCanShowPlaceholder();
|
|
59
59
|
}));
|
|
60
60
|
}, [editor]);
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var c=require("lexical"),f=require("react"),g=require("@lexical/text"),h=require("@lexical/utils"),k="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?f.useLayoutEffect:f.useEffect;function l(a){return a.getEditorState().read(g.$canShowPlaceholderCurry(a.isComposing(),a.
|
|
8
|
-
function m(a){let [b,d]=f.useState(()=>l(a));k(()=>{function e(){let n=l(a);d(n)}e();return h.mergeRegister(a.registerUpdateListener(()=>{e()}),a.
|
|
7
|
+
'use strict';var c=require("lexical"),f=require("react"),g=require("@lexical/text"),h=require("@lexical/utils"),k="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?f.useLayoutEffect:f.useEffect;function l(a){return a.getEditorState().read(g.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}
|
|
8
|
+
function m(a){let [b,d]=f.useState(()=>l(a));k(()=>{function e(){let n=l(a);d(n)}e();return h.mergeRegister(a.registerUpdateListener(()=>{e()}),a.registerEditableListener(()=>{e()}))},[a]);return b}function p(a){let b=m(a);return[f.useCallback(d=>{a.setRootElement(d)},[a]),b]}exports.useLexical=function(a){let b=f.useMemo(()=>c.createEditor(a),[]),[d,e]=p(b);return[b,d,e]}
|
|
@@ -38,7 +38,7 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
41
|
-
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing(), editor.
|
|
41
|
+
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing(), editor.isEditable()));
|
|
42
42
|
return currentCanShowPlaceholder;
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -53,7 +53,7 @@ function useCanShowPlaceholder(editor) {
|
|
|
53
53
|
resetCanShowPlaceholder();
|
|
54
54
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
55
55
|
resetCanShowPlaceholder();
|
|
56
|
-
}), editor.
|
|
56
|
+
}), editor.registerEditableListener(() => {
|
|
57
57
|
resetCanShowPlaceholder();
|
|
58
58
|
}));
|
|
59
59
|
}, [editor]);
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var b=require("@lexical/text"),d=require("@lexical/utils"),e=require("react"),f="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?e.useLayoutEffect:e.useEffect;function g(a){return a.getEditorState().read(b.$canShowPlaceholderCurry(a.isComposing(),a.
|
|
8
|
-
function h(a){let [k,l]=e.useState(()=>g(a));f(()=>{function c(){let m=g(a);l(m)}c();return d.mergeRegister(a.registerUpdateListener(()=>{c()}),a.
|
|
7
|
+
'use strict';var b=require("@lexical/text"),d=require("@lexical/utils"),e=require("react"),f="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?e.useLayoutEffect:e.useEffect;function g(a){return a.getEditorState().read(b.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}
|
|
8
|
+
function h(a){let [k,l]=e.useState(()=>g(a));f(()=>{function c(){let m=g(a);l(m)}c();return d.mergeRegister(a.registerUpdateListener(()=>{c()}),a.registerEditableListener(()=>{c()}))},[a]);return k}exports.useLexicalCanShowPlaceholder=function(a){return h(a)}
|
|
@@ -38,7 +38,7 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
41
|
-
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing(), editor.
|
|
41
|
+
const currentCanShowPlaceholder = editor.getEditorState().read(text.$canShowPlaceholderCurry(editor.isComposing(), editor.isEditable()));
|
|
42
42
|
return currentCanShowPlaceholder;
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -53,7 +53,7 @@ function useCanShowPlaceholder(editor) {
|
|
|
53
53
|
resetCanShowPlaceholder();
|
|
54
54
|
return utils.mergeRegister(editor.registerUpdateListener(() => {
|
|
55
55
|
resetCanShowPlaceholder();
|
|
56
|
-
}), editor.
|
|
56
|
+
}), editor.registerEditableListener(() => {
|
|
57
57
|
resetCanShowPlaceholder();
|
|
58
58
|
}));
|
|
59
59
|
}, [editor]);
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var b=require("react"),f=require("@lexical/text"),g=require("@lexical/utils"),h="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?b.useLayoutEffect:b.useEffect;function k(a){return a.getEditorState().read(f.$canShowPlaceholderCurry(a.isComposing(),a.
|
|
8
|
-
function l(a){let [c,d]=b.useState(()=>k(a));h(()=>{function e(){let m=k(a);d(m)}e();return g.mergeRegister(a.registerUpdateListener(()=>{e()}),a.
|
|
7
|
+
'use strict';var b=require("react"),f=require("@lexical/text"),g=require("@lexical/utils"),h="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?b.useLayoutEffect:b.useEffect;function k(a){return a.getEditorState().read(f.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}
|
|
8
|
+
function l(a){let [c,d]=b.useState(()=>k(a));h(()=>{function e(){let m=k(a);d(m)}e();return g.mergeRegister(a.registerUpdateListener(()=>{e()}),a.registerEditableListener(()=>{e()}))},[a]);return c}exports.useLexicalEditor=function(a){let c=l(a);return[b.useCallback(d=>{a.setRootElement(d)},[a]),c]}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
import type { LexicalNode } from 'lexical';
|
|
9
|
-
import { TypeaheadOption } from '@lexical/react/
|
|
9
|
+
import { TypeaheadOption } from '@lexical/react/LexicalTypeaheadMenuPlugin';
|
|
10
10
|
import { LexicalCommand, LexicalEditor } from 'lexical';
|
|
11
11
|
import * as React from 'react';
|
|
12
12
|
export declare type EmbedMatchResult = {
|
|
@@ -8,346 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
var link = require('@lexical/link');
|
|
10
10
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
11
|
+
var LexicalTypeaheadMenuPlugin = require('@lexical/react/LexicalTypeaheadMenuPlugin');
|
|
11
12
|
var utils = require('@lexical/utils');
|
|
12
13
|
var lexical = require('lexical');
|
|
13
14
|
var React = require('react');
|
|
14
15
|
var ReactDOM = require('react-dom');
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
18
|
-
*
|
|
19
|
-
* This source code is licensed under the MIT license found in the
|
|
20
|
-
* LICENSE file in the root directory of this source tree.
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
23
|
-
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
27
|
-
*
|
|
28
|
-
* This source code is licensed under the MIT license found in the
|
|
29
|
-
* LICENSE file in the root directory of this source tree.
|
|
30
|
-
*
|
|
31
|
-
*/
|
|
32
|
-
const useLayoutEffectImpl = CAN_USE_DOM ? React.useLayoutEffect : React.useEffect;
|
|
33
|
-
var useLayoutEffect = useLayoutEffectImpl;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
37
|
-
*
|
|
38
|
-
* This source code is licensed under the MIT license found in the
|
|
39
|
-
* LICENSE file in the root directory of this source tree.
|
|
40
|
-
*
|
|
41
|
-
*/
|
|
42
|
-
class TypeaheadOption {
|
|
43
|
-
constructor(key) {
|
|
44
|
-
this.key = key;
|
|
45
|
-
this.ref = {
|
|
46
|
-
current: null
|
|
47
|
-
};
|
|
48
|
-
this.setRefElement = this.setRefElement.bind(this);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
setRefElement(element) {
|
|
52
|
-
this.ref = {
|
|
53
|
-
current: element
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const scrollIntoViewIfNeeded = target => {
|
|
60
|
-
const container = document.getElementById('typeahead-menu');
|
|
61
|
-
|
|
62
|
-
if (container) {
|
|
63
|
-
const containerRect = container.getBoundingClientRect();
|
|
64
|
-
const targetRect = target.getBoundingClientRect();
|
|
65
|
-
|
|
66
|
-
if (targetRect.bottom > containerRect.bottom) {
|
|
67
|
-
target.scrollIntoView(false);
|
|
68
|
-
} else if (targetRect.top < containerRect.top) {
|
|
69
|
-
target.scrollIntoView();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* Walk backwards along user input and forward through entity title to try
|
|
75
|
-
* and replace more of the user's text with entity.
|
|
76
|
-
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
function getFullMatchOffset(documentText, entryText, offset) {
|
|
80
|
-
let triggerOffset = offset;
|
|
81
|
-
|
|
82
|
-
for (let i = triggerOffset; i <= entryText.length; i++) {
|
|
83
|
-
if (documentText.substr(-i) === entryText.substr(0, i)) {
|
|
84
|
-
triggerOffset = i;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return triggerOffset;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Split Lexical TextNode and return a new TextNode only containing matched text.
|
|
92
|
-
* Common use cases include: removing the node, replacing with a new node.
|
|
93
|
-
*/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
function splitNodeContainingQuery(editor, match) {
|
|
97
|
-
const selection = lexical.$getSelection();
|
|
98
|
-
|
|
99
|
-
if (!lexical.$isRangeSelection(selection) || !selection.isCollapsed()) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const anchor = selection.anchor;
|
|
104
|
-
|
|
105
|
-
if (anchor.type !== 'text') {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const anchorNode = anchor.getNode();
|
|
110
|
-
|
|
111
|
-
if (!anchorNode.isSimpleText()) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const selectionOffset = anchor.offset;
|
|
116
|
-
const textContent = anchorNode.getTextContent().slice(0, selectionOffset);
|
|
117
|
-
const characterOffset = match.replaceableString.length;
|
|
118
|
-
const queryOffset = getFullMatchOffset(textContent, match.matchingString, characterOffset);
|
|
119
|
-
const startOffset = selectionOffset - queryOffset;
|
|
120
|
-
|
|
121
|
-
if (startOffset < 0) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
let newNode;
|
|
126
|
-
|
|
127
|
-
if (startOffset === 0) {
|
|
128
|
-
[newNode] = anchorNode.splitText(selectionOffset);
|
|
129
|
-
} else {
|
|
130
|
-
[, newNode] = anchorNode.splitText(startOffset, selectionOffset);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return newNode;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function startTransition(callback) {
|
|
137
|
-
if (React.startTransition) {
|
|
138
|
-
React.startTransition(callback);
|
|
139
|
-
} else {
|
|
140
|
-
callback();
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function LexicalPopoverMenu({
|
|
145
|
-
close,
|
|
146
|
-
editor,
|
|
147
|
-
anchorElement,
|
|
148
|
-
resolution,
|
|
149
|
-
options,
|
|
150
|
-
menuRenderFn,
|
|
151
|
-
onSelectOption
|
|
152
|
-
}) {
|
|
153
|
-
const [selectedIndex, setHighlightedIndex] = React.useState(null);
|
|
154
|
-
React.useEffect(() => {
|
|
155
|
-
setHighlightedIndex(0);
|
|
156
|
-
}, [resolution.match.matchingString]);
|
|
157
|
-
const selectOptionAndCleanUp = React.useCallback(async selectedEntry => {
|
|
158
|
-
editor.update(() => {
|
|
159
|
-
const textNodeContainingQuery = splitNodeContainingQuery(editor, resolution.match);
|
|
160
|
-
onSelectOption(selectedEntry, textNodeContainingQuery, close, resolution.match.matchingString);
|
|
161
|
-
});
|
|
162
|
-
}, [close, editor, resolution.match, onSelectOption]);
|
|
163
|
-
const updateSelectedIndex = React.useCallback(index => {
|
|
164
|
-
const rootElem = editor.getRootElement();
|
|
165
|
-
|
|
166
|
-
if (rootElem !== null) {
|
|
167
|
-
rootElem.setAttribute('aria-activedescendant', 'typeahead-item-' + index);
|
|
168
|
-
setHighlightedIndex(index);
|
|
169
|
-
}
|
|
170
|
-
}, [editor]);
|
|
171
|
-
React.useEffect(() => {
|
|
172
|
-
return () => {
|
|
173
|
-
const rootElem = editor.getRootElement();
|
|
174
|
-
|
|
175
|
-
if (rootElem !== null) {
|
|
176
|
-
rootElem.removeAttribute('aria-activedescendant');
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
}, [editor]);
|
|
180
|
-
useLayoutEffect(() => {
|
|
181
|
-
if (options === null) {
|
|
182
|
-
setHighlightedIndex(null);
|
|
183
|
-
} else if (selectedIndex === null) {
|
|
184
|
-
updateSelectedIndex(0);
|
|
185
|
-
}
|
|
186
|
-
}, [options, selectedIndex, updateSelectedIndex]);
|
|
187
|
-
React.useEffect(() => {
|
|
188
|
-
return utils.mergeRegister(editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, payload => {
|
|
189
|
-
const event = payload;
|
|
190
|
-
|
|
191
|
-
if (options !== null && options.length && selectedIndex !== null) {
|
|
192
|
-
const newSelectedIndex = selectedIndex !== options.length - 1 ? selectedIndex + 1 : 0;
|
|
193
|
-
updateSelectedIndex(newSelectedIndex);
|
|
194
|
-
const option = options[newSelectedIndex];
|
|
195
|
-
|
|
196
|
-
if (option.ref != null && option.ref.current) {
|
|
197
|
-
scrollIntoViewIfNeeded(option.ref.current);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
event.preventDefault();
|
|
201
|
-
event.stopImmediatePropagation();
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return true;
|
|
205
|
-
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, payload => {
|
|
206
|
-
const event = payload;
|
|
207
|
-
|
|
208
|
-
if (options !== null && options.length && selectedIndex !== null) {
|
|
209
|
-
const newSelectedIndex = selectedIndex !== 0 ? selectedIndex - 1 : options.length - 1;
|
|
210
|
-
updateSelectedIndex(newSelectedIndex);
|
|
211
|
-
const option = options[newSelectedIndex];
|
|
212
|
-
|
|
213
|
-
if (option.ref != null && option.ref.current) {
|
|
214
|
-
scrollIntoViewIfNeeded(option.ref.current);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
event.preventDefault();
|
|
218
|
-
event.stopImmediatePropagation();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return true;
|
|
222
|
-
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, payload => {
|
|
223
|
-
const event = payload;
|
|
224
|
-
event.preventDefault();
|
|
225
|
-
event.stopImmediatePropagation();
|
|
226
|
-
close();
|
|
227
|
-
return true;
|
|
228
|
-
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_TAB_COMMAND, payload => {
|
|
229
|
-
const event = payload;
|
|
230
|
-
|
|
231
|
-
if (options === null || selectedIndex === null || options[selectedIndex] == null) {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
event.preventDefault();
|
|
236
|
-
event.stopImmediatePropagation();
|
|
237
|
-
selectOptionAndCleanUp(options[selectedIndex]);
|
|
238
|
-
return true;
|
|
239
|
-
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_ENTER_COMMAND, event => {
|
|
240
|
-
if (options === null || selectedIndex === null || options[selectedIndex] == null) {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (event !== null) {
|
|
245
|
-
event.preventDefault();
|
|
246
|
-
event.stopImmediatePropagation();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
selectOptionAndCleanUp(options[selectedIndex]);
|
|
250
|
-
return true;
|
|
251
|
-
}, lexical.COMMAND_PRIORITY_LOW));
|
|
252
|
-
}, [selectOptionAndCleanUp, close, editor, options, selectedIndex, updateSelectedIndex]);
|
|
253
|
-
const listItemProps = React.useMemo(() => ({
|
|
254
|
-
selectOptionAndCleanUp,
|
|
255
|
-
selectedIndex,
|
|
256
|
-
setHighlightedIndex
|
|
257
|
-
}), [selectOptionAndCleanUp, selectedIndex]);
|
|
258
|
-
return menuRenderFn(anchorElement, listItemProps, resolution.match.matchingString);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function useAnchorElementRef(resolution, options) {
|
|
262
|
-
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
263
|
-
const anchorElementRef = React.useRef(document.createElement('div'));
|
|
264
|
-
React.useEffect(() => {
|
|
265
|
-
const rootElement = editor.getRootElement();
|
|
266
|
-
|
|
267
|
-
function positionMenu() {
|
|
268
|
-
const containerDiv = anchorElementRef.current;
|
|
269
|
-
containerDiv.setAttribute('aria-label', 'Typeahead menu');
|
|
270
|
-
containerDiv.setAttribute('id', 'typeahead-menu');
|
|
271
|
-
containerDiv.setAttribute('role', 'listbox');
|
|
272
|
-
|
|
273
|
-
if (rootElement !== null && resolution !== null) {
|
|
274
|
-
const {
|
|
275
|
-
left,
|
|
276
|
-
top,
|
|
277
|
-
height,
|
|
278
|
-
width
|
|
279
|
-
} = resolution.getRect();
|
|
280
|
-
containerDiv.style.top = `${top + height + window.pageYOffset}px`;
|
|
281
|
-
containerDiv.style.left = `${left + width + window.pageXOffset}px`;
|
|
282
|
-
containerDiv.style.display = 'block';
|
|
283
|
-
containerDiv.style.position = 'absolute';
|
|
284
|
-
|
|
285
|
-
if (!containerDiv.isConnected) {
|
|
286
|
-
document.body.append(containerDiv);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
anchorElementRef.current = containerDiv;
|
|
290
|
-
rootElement.setAttribute('aria-controls', 'typeahead-menu');
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (resolution !== null) {
|
|
295
|
-
positionMenu();
|
|
296
|
-
window.addEventListener('resize', positionMenu);
|
|
297
|
-
return () => {
|
|
298
|
-
window.removeEventListener('resize', positionMenu);
|
|
299
|
-
|
|
300
|
-
if (rootElement !== null) {
|
|
301
|
-
rootElement.removeAttribute('aria-controls');
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
}, [editor, resolution, options]);
|
|
306
|
-
return anchorElementRef;
|
|
307
|
-
}
|
|
308
|
-
function LexicalNodeMenuPlugin({
|
|
309
|
-
options,
|
|
310
|
-
nodeKey,
|
|
311
|
-
onClose,
|
|
312
|
-
onSelectOption,
|
|
313
|
-
menuRenderFn
|
|
314
|
-
}) {
|
|
315
|
-
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
316
|
-
const [resolution, setResolution] = React.useState(null);
|
|
317
|
-
const anchorElementRef = useAnchorElementRef(resolution, options);
|
|
318
|
-
React.useEffect(() => {
|
|
319
|
-
if (nodeKey && resolution == null) {
|
|
320
|
-
editor.update(() => {
|
|
321
|
-
const node = lexical.$getNodeByKey(nodeKey);
|
|
322
|
-
const domElement = editor.getElementByKey(nodeKey);
|
|
323
|
-
|
|
324
|
-
if (node != null && domElement != null) {
|
|
325
|
-
const text = node.getTextContent();
|
|
326
|
-
startTransition(() => setResolution({
|
|
327
|
-
getRect: () => domElement.getBoundingClientRect(),
|
|
328
|
-
match: {
|
|
329
|
-
leadOffset: text.length,
|
|
330
|
-
matchingString: text,
|
|
331
|
-
replaceableString: text
|
|
332
|
-
}
|
|
333
|
-
}));
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
} else if (nodeKey == null && resolution != null) {
|
|
337
|
-
setResolution(null);
|
|
338
|
-
}
|
|
339
|
-
}, [editor, nodeKey, resolution]);
|
|
340
|
-
return resolution === null || editor === null ? null : /*#__PURE__*/React.createElement(LexicalPopoverMenu, {
|
|
341
|
-
close: onClose,
|
|
342
|
-
resolution: resolution,
|
|
343
|
-
editor: editor,
|
|
344
|
-
anchorElement: anchorElementRef.current,
|
|
345
|
-
options: options,
|
|
346
|
-
menuRenderFn: menuRenderFn,
|
|
347
|
-
onSelectOption: onSelectOption
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
|
|
351
17
|
/**
|
|
352
18
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
353
19
|
*
|
|
@@ -357,7 +23,7 @@ function LexicalNodeMenuPlugin({
|
|
|
357
23
|
*/
|
|
358
24
|
const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
359
25
|
const INSERT_EMBED_COMMAND = lexical.createCommand();
|
|
360
|
-
class AutoEmbedOption extends TypeaheadOption {
|
|
26
|
+
class AutoEmbedOption extends LexicalTypeaheadMenuPlugin.TypeaheadOption {
|
|
361
27
|
constructor(title, options) {
|
|
362
28
|
super(title);
|
|
363
29
|
this.title = title;
|
|
@@ -461,7 +127,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
461
127
|
closeMenu();
|
|
462
128
|
});
|
|
463
129
|
}, [editor]);
|
|
464
|
-
return nodeKey != null ? /*#__PURE__*/React.createElement(LexicalNodeMenuPlugin, {
|
|
130
|
+
return nodeKey != null ? /*#__PURE__*/React.createElement(LexicalTypeaheadMenuPlugin.LexicalNodeMenuPlugin, {
|
|
465
131
|
nodeKey: nodeKey,
|
|
466
132
|
onClose: reset,
|
|
467
133
|
onSelectOption: onSelectOption,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {LexicalNode, MutationListener} from 'lexical';
|
|
11
|
+
|
|
12
|
+
import {TypeaheadOption} from '@lexical/react/LexicalTypeaheadMenuPlugin';
|
|
13
|
+
import type {LexicalCommand, LexicalEditor, NodeKey, TextNode} from 'lexical';
|
|
14
|
+
import * as React from 'react';
|
|
15
|
+
import {createCommand} from 'lexical';
|
|
16
|
+
|
|
17
|
+
export type EmbedMatchResult = {
|
|
18
|
+
url: string,
|
|
19
|
+
id: string,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface EmbedConfig {
|
|
23
|
+
// Used to identify this config e.g. youtube, tweet, google-maps.
|
|
24
|
+
type: string;
|
|
25
|
+
// Determine if a given URL is a match and return url data.
|
|
26
|
+
parseUrl: (text: string) => EmbedMatchResult | null;
|
|
27
|
+
// Create the Lexical embed node from the url data.
|
|
28
|
+
insertNode: (editor: LexicalEditor, result: EmbedMatchResult) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const URL_MATCHER: RegExp =
|
|
32
|
+
/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
33
|
+
|
|
34
|
+
export const INSERT_EMBED_COMMAND: LexicalCommand<EmbedConfig['type']> =
|
|
35
|
+
createCommand();
|
|
36
|
+
|
|
37
|
+
export type EmbedMenuProps = {
|
|
38
|
+
selectedItemIndex: number | null,
|
|
39
|
+
onOptionClick: (option: AutoEmbedOption, index: number) => void,
|
|
40
|
+
onOptionMouseEnter: (index: number) => void,
|
|
41
|
+
options: Array<AutoEmbedOption>,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type EmbedMenuComponent = React.ComponentType<EmbedMenuProps>;
|
|
45
|
+
|
|
46
|
+
type LexicalAutoEmbedPluginProps<TEmbedConfig> = {
|
|
47
|
+
embedConfigs: Array<TEmbedConfig>,
|
|
48
|
+
onOpenEmbedModalForConfig: (embedConfig: TEmbedConfig) => void,
|
|
49
|
+
menuComponent: EmbedMenuComponent,
|
|
50
|
+
getMenuOptions: (
|
|
51
|
+
activeEmbedConfig: TEmbedConfig,
|
|
52
|
+
embedFn: () => void,
|
|
53
|
+
dismissFn: () => void,
|
|
54
|
+
) => Array<AutoEmbedOption>,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
declare export class AutoEmbedOption extends TypeaheadOption {
|
|
58
|
+
title: string;
|
|
59
|
+
icon: React.MixedElement;
|
|
60
|
+
onSelect: (targetNode: LexicalNode | null) => void;
|
|
61
|
+
constructor(
|
|
62
|
+
title: string,
|
|
63
|
+
options: {
|
|
64
|
+
icon: React.MixedElement,
|
|
65
|
+
onSelect: (targetNode: LexicalNode | null) => void,
|
|
66
|
+
},
|
|
67
|
+
): void;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
declare export function LexicalAutoEmbedPlugin<TEmbedConfig>(
|
|
71
|
+
LexicalAutoEmbedPluginProps<TEmbedConfig>,
|
|
72
|
+
): React.MixedElement | null;
|
|
@@ -4,18 +4,8 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var
|
|
8
|
-
let
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
h.stopImmediatePropagation()}return!0},A.COMMAND_PRIORITY_LOW),a.registerCommand(A.KEY_ESCAPE_COMMAND,h=>{h.preventDefault();h.stopImmediatePropagation();b();return!0},A.COMMAND_PRIORITY_LOW),a.registerCommand(A.KEY_TAB_COMMAND,h=>{if(null===c||null===d||null==c[d])return!1;h.preventDefault();h.stopImmediatePropagation();p(c[d]);return!0},A.COMMAND_PRIORITY_LOW),a.registerCommand(A.KEY_ENTER_COMMAND,h=>{if(null===c||null===d||null==c[d])return!1;null!==h&&(h.preventDefault(),h.stopImmediatePropagation());
|
|
13
|
-
p(c[d]);return!0},A.COMMAND_PRIORITY_LOW)),[p,b,a,c,d,t]);let w=C.useMemo(()=>({selectOptionAndCleanUp:p,selectedIndex:d,setHighlightedIndex:v}),[p,d]);return g(k,w,q.match.matchingString)}
|
|
14
|
-
function K(b,a){let [k]=n.useLexicalComposerContext(),q=C.useRef(document.createElement("div"));C.useEffect(()=>{function c(){let e=q.current;e.setAttribute("aria-label","Typeahead menu");e.setAttribute("id","typeahead-menu");e.setAttribute("role","listbox");if(null!==g&&null!==b){let {left:d,top:v,height:p,width:t}=b.getRect();e.style.top=`${v+p+window.pageYOffset}px`;e.style.left=`${d+t+window.pageXOffset}px`;e.style.display="block";e.style.position="absolute";e.isConnected||document.body.append(e);
|
|
15
|
-
q.current=e;g.setAttribute("aria-controls","typeahead-menu")}}let g=k.getRootElement();if(null!==b)return c(),window.addEventListener("resize",c),()=>{window.removeEventListener("resize",c);null!==g&&g.removeAttribute("aria-controls")}},[k,b,a]);return q}
|
|
16
|
-
function L({options:b,nodeKey:a,onClose:k,onSelectOption:q,menuRenderFn:c}){let [g]=n.useLexicalComposerContext(),[e,d]=C.useState(null),v=K(e,b);C.useEffect(()=>{a&&null==e?g.update(()=>{let p=A.$getNodeByKey(a),t=g.getElementByKey(a);if(null!=p&&null!=t){let w=p.getTextContent();I(()=>d({getRect:()=>t.getBoundingClientRect(),match:{leadOffset:w.length,matchingString:w,replaceableString:w}}))}}):null==a&&null!=e&&d(null)},[g,a,e]);return null===e||null===g?null:C.createElement(J,{close:k,resolution:e,
|
|
17
|
-
editor:g,anchorElement:v.current,options:b,menuRenderFn:c,onSelectOption:q})}let M=A.createCommand();class N extends F{constructor(b,a){super(b);this.title=b;this.icon=a.icon;this.onSelect=a.onSelect.bind(this)}}exports.AutoEmbedOption=N;exports.INSERT_EMBED_COMMAND=M;
|
|
18
|
-
exports.LexicalAutoEmbedPlugin=function({embedConfigs:b,onOpenEmbedModalForConfig:a,getMenuOptions:k,menuComponent:q}){let [c]=n.useLexicalComposerContext(),[g,e]=C.useState(null),[d,v]=C.useState(null),p=C.useCallback(()=>{e(null);v(null)},[]),t=C.useCallback(r=>{c.getEditorState().read(()=>{const m=A.$getNodeByKey(r);if(f.$isLinkNode(m)){const u=b.find(x=>x.parseUrl(m.__url));null!=u&&(v(u),e(m.getKey()))}})},[c,b]);C.useEffect(()=>{let r=(m,{updateTags:u,dirtyLeaves:x})=>{for(const [y,B]of m)"created"===
|
|
19
|
-
B&&u.has("paste")&&1===x.size?t(y):y===g&&p()};return z.mergeRegister(...[f.LinkNode,f.AutoLinkNode].map(m=>c.registerMutationListener(m,(...u)=>r(...u))))},[t,c,b,g,p]);C.useEffect(()=>c.registerCommand(M,r=>{let m=b.find(({type:u})=>u===r);return m?(a(m),!0):!1},A.COMMAND_PRIORITY_EDITOR),[c,b,a]);let w=C.useCallback(()=>{if(null!=d&&null!=g){const r=c.getEditorState().read(()=>{const m=A.$getNodeByKey(g);return f.$isLinkNode(m)?m:null});if(f.$isLinkNode(r)){const m=d.parseUrl(r.__url);null!=m&&
|
|
20
|
-
(c.update(()=>{d.insertNode(c,m)}),r.isAttached()&&c.update(()=>{r.remove()}))}}},[d,c,g]),h=C.useMemo(()=>null!=d&&null!=g?k(d,w,p):[],[d,w,k,g,p]),l=C.useCallback((r,m,u)=>{c.update(()=>{r.onSelect(m);u()})},[c]);return null!=g?C.createElement(L,{nodeKey:g,onClose:p,onSelectOption:l,options:h,menuRenderFn:(r,{selectedIndex:m,selectOptionAndCleanUp:u,setHighlightedIndex:x})=>r&&null!=g?D.createPortal(C.createElement(q,{options:h,selectedItemIndex:m,onOptionClick:(y,B)=>{x(B);u(y)},onOptionMouseEnter:y=>
|
|
21
|
-
{x(y)}}),r):null}):null};exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/
|
|
7
|
+
'use strict';var e=require("@lexical/link"),m=require("@lexical/react/LexicalComposerContext"),q=require("@lexical/react/LexicalTypeaheadMenuPlugin"),t=require("@lexical/utils"),u=require("lexical"),B=require("react"),C=require("react-dom");let D=u.createCommand();class E extends q.TypeaheadOption{constructor(g,n){super(g);this.title=g;this.icon=n.icon;this.onSelect=n.onSelect.bind(this)}}exports.AutoEmbedOption=E;exports.INSERT_EMBED_COMMAND=D;
|
|
8
|
+
exports.LexicalAutoEmbedPlugin=function({embedConfigs:g,onOpenEmbedModalForConfig:n,getMenuOptions:v,menuComponent:F}){let [c]=m.useLexicalComposerContext(),[f,w]=B.useState(null),[h,x]=B.useState(null),p=B.useCallback(()=>{w(null);x(null)},[]),y=B.useCallback(b=>{c.getEditorState().read(()=>{const a=u.$getNodeByKey(b);if(e.$isLinkNode(a)){const d=g.find(k=>k.parseUrl(a.__url));null!=d&&(x(d),w(a.getKey()))}})},[c,g]);B.useEffect(()=>{let b=(a,{updateTags:d,dirtyLeaves:k})=>{for(const [l,r]of a)"created"===
|
|
9
|
+
r&&d.has("paste")&&1===k.size?y(l):l===f&&p()};return t.mergeRegister(...[e.LinkNode,e.AutoLinkNode].map(a=>c.registerMutationListener(a,(...d)=>b(...d))))},[y,c,g,f,p]);B.useEffect(()=>c.registerCommand(D,b=>{let a=g.find(({type:d})=>d===b);return a?(n(a),!0):!1},u.COMMAND_PRIORITY_EDITOR),[c,g,n]);let z=B.useCallback(()=>{if(null!=h&&null!=f){const b=c.getEditorState().read(()=>{const a=u.$getNodeByKey(f);return e.$isLinkNode(a)?a:null});if(e.$isLinkNode(b)){const a=h.parseUrl(b.__url);null!=a&&
|
|
10
|
+
(c.update(()=>{h.insertNode(c,a)}),b.isAttached()&&c.update(()=>{b.remove()}))}}},[h,c,f]),A=B.useMemo(()=>null!=h&&null!=f?v(h,z,p):[],[h,z,v,f,p]),G=B.useCallback((b,a,d)=>{c.update(()=>{b.onSelect(a);d()})},[c]);return null!=f?B.createElement(q.LexicalNodeMenuPlugin,{nodeKey:f,onClose:p,onSelectOption:G,options:A,menuRenderFn:(b,{selectedIndex:a,selectOptionAndCleanUp:d,setHighlightedIndex:k})=>b&&null!=f?C.createPortal(B.createElement(F,{options:A,selectedItemIndex:a,onOptionClick:(l,r)=>{k(r);
|
|
11
|
+
d(l)},onOptionMouseEnter:l=>{k(l)}}),b):null}):null};exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/
|
|
@@ -46,7 +46,7 @@ function CheckListPlugin() {
|
|
|
46
46
|
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_SPACE_COMMAND, event => {
|
|
47
47
|
const activeItem = getActiveCheckListItem();
|
|
48
48
|
|
|
49
|
-
if (activeItem != null &&
|
|
49
|
+
if (activeItem != null && editor.isEditable()) {
|
|
50
50
|
editor.update(() => {
|
|
51
51
|
const listItemNode = lexical.$getNearestNodeFromDOMNode(activeItem);
|
|
52
52
|
|
|
@@ -140,7 +140,7 @@ function handleClick(event) {
|
|
|
140
140
|
const domNode = event.target;
|
|
141
141
|
const editor = findEditor(domNode);
|
|
142
142
|
|
|
143
|
-
if (editor != null &&
|
|
143
|
+
if (editor != null && editor.isEditable()) {
|
|
144
144
|
editor.update(() => {
|
|
145
145
|
if (event.target) {
|
|
146
146
|
const node = lexical.$getNearestNodeFromDOMNode(domNode);
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
'use strict';var e=require("@lexical/list"),g=require("@lexical/react/LexicalComposerContext"),k=require("@lexical/utils"),l=require("lexical"),m=require("react");let n=0;function p(){0===n++&&(document.addEventListener("click",q),document.addEventListener("pointerdown",r));return()=>{0===--n&&(document.removeEventListener("click",q),document.removeEventListener("pointerdown",r))}}
|
|
8
8
|
function t(a,d){let b=a.target;if(b instanceof HTMLElement){var c=b.firstChild;null!=c&&c instanceof HTMLElement&&("UL"===c.tagName||"OL"===c.tagName)||(c=b.parentNode)&&"check"===c.__lexicalListType&&(a=a.pageX,c=b.getBoundingClientRect(),("rtl"===b.dir?a<c.right&&a>c.right-20:a>c.left&&a<c.left+20)&&d())}}
|
|
9
|
-
function q(a){t(a,()=>{let d=a.target,b=u(d);null
|
|
9
|
+
function q(a){t(a,()=>{let d=a.target,b=u(d);null!=b&&b.isEditable()&&b.update(()=>{if(a.target){let c=l.$getNearestNodeFromDOMNode(d);e.$isListItemNode(c)&&(d.focus(),c.toggleChecked())}})})}function r(a){t(a,()=>{a.preventDefault()})}function u(a){for(;a;){if(a.__lexicalEditor)return a.__lexicalEditor;a=a.parentNode}return null}function v(){let a=document.activeElement;return null!=a&&"LI"===a.tagName&&null!=a.parentNode&&"check"===a.parentNode.__lexicalListType?a:null}
|
|
10
10
|
function w(a,d){let b=d?a.getPreviousSibling():a.getNextSibling();for(;null==b&&e.$isListItemNode(a);)a=a.getParentOrThrow().getParent(),null!=a&&(b=d?a.getPreviousSibling():a.getNextSibling());for(;e.$isListItemNode(b);){a=d?b.getLastChild():b.getFirstChild();if(!e.$isListNode(a))return b;b=d?a.getLastChild():a.getFirstChild()}return null}
|
|
11
11
|
function x(a,d,b){let c=v();null!=c&&d.update(()=>{var f=l.$getNearestNodeFromDOMNode(c);if(e.$isListItemNode(f)&&(f=w(f,b),null!=f)){f.selectStart();let h=d.getElementByKey(f.__key);null!=h&&(a.preventDefault(),setTimeout(()=>{h.focus()},0))}});return!1}
|
|
12
12
|
exports.CheckListPlugin=function(){let [a]=g.useLexicalComposerContext();m.useEffect(()=>k.mergeRegister(a.registerCommand(e.INSERT_CHECK_LIST_COMMAND,()=>{e.insertList(a,"check");return!0},l.COMMAND_PRIORITY_LOW),a.registerCommand(l.KEY_ARROW_DOWN_COMMAND,d=>x(d,a,!1),l.COMMAND_PRIORITY_LOW),a.registerCommand(l.KEY_ARROW_UP_COMMAND,d=>x(d,a,!0),l.COMMAND_PRIORITY_LOW),a.registerCommand(l.KEY_ESCAPE_COMMAND,()=>{if(null!=v()){let d=a.getRootElement();null!=d&&d.focus();return!0}return!1},l.COMMAND_PRIORITY_LOW),
|
|
13
|
-
a.registerCommand(l.KEY_SPACE_COMMAND,d=>{let b=v();return null
|
|
13
|
+
a.registerCommand(l.KEY_SPACE_COMMAND,d=>{let b=v();return null!=b&&a.isEditable()?(a.update(()=>{let c=l.$getNearestNodeFromDOMNode(b);e.$isListItemNode(c)&&(d.preventDefault(),c.toggleChecked())}),!0):!1},l.COMMAND_PRIORITY_LOW),a.registerCommand(l.KEY_ARROW_LEFT_COMMAND,d=>a.getEditorState().read(()=>{var b=l.$getSelection();if(l.$isRangeSelection(b)&&b.isCollapsed()){var {anchor:c}=b;if((b="element"===c.type)||0===c.offset){c=c.getNode();let f=k.$findMatchingParent(c,h=>l.$isElementNode(h)&&!h.isInline());
|
|
14
14
|
if(e.$isListItemNode(f)&&(b||f.getFirstDescendant()===c)&&(b=a.getElementByKey(f.__key),null!=b&&document.activeElement!==b))return b.focus(),d.preventDefault(),!0}}return!1}),l.COMMAND_PRIORITY_LOW),p()));return null}
|
|
@@ -78,7 +78,8 @@ function useYjsCollaboration(editor, id, provider, docMap, name, color, shouldBo
|
|
|
78
78
|
provider.on('reload', onProviderDocReload);
|
|
79
79
|
provider.on('status', onStatus);
|
|
80
80
|
provider.on('sync', onSync);
|
|
81
|
-
awareness.on('update', onAwarenessUpdate);
|
|
81
|
+
awareness.on('update', onAwarenessUpdate); // This updates the local editor state when we recieve updates from other clients
|
|
82
|
+
|
|
82
83
|
root.getSharedType().observeDeep(onYjsTreeChanges);
|
|
83
84
|
const removeListener = editor.registerUpdateListener(({
|
|
84
85
|
prevEditorState,
|
|
@@ -7,24 +7,9 @@
|
|
|
7
7
|
* @flow strict
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type {ProviderAwareness} from '@lexical/yjs';
|
|
10
11
|
import type {Doc, RelativePosition} from 'yjs';
|
|
11
12
|
|
|
12
|
-
export type UserState = {
|
|
13
|
-
anchorPos: null | RelativePosition,
|
|
14
|
-
focusPos: null | RelativePosition,
|
|
15
|
-
name: string,
|
|
16
|
-
color: string,
|
|
17
|
-
focusing: boolean,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type ProviderAwareness = {
|
|
21
|
-
getLocalState: () => UserState | null,
|
|
22
|
-
setLocalState: (UserState) => void,
|
|
23
|
-
getStates: () => Map<number, UserState>,
|
|
24
|
-
on: (type: 'update', cb: () => void) => void,
|
|
25
|
-
off: (type: 'update', cb: () => void) => void,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
13
|
export interface Provider {
|
|
29
14
|
connect(): void | Promise<void>;
|
|
30
15
|
disconnect(): void;
|
package/LexicalComposer.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ declare type Props = {
|
|
|
15
15
|
namespace: string;
|
|
16
16
|
nodes?: ReadonlyArray<Klass<LexicalNode>>;
|
|
17
17
|
onError: (error: Error, editor: LexicalEditor) => void;
|
|
18
|
-
|
|
18
|
+
editable?: boolean;
|
|
19
19
|
theme?: EditorThemeClasses;
|
|
20
20
|
editorState?: InitialEditorStateType;
|
|
21
21
|
}>;
|