lexical 0.3.1 → 0.3.4
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/Lexical.dev.js +231 -214
- package/Lexical.js.flow +17 -10
- package/Lexical.prod.js +172 -170
- package/LexicalCommands.d.ts +50 -0
- package/LexicalConstants.d.ts +42 -0
- package/LexicalEditor.d.ts +200 -0
- package/LexicalEditorState.d.ts +28 -0
- package/LexicalEvents.d.ts +14 -0
- package/LexicalGC.d.ts +12 -0
- package/LexicalMutations.d.ts +12 -0
- package/LexicalNode.d.ts +82 -0
- package/LexicalNormalization.d.ts +9 -0
- package/LexicalReconciler.d.ts +12 -0
- package/LexicalSelection.d.ts +147 -0
- package/LexicalUpdates.d.ts +25 -0
- package/LexicalUtils.d.ts +95 -0
- package/LexicalVersion.d.ts +8 -0
- package/README.md +1 -0
- package/index.d.ts +31 -0
- package/nodes/LexicalDecoratorNode.d.ts +18 -0
- package/nodes/LexicalElementNode.d.ts +71 -0
- package/nodes/LexicalGridCellNode.d.ts +18 -0
- package/nodes/LexicalGridNode.d.ts +12 -0
- package/nodes/LexicalGridRowNode.d.ts +12 -0
- package/nodes/LexicalLineBreakNode.d.ts +26 -0
- package/nodes/LexicalParagraphNode.d.ts +30 -0
- package/nodes/LexicalRootNode.d.ts +29 -0
- package/nodes/LexicalTextNode.d.ts +74 -0
- package/package.json +4 -2
- package/Lexical.d.ts +0 -849
package/Lexical.dev.js
CHANGED
|
@@ -6,6 +6,58 @@
|
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11
|
+
*
|
|
12
|
+
* This source code is licensed under the MIT license found in the
|
|
13
|
+
* LICENSE file in the root directory of this source tree.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
function createCommand() {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
const SELECTION_CHANGE_COMMAND = createCommand();
|
|
20
|
+
const CLICK_COMMAND = createCommand();
|
|
21
|
+
const DELETE_CHARACTER_COMMAND = createCommand();
|
|
22
|
+
const INSERT_LINE_BREAK_COMMAND = createCommand();
|
|
23
|
+
const INSERT_PARAGRAPH_COMMAND = createCommand();
|
|
24
|
+
const CONTROLLED_TEXT_INSERTION_COMMAND = createCommand();
|
|
25
|
+
const PASTE_COMMAND = createCommand();
|
|
26
|
+
const REMOVE_TEXT_COMMAND = createCommand();
|
|
27
|
+
const DELETE_WORD_COMMAND = createCommand();
|
|
28
|
+
const DELETE_LINE_COMMAND = createCommand();
|
|
29
|
+
const FORMAT_TEXT_COMMAND = createCommand();
|
|
30
|
+
const UNDO_COMMAND = createCommand();
|
|
31
|
+
const REDO_COMMAND = createCommand();
|
|
32
|
+
const KEY_ARROW_RIGHT_COMMAND = createCommand();
|
|
33
|
+
const MOVE_TO_END = createCommand();
|
|
34
|
+
const KEY_ARROW_LEFT_COMMAND = createCommand();
|
|
35
|
+
const MOVE_TO_START = createCommand();
|
|
36
|
+
const KEY_ARROW_UP_COMMAND = createCommand();
|
|
37
|
+
const KEY_ARROW_DOWN_COMMAND = createCommand();
|
|
38
|
+
const KEY_ENTER_COMMAND = createCommand();
|
|
39
|
+
const KEY_SPACE_COMMAND = createCommand();
|
|
40
|
+
const KEY_BACKSPACE_COMMAND = createCommand();
|
|
41
|
+
const KEY_ESCAPE_COMMAND = createCommand();
|
|
42
|
+
const KEY_DELETE_COMMAND = createCommand();
|
|
43
|
+
const KEY_TAB_COMMAND = createCommand();
|
|
44
|
+
const INDENT_CONTENT_COMMAND = createCommand();
|
|
45
|
+
const OUTDENT_CONTENT_COMMAND = createCommand();
|
|
46
|
+
const DROP_COMMAND = createCommand();
|
|
47
|
+
const FORMAT_ELEMENT_COMMAND = createCommand();
|
|
48
|
+
const DRAGSTART_COMMAND = createCommand();
|
|
49
|
+
const DRAGOVER_COMMAND = createCommand();
|
|
50
|
+
const DRAGEND_COMMAND = createCommand();
|
|
51
|
+
const COPY_COMMAND = createCommand();
|
|
52
|
+
const CUT_COMMAND = createCommand();
|
|
53
|
+
const CLEAR_EDITOR_COMMAND = createCommand();
|
|
54
|
+
const CLEAR_HISTORY_COMMAND = createCommand();
|
|
55
|
+
const CAN_REDO_COMMAND = createCommand();
|
|
56
|
+
const CAN_UNDO_COMMAND = createCommand();
|
|
57
|
+
const FOCUS_COMMAND = createCommand();
|
|
58
|
+
const BLUR_COMMAND = createCommand();
|
|
59
|
+
const KEY_MODIFIER_COMMAND = createCommand();
|
|
60
|
+
|
|
9
61
|
/**
|
|
10
62
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11
63
|
*
|
|
@@ -173,12 +225,25 @@ function handleTextMutation(target, node, editor) {
|
|
|
173
225
|
$updateTextNodeFromDOMContent(node, text, anchorOffset, focusOffset, false);
|
|
174
226
|
}
|
|
175
227
|
|
|
228
|
+
function shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) {
|
|
229
|
+
if ($isRangeSelection(selection)) {
|
|
230
|
+
const anchorNode = selection.anchor.getNode();
|
|
231
|
+
|
|
232
|
+
if (anchorNode.is(targetNode) && selection.format !== anchorNode.getFormat()) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached();
|
|
238
|
+
}
|
|
239
|
+
|
|
176
240
|
function $flushMutations$1(editor, mutations, observer) {
|
|
177
241
|
isProcessingMutations = true;
|
|
178
242
|
const shouldFlushTextMutations = performance.now() - lastTextEntryTimeStamp > TEXT_MUTATION_VARIANCE;
|
|
179
243
|
|
|
180
244
|
try {
|
|
181
245
|
updateEditor(editor, () => {
|
|
246
|
+
const selection = $getSelection() || getLastSelection(editor);
|
|
182
247
|
const badDOMTargets = new Map();
|
|
183
248
|
const rootElement = editor.getRootElement(); // We use the current edtior state, as that reflects what is
|
|
184
249
|
// actually "on screen".
|
|
@@ -200,7 +265,7 @@ function $flushMutations$1(editor, mutations, observer) {
|
|
|
200
265
|
if (type === 'characterData') {
|
|
201
266
|
// Text mutations are deferred and passed to mutation listeners to be
|
|
202
267
|
// processed outside of the Lexical engine.
|
|
203
|
-
if (shouldFlushTextMutations &&
|
|
268
|
+
if (shouldFlushTextMutations && $isTextNode(targetNode) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode)) {
|
|
204
269
|
handleTextMutation( // nodeType === DOM_TEXT_TYPE is a Text DOM node
|
|
205
270
|
targetDOM, targetNode);
|
|
206
271
|
}
|
|
@@ -315,8 +380,6 @@ function $flushMutations$1(editor, mutations, observer) {
|
|
|
315
380
|
observer.takeRecords();
|
|
316
381
|
}
|
|
317
382
|
|
|
318
|
-
const selection = $getSelection() || getLastSelection(editor);
|
|
319
|
-
|
|
320
383
|
if (selection !== null) {
|
|
321
384
|
if (shouldRevertSelection) {
|
|
322
385
|
selection.dirty = true;
|
|
@@ -664,7 +727,6 @@ function $setSelection(selection) {
|
|
|
664
727
|
const editorState = getActiveEditorState();
|
|
665
728
|
|
|
666
729
|
if (selection !== null) {
|
|
667
|
-
// @ts-ignore
|
|
668
730
|
{
|
|
669
731
|
if (Object.isFrozen(selection)) {
|
|
670
732
|
{
|
|
@@ -1173,11 +1235,12 @@ function scrollIntoViewIfNeeded(editor, anchor, rootElement, tags) {
|
|
|
1173
1235
|
} else if (rect.top < 0) {
|
|
1174
1236
|
element.scrollIntoView();
|
|
1175
1237
|
} else {
|
|
1176
|
-
const rootRect = rootElement.getBoundingClientRect();
|
|
1238
|
+
const rootRect = rootElement.getBoundingClientRect(); // Rects can returning decimal numbers that differ due to rounding
|
|
1239
|
+
// differences. So let's normalize the values.
|
|
1177
1240
|
|
|
1178
|
-
if (rect.bottom > rootRect.bottom) {
|
|
1241
|
+
if (Math.floor(rect.bottom) > Math.floor(rootRect.bottom)) {
|
|
1179
1242
|
element.scrollIntoView(false);
|
|
1180
|
-
} else if (rect.top < rootRect.top) {
|
|
1243
|
+
} else if (Math.floor(rect.top) < Math.floor(rootRect.top)) {
|
|
1181
1244
|
element.scrollIntoView();
|
|
1182
1245
|
}
|
|
1183
1246
|
}
|
|
@@ -1473,7 +1536,7 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
1473
1536
|
const text = node.getTextContent();
|
|
1474
1537
|
|
|
1475
1538
|
if ($isDecoratorNode(node)) {
|
|
1476
|
-
const decorator = node.decorate(activeEditor$1);
|
|
1539
|
+
const decorator = node.decorate(activeEditor$1, activeEditorConfig);
|
|
1477
1540
|
|
|
1478
1541
|
if (decorator !== null) {
|
|
1479
1542
|
reconcileDecorator(key, decorator);
|
|
@@ -1513,8 +1576,7 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
1513
1576
|
parentDOM.appendChild(dom);
|
|
1514
1577
|
}
|
|
1515
1578
|
}
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1579
|
+
}
|
|
1518
1580
|
|
|
1519
1581
|
{
|
|
1520
1582
|
// Freeze the node in DEV to prevent accidental mutations
|
|
@@ -1789,7 +1851,7 @@ function reconcileNode(key, parentDOM) {
|
|
|
1789
1851
|
const text = nextNode.getTextContent();
|
|
1790
1852
|
|
|
1791
1853
|
if ($isDecoratorNode(nextNode)) {
|
|
1792
|
-
const decorator = nextNode.decorate(activeEditor$1);
|
|
1854
|
+
const decorator = nextNode.decorate(activeEditor$1, activeEditorConfig);
|
|
1793
1855
|
|
|
1794
1856
|
if (decorator !== null) {
|
|
1795
1857
|
reconcileDecorator(key, decorator);
|
|
@@ -1810,8 +1872,7 @@ function reconcileNode(key, parentDOM) {
|
|
|
1810
1872
|
// Cache the latest text content.
|
|
1811
1873
|
nextNode = nextNode.getWritable();
|
|
1812
1874
|
nextNode.__cachedText = editorTextContent;
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1875
|
+
}
|
|
1815
1876
|
|
|
1816
1877
|
{
|
|
1817
1878
|
// Freeze the node in DEV to prevent accidental mutations
|
|
@@ -1970,58 +2031,6 @@ function getPrevElementByKeyOrThrow(key) {
|
|
|
1970
2031
|
return element;
|
|
1971
2032
|
}
|
|
1972
2033
|
|
|
1973
|
-
/**
|
|
1974
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1975
|
-
*
|
|
1976
|
-
* This source code is licensed under the MIT license found in the
|
|
1977
|
-
* LICENSE file in the root directory of this source tree.
|
|
1978
|
-
*
|
|
1979
|
-
*/
|
|
1980
|
-
function createCommand() {
|
|
1981
|
-
return {};
|
|
1982
|
-
}
|
|
1983
|
-
const SELECTION_CHANGE_COMMAND = createCommand();
|
|
1984
|
-
const CLICK_COMMAND = createCommand();
|
|
1985
|
-
const DELETE_CHARACTER_COMMAND = createCommand();
|
|
1986
|
-
const INSERT_LINE_BREAK_COMMAND = createCommand();
|
|
1987
|
-
const INSERT_PARAGRAPH_COMMAND = createCommand();
|
|
1988
|
-
const CONTROLLED_TEXT_INSERTION_COMMAND = createCommand();
|
|
1989
|
-
const PASTE_COMMAND = createCommand();
|
|
1990
|
-
const REMOVE_TEXT_COMMAND = createCommand();
|
|
1991
|
-
const DELETE_WORD_COMMAND = createCommand();
|
|
1992
|
-
const DELETE_LINE_COMMAND = createCommand();
|
|
1993
|
-
const FORMAT_TEXT_COMMAND = createCommand();
|
|
1994
|
-
const UNDO_COMMAND = createCommand();
|
|
1995
|
-
const REDO_COMMAND = createCommand();
|
|
1996
|
-
const KEY_ARROW_RIGHT_COMMAND = createCommand();
|
|
1997
|
-
const MOVE_TO_END = createCommand();
|
|
1998
|
-
const KEY_ARROW_LEFT_COMMAND = createCommand();
|
|
1999
|
-
const MOVE_TO_START = createCommand();
|
|
2000
|
-
const KEY_ARROW_UP_COMMAND = createCommand();
|
|
2001
|
-
const KEY_ARROW_DOWN_COMMAND = createCommand();
|
|
2002
|
-
const KEY_ENTER_COMMAND = createCommand();
|
|
2003
|
-
const KEY_SPACE_COMMAND = createCommand();
|
|
2004
|
-
const KEY_BACKSPACE_COMMAND = createCommand();
|
|
2005
|
-
const KEY_ESCAPE_COMMAND = createCommand();
|
|
2006
|
-
const KEY_DELETE_COMMAND = createCommand();
|
|
2007
|
-
const KEY_TAB_COMMAND = createCommand();
|
|
2008
|
-
const INDENT_CONTENT_COMMAND = createCommand();
|
|
2009
|
-
const OUTDENT_CONTENT_COMMAND = createCommand();
|
|
2010
|
-
const DROP_COMMAND = createCommand();
|
|
2011
|
-
const FORMAT_ELEMENT_COMMAND = createCommand();
|
|
2012
|
-
const DRAGSTART_COMMAND = createCommand();
|
|
2013
|
-
const DRAGOVER_COMMAND = createCommand();
|
|
2014
|
-
const DRAGEND_COMMAND = createCommand();
|
|
2015
|
-
const COPY_COMMAND = createCommand();
|
|
2016
|
-
const CUT_COMMAND = createCommand();
|
|
2017
|
-
const CLEAR_EDITOR_COMMAND = createCommand();
|
|
2018
|
-
const CLEAR_HISTORY_COMMAND = createCommand();
|
|
2019
|
-
const CAN_REDO_COMMAND = createCommand();
|
|
2020
|
-
const CAN_UNDO_COMMAND = createCommand();
|
|
2021
|
-
const FOCUS_COMMAND = createCommand();
|
|
2022
|
-
const BLUR_COMMAND = createCommand();
|
|
2023
|
-
const KEY_MODIFIER_COMMAND = createCommand();
|
|
2024
|
-
|
|
2025
2034
|
/**
|
|
2026
2035
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2027
2036
|
*
|
|
@@ -2038,6 +2047,7 @@ if (CAN_USE_BEFORE_INPUT) {
|
|
|
2038
2047
|
}
|
|
2039
2048
|
|
|
2040
2049
|
let lastKeyDownTimeStamp = 0;
|
|
2050
|
+
let lastKeyCode = 0;
|
|
2041
2051
|
let rootElementsRegistered = 0;
|
|
2042
2052
|
let isSelectionChangeFromDOMUpdate = false;
|
|
2043
2053
|
let isInsertLineBreak = false;
|
|
@@ -2179,6 +2189,10 @@ function $canRemoveText(anchorNode, focusNode) {
|
|
|
2179
2189
|
return anchorNode !== focusNode || $isElementNode(anchorNode) || $isElementNode(focusNode) || !$isTokenOrInert(anchorNode) || !$isTokenOrInert(focusNode);
|
|
2180
2190
|
}
|
|
2181
2191
|
|
|
2192
|
+
function isPossiblyAndroidKeyPress(timeStamp) {
|
|
2193
|
+
return lastKeyCode === 229 && timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY;
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2182
2196
|
function onBeforeInput(event, editor) {
|
|
2183
2197
|
const inputType = event.inputType; // We let the browser do its own thing for composition.
|
|
2184
2198
|
|
|
@@ -2195,7 +2209,9 @@ function onBeforeInput(event, editor) {
|
|
|
2195
2209
|
// during composition and see if the previous text contains
|
|
2196
2210
|
// part of the composed text to work out the actual text that
|
|
2197
2211
|
// we need to insert.
|
|
2198
|
-
const composedText = event.data;
|
|
2212
|
+
const composedText = event.data; // TODO: evaluate if this is Android only. It doesn't always seem
|
|
2213
|
+
// to have any real impact, so could probably be refactored or removed
|
|
2214
|
+
// for an alternative approach.
|
|
2199
2215
|
|
|
2200
2216
|
if (composedText) {
|
|
2201
2217
|
updateEditor(editor, () => {
|
|
@@ -2239,20 +2255,32 @@ function onBeforeInput(event, editor) {
|
|
|
2239
2255
|
}
|
|
2240
2256
|
|
|
2241
2257
|
$setSelection(prevSelection.clone());
|
|
2242
|
-
}
|
|
2258
|
+
}
|
|
2243
2259
|
|
|
2260
|
+
if ($isRangeSelection(selection)) {
|
|
2261
|
+
// Used for handling backspace in Android.
|
|
2262
|
+
if (isPossiblyAndroidKeyPress(event.timeStamp) && selection.anchor.key === selection.focus.key) {
|
|
2263
|
+
$setCompositionKey(null);
|
|
2264
|
+
lastKeyDownTimeStamp = 0; // Fixes an Android bug where selection flickers when backspacing
|
|
2244
2265
|
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2266
|
+
setTimeout(() => {
|
|
2267
|
+
updateEditor(editor, () => {
|
|
2268
|
+
$setCompositionKey(null);
|
|
2269
|
+
});
|
|
2270
|
+
}, ANDROID_COMPOSITION_LATENCY);
|
|
2249
2271
|
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2272
|
+
if ($isRangeSelection(selection)) {
|
|
2273
|
+
const anchorNode = selection.anchor.getNode();
|
|
2274
|
+
anchorNode.markDirty();
|
|
2275
|
+
selection.format = anchorNode.getFormat();
|
|
2276
|
+
}
|
|
2277
|
+
} else {
|
|
2278
|
+
event.preventDefault();
|
|
2279
|
+
dispatchCommand(editor, DELETE_CHARACTER_COMMAND, false);
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
return;
|
|
2283
|
+
}
|
|
2256
2284
|
}
|
|
2257
2285
|
|
|
2258
2286
|
if (!$isRangeSelection(selection)) {
|
|
@@ -2438,9 +2466,8 @@ function onInput(event, editor) {
|
|
|
2438
2466
|
updateEditor(editor, () => {
|
|
2439
2467
|
const selection = $getSelection();
|
|
2440
2468
|
const data = event.data;
|
|
2441
|
-
const possibleTextReplacement = event.inputType === 'insertText' && data != null && data.length > 1 && !doesContainGrapheme(data);
|
|
2442
2469
|
|
|
2443
|
-
if (data != null && $isRangeSelection(selection) &&
|
|
2470
|
+
if (data != null && $isRangeSelection(selection) && $shouldPreventDefaultAndInsertText(selection, data)) {
|
|
2444
2471
|
// Given we're over-riding the default behavior, we will need
|
|
2445
2472
|
// to ensure to disable composition before dispatching the
|
|
2446
2473
|
// insertText command for when changing the sequence for FF.
|
|
@@ -2449,24 +2476,7 @@ function onInput(event, editor) {
|
|
|
2449
2476
|
isFirefoxEndingComposition = false;
|
|
2450
2477
|
}
|
|
2451
2478
|
|
|
2452
|
-
dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
|
|
2453
|
-
|
|
2454
|
-
if (possibleTextReplacement) {
|
|
2455
|
-
// If the DOM selection offset is higher than the existing
|
|
2456
|
-
// offset, then restore the offset as it's likely correct
|
|
2457
|
-
// in the case of text replacements.
|
|
2458
|
-
const {
|
|
2459
|
-
anchorOffset
|
|
2460
|
-
} = window.getSelection();
|
|
2461
|
-
const anchor = selection.anchor;
|
|
2462
|
-
const focus = selection.focus;
|
|
2463
|
-
|
|
2464
|
-
if (anchorOffset > anchor.offset) {
|
|
2465
|
-
anchor.set(anchor.key, anchorOffset, anchor.type);
|
|
2466
|
-
focus.set(anchor.key, anchorOffset, anchor.type);
|
|
2467
|
-
}
|
|
2468
|
-
} // This ensures consistency on Android.
|
|
2469
|
-
|
|
2479
|
+
dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data); // This ensures consistency on Android.
|
|
2470
2480
|
|
|
2471
2481
|
if (!IS_SAFARI && !IS_IOS && editor.isComposing()) {
|
|
2472
2482
|
lastKeyDownTimeStamp = 0;
|
|
@@ -2565,6 +2575,7 @@ function onCompositionEnd(event, editor) {
|
|
|
2565
2575
|
|
|
2566
2576
|
function onKeyDown(event, editor) {
|
|
2567
2577
|
lastKeyDownTimeStamp = event.timeStamp;
|
|
2578
|
+
lastKeyCode = event.keyCode;
|
|
2568
2579
|
|
|
2569
2580
|
if (editor.isComposing()) {
|
|
2570
2581
|
return;
|
|
@@ -2647,12 +2658,18 @@ function onKeyDown(event, editor) {
|
|
|
2647
2658
|
} else if (isRedo(keyCode, shiftKey, metaKey, ctrlKey)) {
|
|
2648
2659
|
event.preventDefault();
|
|
2649
2660
|
dispatchCommand(editor, REDO_COMMAND, undefined);
|
|
2650
|
-
} else
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2661
|
+
} else {
|
|
2662
|
+
const prevSelection = editor._editorState._selection;
|
|
2663
|
+
|
|
2664
|
+
if ($isNodeSelection(prevSelection)) {
|
|
2665
|
+
if (isCopy(keyCode, shiftKey, metaKey, ctrlKey)) {
|
|
2666
|
+
event.preventDefault();
|
|
2667
|
+
dispatchCommand(editor, COPY_COMMAND, event);
|
|
2668
|
+
} else if (isCut(keyCode, shiftKey, metaKey, ctrlKey)) {
|
|
2669
|
+
event.preventDefault();
|
|
2670
|
+
dispatchCommand(editor, CUT_COMMAND, event);
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2656
2673
|
}
|
|
2657
2674
|
|
|
2658
2675
|
if (isModifier(ctrlKey, shiftKey, altKey, metaKey)) {
|
|
@@ -2824,7 +2841,6 @@ function markCollapsedSelectionFormat(format, offset, key, timeStamp) {
|
|
|
2824
2841
|
* LICENSE file in the root directory of this source tree.
|
|
2825
2842
|
*
|
|
2826
2843
|
*/
|
|
2827
|
-
|
|
2828
2844
|
class Point {
|
|
2829
2845
|
constructor(key, offset, type) {
|
|
2830
2846
|
this._selection = null;
|
|
@@ -3461,6 +3477,7 @@ class RangeSelection {
|
|
|
3461
3477
|
|
|
3462
3478
|
if (!$isTextNode(nextSibling) || $isTokenOrInertOrSegmented(nextSibling)) {
|
|
3463
3479
|
nextSibling = $createTextNode();
|
|
3480
|
+
nextSibling.setFormat(format);
|
|
3464
3481
|
|
|
3465
3482
|
if (!firstNodeParent.canInsertTextAfter()) {
|
|
3466
3483
|
firstNodeParent.insertAfter(nextSibling);
|
|
@@ -3481,6 +3498,7 @@ class RangeSelection {
|
|
|
3481
3498
|
|
|
3482
3499
|
if (!$isTextNode(prevSibling) || $isTokenOrInertOrSegmented(prevSibling)) {
|
|
3483
3500
|
prevSibling = $createTextNode();
|
|
3501
|
+
prevSibling.setFormat(format);
|
|
3484
3502
|
|
|
3485
3503
|
if (!firstNodeParent.canInsertTextBefore()) {
|
|
3486
3504
|
firstNodeParent.insertBefore(prevSibling);
|
|
@@ -3498,6 +3516,7 @@ class RangeSelection {
|
|
|
3498
3516
|
}
|
|
3499
3517
|
} else if (firstNode.isSegmented() && startOffset !== firstNodeTextLength) {
|
|
3500
3518
|
const textNode = $createTextNode(firstNode.getTextContent());
|
|
3519
|
+
textNode.setFormat(format);
|
|
3501
3520
|
firstNode.replace(textNode);
|
|
3502
3521
|
firstNode = textNode;
|
|
3503
3522
|
} else if (!this.isCollapsed() && text !== '') {
|
|
@@ -3555,10 +3574,14 @@ class RangeSelection {
|
|
|
3555
3574
|
|
|
3556
3575
|
if (firstNode.getTextContent() === '') {
|
|
3557
3576
|
firstNode.remove();
|
|
3558
|
-
} else if (
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3577
|
+
} else if (this.anchor.type === 'text') {
|
|
3578
|
+
if (firstNode.isComposing()) {
|
|
3579
|
+
// When composing, we need to adjust the anchor offset so that
|
|
3580
|
+
// we correctly replace that right range.
|
|
3581
|
+
this.anchor.offset -= text.length;
|
|
3582
|
+
} else {
|
|
3583
|
+
this.format = firstNodeFormat;
|
|
3584
|
+
}
|
|
3562
3585
|
}
|
|
3563
3586
|
} else {
|
|
3564
3587
|
const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]); // We have to get the parent elements before the next section,
|
|
@@ -4757,15 +4780,15 @@ function internalMakeRangeSelection(anchorKey, anchorOffset, focusKey, focusOffs
|
|
|
4757
4780
|
editorState._selection = selection;
|
|
4758
4781
|
return selection;
|
|
4759
4782
|
}
|
|
4760
|
-
function $
|
|
4783
|
+
function $createRangeSelection() {
|
|
4761
4784
|
const anchor = $createPoint('root', 0, 'element');
|
|
4762
4785
|
const focus = $createPoint('root', 0, 'element');
|
|
4763
4786
|
return new RangeSelection(anchor, focus, 0);
|
|
4764
4787
|
}
|
|
4765
|
-
function $
|
|
4788
|
+
function $createNodeSelection() {
|
|
4766
4789
|
return new NodeSelection(new Set());
|
|
4767
4790
|
}
|
|
4768
|
-
function $
|
|
4791
|
+
function $createGridSelection() {
|
|
4769
4792
|
const anchor = $createPoint('root', 0, 'element');
|
|
4770
4793
|
const focus = $createPoint('root', 0, 'element');
|
|
4771
4794
|
return new GridSelection('root', anchor, focus);
|
|
@@ -5359,7 +5382,7 @@ function parseEditorState(serializedEditorState, editor, updateFn) {
|
|
|
5359
5382
|
} // Make the editorState immutable
|
|
5360
5383
|
|
|
5361
5384
|
|
|
5362
|
-
editorState._readOnly = true;
|
|
5385
|
+
editorState._readOnly = true;
|
|
5363
5386
|
|
|
5364
5387
|
{
|
|
5365
5388
|
handleDEVOnlyPendingUpdateGuarantees(editorState);
|
|
@@ -5464,6 +5487,9 @@ function commitPendingUpdates(editor) {
|
|
|
5464
5487
|
isAttemptingToRecoverFromReconcilerError = true;
|
|
5465
5488
|
commitPendingUpdates(editor);
|
|
5466
5489
|
isAttemptingToRecoverFromReconcilerError = false;
|
|
5490
|
+
} else {
|
|
5491
|
+
// To avoid a possible situation of infinite loops, lets throw
|
|
5492
|
+
throw error;
|
|
5467
5493
|
}
|
|
5468
5494
|
|
|
5469
5495
|
return;
|
|
@@ -5480,7 +5506,7 @@ function commitPendingUpdates(editor) {
|
|
|
5480
5506
|
}
|
|
5481
5507
|
}
|
|
5482
5508
|
|
|
5483
|
-
pendingEditorState._readOnly = true;
|
|
5509
|
+
pendingEditorState._readOnly = true;
|
|
5484
5510
|
|
|
5485
5511
|
{
|
|
5486
5512
|
handleDEVOnlyPendingUpdateGuarantees(pendingEditorState);
|
|
@@ -5821,8 +5847,17 @@ function updateEditor(editor, updateFn, options) {
|
|
|
5821
5847
|
beginUpdate(editor, updateFn, options);
|
|
5822
5848
|
}
|
|
5823
5849
|
}
|
|
5850
|
+
function internalGetActiveEditor() {
|
|
5851
|
+
return activeEditor;
|
|
5852
|
+
}
|
|
5824
5853
|
|
|
5825
|
-
|
|
5854
|
+
/**
|
|
5855
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
5856
|
+
*
|
|
5857
|
+
* This source code is licensed under the MIT license found in the
|
|
5858
|
+
* LICENSE file in the root directory of this source tree.
|
|
5859
|
+
*
|
|
5860
|
+
*/
|
|
5826
5861
|
function removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
|
|
5827
5862
|
errorOnReadOnly();
|
|
5828
5863
|
const key = nodeToRemove.__key;
|
|
@@ -5889,6 +5924,7 @@ function $getNodeByKeyOrThrow(key) {
|
|
|
5889
5924
|
return node;
|
|
5890
5925
|
}
|
|
5891
5926
|
class LexicalNode {
|
|
5927
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5892
5928
|
// Flow doesn't support abstract classes unfortunately, so we can't _force_
|
|
5893
5929
|
// subclasses of Node to implement statics. All subclasses of Node should have
|
|
5894
5930
|
// a static getType and clone method though. We define getType and clone here so we can call it
|
|
@@ -5910,7 +5946,7 @@ class LexicalNode {
|
|
|
5910
5946
|
// @ts-expect-error
|
|
5911
5947
|
this.__type = this.constructor.getType();
|
|
5912
5948
|
this.__parent = null;
|
|
5913
|
-
$setNodeKey(this, key);
|
|
5949
|
+
$setNodeKey(this, key);
|
|
5914
5950
|
|
|
5915
5951
|
{
|
|
5916
5952
|
if (this.__type !== 'root') {
|
|
@@ -6379,52 +6415,11 @@ class LexicalNode {
|
|
|
6379
6415
|
|
|
6380
6416
|
exportDOM(editor) {
|
|
6381
6417
|
const element = this.createDOM(editor._config, editor);
|
|
6382
|
-
const serializedNode = this.exportJSON();
|
|
6383
|
-
element.setAttribute('data-lexical-node-type', this.__type);
|
|
6384
|
-
element.setAttribute('data-lexical-node-json', JSON.stringify(serializedNode));
|
|
6385
|
-
element.setAttribute('data-lexical-editor-key', editor._key);
|
|
6386
6418
|
return {
|
|
6387
6419
|
element
|
|
6388
6420
|
};
|
|
6389
6421
|
}
|
|
6390
6422
|
|
|
6391
|
-
static importDOM() {
|
|
6392
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6393
|
-
const proto = this.prototype.constructor;
|
|
6394
|
-
return {
|
|
6395
|
-
// Catch-all key because we don't know the nodeName of the element returned by exportDOM.
|
|
6396
|
-
'*': domNode => {
|
|
6397
|
-
if (!(domNode instanceof HTMLElement)) return null;
|
|
6398
|
-
const editorKey = domNode.getAttribute('data-lexical-editor-key');
|
|
6399
|
-
const nodeType = domNode.getAttribute('data-lexical-node-type');
|
|
6400
|
-
if (editorKey == null || nodeType == null) return null;
|
|
6401
|
-
const editor = getActiveEditor();
|
|
6402
|
-
|
|
6403
|
-
if (editorKey === editor.getKey() && nodeType === proto.getType()) {
|
|
6404
|
-
try {
|
|
6405
|
-
const json = domNode.getAttribute('data-lexical-node-json');
|
|
6406
|
-
|
|
6407
|
-
if (json != null) {
|
|
6408
|
-
const serializedNode = JSON.parse(json);
|
|
6409
|
-
const node = proto.importJSON(serializedNode);
|
|
6410
|
-
return {
|
|
6411
|
-
conversion: () => ({
|
|
6412
|
-
node
|
|
6413
|
-
}),
|
|
6414
|
-
// Max priority because of the 'data-lexical-node-type' attribute
|
|
6415
|
-
// matching the one on node klass guarantees a match.
|
|
6416
|
-
priority: 4
|
|
6417
|
-
}; // eslint-disable-next-line no-empty
|
|
6418
|
-
} // eslint-disable-next-line no-empty
|
|
6419
|
-
|
|
6420
|
-
} catch {}
|
|
6421
|
-
}
|
|
6422
|
-
|
|
6423
|
-
return null;
|
|
6424
|
-
}
|
|
6425
|
-
};
|
|
6426
|
-
}
|
|
6427
|
-
|
|
6428
6423
|
exportJSON() {
|
|
6429
6424
|
{
|
|
6430
6425
|
throw Error(`exportJSON: base method not extended`);
|
|
@@ -6643,7 +6638,7 @@ class DecoratorNode extends LexicalNode {
|
|
|
6643
6638
|
super(key);
|
|
6644
6639
|
}
|
|
6645
6640
|
|
|
6646
|
-
decorate(editor) {
|
|
6641
|
+
decorate(editor, config) {
|
|
6647
6642
|
{
|
|
6648
6643
|
throw Error(`decorate: base method not extended`);
|
|
6649
6644
|
}
|
|
@@ -7112,7 +7107,7 @@ class ElementNode extends LexicalNode {
|
|
|
7112
7107
|
return false;
|
|
7113
7108
|
}
|
|
7114
7109
|
|
|
7115
|
-
excludeFromCopy() {
|
|
7110
|
+
excludeFromCopy(destination) {
|
|
7116
7111
|
return false;
|
|
7117
7112
|
}
|
|
7118
7113
|
|
|
@@ -7555,7 +7550,9 @@ function setTextContent(nextText, dom, node) {
|
|
|
7555
7550
|
dom.textContent = text;
|
|
7556
7551
|
} else {
|
|
7557
7552
|
const nodeValue = firstChild.nodeValue;
|
|
7558
|
-
if (nodeValue !== text) if (isComposing) {
|
|
7553
|
+
if (nodeValue !== text) if (isComposing || IS_FIREFOX) {
|
|
7554
|
+
// We also use the diff composed text for general text in FF to avoid
|
|
7555
|
+
// the spellcheck red line from flickering.
|
|
7559
7556
|
const [index, remove, insert] = diffComposedText(nodeValue, text);
|
|
7560
7557
|
|
|
7561
7558
|
if (remove !== 0) {
|
|
@@ -8164,8 +8161,21 @@ function convertBringAttentionToElement(domNode) {
|
|
|
8164
8161
|
}
|
|
8165
8162
|
|
|
8166
8163
|
function convertTextDOMNode(domNode) {
|
|
8164
|
+
const {
|
|
8165
|
+
parentElement,
|
|
8166
|
+
textContent
|
|
8167
|
+
} = domNode;
|
|
8168
|
+
const textContentTrim = textContent.trim();
|
|
8169
|
+
const isPre = parentElement != null && parentElement.tagName.toLowerCase() === 'pre';
|
|
8170
|
+
|
|
8171
|
+
if (!isPre && textContentTrim.length === 0 && textContent.includes('\n')) {
|
|
8172
|
+
return {
|
|
8173
|
+
node: null
|
|
8174
|
+
};
|
|
8175
|
+
}
|
|
8176
|
+
|
|
8167
8177
|
return {
|
|
8168
|
-
node: $createTextNode(
|
|
8178
|
+
node: $createTextNode(textContent)
|
|
8169
8179
|
};
|
|
8170
8180
|
}
|
|
8171
8181
|
|
|
@@ -8378,10 +8388,11 @@ function initializeConversionCache(nodes) {
|
|
|
8378
8388
|
const conversionCache = new Map();
|
|
8379
8389
|
const handledConversions = new Set();
|
|
8380
8390
|
nodes.forEach(node => {
|
|
8381
|
-
// @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8382
|
-
|
|
8391
|
+
const importDOM = // @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8392
|
+
node.klass.importDOM != null ? // @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8393
|
+
node.klass.importDOM.bind(node.klass) : null;
|
|
8383
8394
|
|
|
8384
|
-
if (handledConversions.has(importDOM)) {
|
|
8395
|
+
if (importDOM == null || handledConversions.has(importDOM)) {
|
|
8385
8396
|
return;
|
|
8386
8397
|
}
|
|
8387
8398
|
|
|
@@ -8404,69 +8415,77 @@ function initializeConversionCache(nodes) {
|
|
|
8404
8415
|
return conversionCache;
|
|
8405
8416
|
}
|
|
8406
8417
|
|
|
8407
|
-
function createEditor(editorConfig
|
|
8408
|
-
const config = editorConfig;
|
|
8418
|
+
function createEditor(editorConfig) {
|
|
8419
|
+
const config = editorConfig || {};
|
|
8420
|
+
const activeEditor = internalGetActiveEditor();
|
|
8409
8421
|
const theme = config.theme || {};
|
|
8410
|
-
const parentEditor = config.parentEditor || null;
|
|
8422
|
+
const parentEditor = editorConfig === undefined ? activeEditor : config.parentEditor || null;
|
|
8411
8423
|
const disableEvents = config.disableEvents || false;
|
|
8412
8424
|
const editorState = createEmptyEditorState();
|
|
8425
|
+
const namespace = config.namespace || (parentEditor !== null ? parentEditor._config.namespace : createUID());
|
|
8413
8426
|
const initialEditorState = config.editorState;
|
|
8414
8427
|
const nodes = [RootNode, TextNode, LineBreakNode, ParagraphNode, ...(config.nodes || [])];
|
|
8415
8428
|
const onError = config.onError;
|
|
8416
8429
|
const isReadOnly = config.readOnly || false;
|
|
8417
|
-
|
|
8430
|
+
let registeredNodes;
|
|
8418
8431
|
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8432
|
+
if (editorConfig === undefined && activeEditor !== null) {
|
|
8433
|
+
registeredNodes = activeEditor._nodes;
|
|
8434
|
+
} else {
|
|
8435
|
+
registeredNodes = new Map();
|
|
8422
8436
|
|
|
8423
|
-
{
|
|
8424
|
-
const
|
|
8425
|
-
|
|
8426
|
-
if (name !== 'RootNode') {
|
|
8427
|
-
const proto = klass.prototype;
|
|
8428
|
-
['getType', 'clone'].forEach(method => {
|
|
8429
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
8430
|
-
if (!klass.hasOwnProperty(method)) {
|
|
8431
|
-
console.warn(`${name} must implement static "${method}" method`);
|
|
8432
|
-
}
|
|
8433
|
-
});
|
|
8437
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
8438
|
+
const klass = nodes[i]; // Ensure custom nodes implement required methods.
|
|
8434
8439
|
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
+
{
|
|
8441
|
+
const name = klass.name;
|
|
8442
|
+
|
|
8443
|
+
if (name !== 'RootNode') {
|
|
8444
|
+
const proto = klass.prototype;
|
|
8445
|
+
['getType', 'clone'].forEach(method => {
|
|
8446
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
8447
|
+
if (!klass.hasOwnProperty(method)) {
|
|
8448
|
+
console.warn(`${name} must implement static "${method}" method`);
|
|
8449
|
+
}
|
|
8450
|
+
});
|
|
8440
8451
|
|
|
8441
|
-
|
|
8442
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
8443
|
-
|
|
8444
|
-
console.warn(`${
|
|
8452
|
+
if ( // eslint-disable-next-line no-prototype-builtins
|
|
8453
|
+
!klass.hasOwnProperty('importDOM') && // eslint-disable-next-line no-prototype-builtins
|
|
8454
|
+
klass.hasOwnProperty('exportDOM')) {
|
|
8455
|
+
console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`);
|
|
8445
8456
|
}
|
|
8446
|
-
}
|
|
8447
8457
|
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8458
|
+
if (proto instanceof DecoratorNode) {
|
|
8459
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
8460
|
+
if (!proto.hasOwnProperty('decorate')) {
|
|
8461
|
+
console.warn(`${this.constructor.name} must implement "decorate" method`);
|
|
8462
|
+
}
|
|
8463
|
+
}
|
|
8452
8464
|
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8465
|
+
if ( // eslint-disable-next-line no-prototype-builtins
|
|
8466
|
+
!klass.hasOwnProperty('importJSON')) {
|
|
8467
|
+
console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`);
|
|
8468
|
+
}
|
|
8469
|
+
|
|
8470
|
+
if ( // eslint-disable-next-line no-prototype-builtins
|
|
8471
|
+
!proto.hasOwnProperty('exportJSON')) {
|
|
8472
|
+
console.warn(`${name} should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected`);
|
|
8473
|
+
}
|
|
8456
8474
|
}
|
|
8457
|
-
}
|
|
8458
|
-
} // @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8475
|
+
} // @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8459
8476
|
|
|
8460
8477
|
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8478
|
+
const type = klass.getType();
|
|
8479
|
+
registeredNodes.set(type, {
|
|
8480
|
+
klass,
|
|
8481
|
+
transforms: new Set()
|
|
8482
|
+
});
|
|
8483
|
+
}
|
|
8466
8484
|
}
|
|
8467
8485
|
|
|
8468
8486
|
const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, {
|
|
8469
8487
|
disableEvents,
|
|
8488
|
+
namespace,
|
|
8470
8489
|
theme
|
|
8471
8490
|
}, onError, initializeConversionCache(registeredNodes), isReadOnly);
|
|
8472
8491
|
|
|
@@ -8623,9 +8642,7 @@ class LexicalEditor {
|
|
|
8623
8642
|
};
|
|
8624
8643
|
}
|
|
8625
8644
|
|
|
8626
|
-
registerNodeTransform(
|
|
8627
|
-
// declaration below guarantees these are LexicalNodes.
|
|
8628
|
-
klass, listener) {
|
|
8645
|
+
registerNodeTransform(klass, listener) {
|
|
8629
8646
|
// @ts-expect-error TODO Replace Class utility type with InstanceType
|
|
8630
8647
|
const type = klass.getType();
|
|
8631
8648
|
|
|
@@ -8647,7 +8664,7 @@ class LexicalEditor {
|
|
|
8647
8664
|
|
|
8648
8665
|
hasNodes(nodes) {
|
|
8649
8666
|
for (let i = 0; i < nodes.length; i++) {
|
|
8650
|
-
const klass = nodes[i]; // @ts-expect-error
|
|
8667
|
+
const klass = nodes[i]; // @ts-expect-error
|
|
8651
8668
|
|
|
8652
8669
|
const type = klass.getType();
|
|
8653
8670
|
|
|
@@ -8816,7 +8833,7 @@ class LexicalEditor {
|
|
|
8816
8833
|
|
|
8817
8834
|
toJSON() {
|
|
8818
8835
|
return {
|
|
8819
|
-
editorState: this._editorState
|
|
8836
|
+
editorState: this._editorState.toJSON()
|
|
8820
8837
|
};
|
|
8821
8838
|
}
|
|
8822
8839
|
|
|
@@ -8829,7 +8846,7 @@ class LexicalEditor {
|
|
|
8829
8846
|
* LICENSE file in the root directory of this source tree.
|
|
8830
8847
|
*
|
|
8831
8848
|
*/
|
|
8832
|
-
const VERSION = '0.3.
|
|
8849
|
+
const VERSION = '0.3.4';
|
|
8833
8850
|
|
|
8834
8851
|
/**
|
|
8835
8852
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -8879,11 +8896,11 @@ function $isGridRowNode(node) {
|
|
|
8879
8896
|
return node instanceof GridRowNode;
|
|
8880
8897
|
}
|
|
8881
8898
|
|
|
8882
|
-
exports.$createGridSelection = $
|
|
8899
|
+
exports.$createGridSelection = $createGridSelection;
|
|
8883
8900
|
exports.$createLineBreakNode = $createLineBreakNode;
|
|
8884
|
-
exports.$createNodeSelection = $
|
|
8901
|
+
exports.$createNodeSelection = $createNodeSelection;
|
|
8885
8902
|
exports.$createParagraphNode = $createParagraphNode;
|
|
8886
|
-
exports.$createRangeSelection = $
|
|
8903
|
+
exports.$createRangeSelection = $createRangeSelection;
|
|
8887
8904
|
exports.$createTextNode = $createTextNode;
|
|
8888
8905
|
exports.$getDecoratorNode = $getDecoratorNode;
|
|
8889
8906
|
exports.$getNearestNodeFromDOMNode = $getNearestNodeFromDOMNode;
|