@lexical/react 0.1.9 → 0.1.12
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 +5 -44
- package/DEPRECATED_useLexical.prod.js +1 -2
- package/DEPRECATED_useLexicalAutoFormatter.dev.js +87 -41
- package/DEPRECATED_useLexicalAutoFormatter.prod.js +20 -18
- package/DEPRECATED_useLexicalCharacterLimit.dev.js +22 -19
- package/DEPRECATED_useLexicalCharacterLimit.prod.js +8 -8
- package/DEPRECATED_useLexicalEditor.dev.js +1 -25
- package/DEPRECATED_useLexicalEditor.prod.js +1 -1
- package/DEPRECATED_useLexicalHistory.dev.js +1 -1
- package/DEPRECATED_useLexicalHistory.prod.js +2 -2
- package/DEPRECATED_useLexicalList.dev.js +6 -0
- package/DEPRECATED_useLexicalList.prod.js +1 -1
- package/DEPRECATED_useLexicalPlainText.dev.js +81 -89
- package/DEPRECATED_useLexicalPlainText.prod.js +15 -16
- package/DEPRECATED_useLexicalRichText.dev.js +98 -592
- package/DEPRECATED_useLexicalRichText.prod.js +17 -29
- package/LexicalAutoFormatterPlugin.d.ts +9 -0
- package/LexicalAutoFormatterPlugin.dev.js +87 -41
- package/LexicalAutoFormatterPlugin.js.flow +10 -0
- package/LexicalAutoFormatterPlugin.prod.js +21 -19
- package/LexicalAutoLinkPlugin.d.ts +20 -0
- package/LexicalAutoLinkPlugin.js.flow +23 -0
- package/LexicalCharacterLimitPlugin.d.ts +11 -0
- package/LexicalCharacterLimitPlugin.dev.js +22 -19
- package/LexicalCharacterLimitPlugin.js.flow +12 -0
- package/LexicalCharacterLimitPlugin.prod.js +9 -8
- package/LexicalClearEditorPlugin.d.ts +14 -0
- package/LexicalClearEditorPlugin.dev.js +73 -0
- package/LexicalClearEditorPlugin.js +9 -0
- package/LexicalClearEditorPlugin.js.flow +14 -0
- package/LexicalClearEditorPlugin.prod.js +8 -0
- package/LexicalCollaborationPlugin.d.ts +49 -0
- package/LexicalCollaborationPlugin.dev.js +21 -11
- package/LexicalCollaborationPlugin.js.flow +55 -0
- package/LexicalCollaborationPlugin.prod.js +7 -7
- package/LexicalComposer.d.ts +22 -0
- package/LexicalComposer.dev.js +29 -5
- package/LexicalComposer.js.flow +24 -0
- package/LexicalComposer.prod.js +3 -3
- package/LexicalComposerContext.d.ts +24 -0
- package/LexicalComposerContext.js.flow +27 -0
- package/LexicalContentEditable.d.ts +32 -0
- package/LexicalContentEditable.dev.js +35 -8
- package/LexicalContentEditable.js.flow +35 -0
- package/LexicalContentEditable.prod.js +3 -3
- package/LexicalHashtagPlugin.d.ts +9 -0
- package/LexicalHashtagPlugin.js.flow +10 -0
- package/LexicalHistoryPlugin.d.ts +29 -0
- package/LexicalHistoryPlugin.dev.js +1 -1
- package/LexicalHistoryPlugin.js.flow +34 -0
- package/LexicalHistoryPlugin.prod.js +2 -2
- package/LexicalHorizontalRuleNode.d.ts +23 -0
- package/LexicalHorizontalRuleNode.js.flow +25 -0
- package/LexicalLinkPlugin.d.ts +9 -0
- package/LexicalLinkPlugin.js.flow +10 -0
- package/LexicalListPlugin.d.ts +9 -0
- package/LexicalListPlugin.dev.js +6 -0
- package/LexicalListPlugin.js.flow +10 -0
- package/LexicalListPlugin.prod.js +2 -2
- package/LexicalNestedComposer.d.ts +20 -0
- package/LexicalNestedComposer.js.flow +21 -0
- package/LexicalOnChangePlugin.d.ts +12 -0
- package/LexicalOnChangePlugin.js.flow +14 -0
- package/LexicalPlainTextPlugin.d.ts +15 -0
- package/LexicalPlainTextPlugin.dev.js +77 -84
- package/LexicalPlainTextPlugin.js.flow +18 -0
- package/LexicalPlainTextPlugin.prod.js +12 -12
- package/LexicalRichTextPlugin.d.ts +15 -0
- package/LexicalRichTextPlugin.dev.js +93 -586
- package/LexicalRichTextPlugin.js.flow +18 -0
- package/LexicalRichTextPlugin.prod.js +13 -25
- package/LexicalTablePlugin.d.ts +9 -0
- package/LexicalTablePlugin.dev.js +23 -1
- package/LexicalTablePlugin.js.flow +10 -0
- package/LexicalTablePlugin.prod.js +4 -3
- package/LexicalTreeView.d.ts +17 -0
- package/LexicalTreeView.dev.js +10 -2
- package/LexicalTreeView.js.flow +19 -0
- package/LexicalTreeView.prod.js +9 -8
- package/README.md +0 -1
- package/package.json +6 -5
- package/useLexicalDecoratorMap.d.ts +14 -0
- package/useLexicalDecoratorMap.js.flow +16 -0
- package/useLexicalIsTextContentEmpty.d.ts +13 -0
- package/useLexicalIsTextContentEmpty.js.flow +15 -0
- package/useLexicalNodeSelection.d.ts +12 -0
- package/useLexicalNodeSelection.dev.js +70 -0
- package/useLexicalNodeSelection.js +9 -0
- package/useLexicalNodeSelection.js.flow +14 -0
- package/useLexicalNodeSelection.prod.js +8 -0
- package/withSubscriptions.d.ts +12 -0
- package/withSubscriptions.js.flow +13 -0
- package/LexicalBootstrapPlugin.dev.js +0 -122
- package/LexicalBootstrapPlugin.js +0 -9
- package/LexicalBootstrapPlugin.prod.js +0 -8
|
@@ -10,10 +10,7 @@ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
|
10
10
|
var React = require('react');
|
|
11
11
|
var lexical = require('lexical');
|
|
12
12
|
var reactDom = require('react-dom');
|
|
13
|
-
var
|
|
14
|
-
var CodeNode = require('lexical/CodeNode');
|
|
15
|
-
var HeadingNode = require('lexical/HeadingNode');
|
|
16
|
-
var LinkNode = require('lexical/LinkNode');
|
|
13
|
+
var clipboard = require('@lexical/clipboard');
|
|
17
14
|
|
|
18
15
|
/**
|
|
19
16
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -173,182 +170,6 @@ function useDecorators(editor) {
|
|
|
173
170
|
*
|
|
174
171
|
*/
|
|
175
172
|
|
|
176
|
-
function $cloneWithProperties(node) {
|
|
177
|
-
const latest = node.getLatest();
|
|
178
|
-
const constructor = latest.constructor;
|
|
179
|
-
const clone = constructor.clone(latest);
|
|
180
|
-
clone.__parent = latest.__parent;
|
|
181
|
-
|
|
182
|
-
if (lexical.$isElementNode(latest) && lexical.$isElementNode(clone)) {
|
|
183
|
-
clone.__children = Array.from(latest.__children);
|
|
184
|
-
clone.__format = latest.__format;
|
|
185
|
-
clone.__indent = latest.__indent;
|
|
186
|
-
clone.__dir = latest.__dir;
|
|
187
|
-
} else if (lexical.$isTextNode(latest) && lexical.$isTextNode(clone)) {
|
|
188
|
-
clone.__format = latest.__format;
|
|
189
|
-
clone.__style = latest.__style;
|
|
190
|
-
clone.__mode = latest.__mode;
|
|
191
|
-
clone.__detail = latest.__detail;
|
|
192
|
-
} else if (lexical.$isDecoratorNode(latest) && lexical.$isDecoratorNode(clone)) {
|
|
193
|
-
clone.__state = latest.__state;
|
|
194
|
-
} // $FlowFixMe
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return clone;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function $getIndexFromPossibleClone(node, parent, nodeMap) {
|
|
201
|
-
const parentClone = nodeMap.get(parent.getKey());
|
|
202
|
-
|
|
203
|
-
if (lexical.$isElementNode(parentClone)) {
|
|
204
|
-
return parentClone.__children.indexOf(node.getKey());
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return node.getIndexWithinParent();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function $getParentAvoidingExcludedElements(node) {
|
|
211
|
-
let parent = node.getParent();
|
|
212
|
-
|
|
213
|
-
while (parent !== null && parent.excludeFromCopy()) {
|
|
214
|
-
parent = parent.getParent();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return parent;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function $copyLeafNodeBranchToRoot(leaf, startingOffset, isLeftSide, range, nodeMap) {
|
|
221
|
-
let node = leaf;
|
|
222
|
-
let offset = startingOffset;
|
|
223
|
-
|
|
224
|
-
while (node !== null) {
|
|
225
|
-
const parent = $getParentAvoidingExcludedElements(node);
|
|
226
|
-
|
|
227
|
-
if (parent === null) {
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (!lexical.$isElementNode(node) || !node.excludeFromCopy()) {
|
|
232
|
-
const key = node.getKey();
|
|
233
|
-
let clone = nodeMap.get(key);
|
|
234
|
-
const needsClone = clone === undefined;
|
|
235
|
-
|
|
236
|
-
if (needsClone) {
|
|
237
|
-
clone = $cloneWithProperties(node);
|
|
238
|
-
nodeMap.set(key, clone);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (lexical.$isTextNode(clone) && !clone.isSegmented() && !clone.isToken()) {
|
|
242
|
-
clone.__text = clone.__text.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset);
|
|
243
|
-
} else if (lexical.$isElementNode(clone)) {
|
|
244
|
-
clone.__children = clone.__children.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset + 1);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (lexical.$isRootNode(parent)) {
|
|
248
|
-
if (needsClone) {
|
|
249
|
-
// We only want to collect a range of top level nodes.
|
|
250
|
-
// So if the parent is the root, we know this is a top level.
|
|
251
|
-
range.push(key);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
break;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
offset = $getIndexFromPossibleClone(node, parent, nodeMap);
|
|
259
|
-
node = parent;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function $cloneContents(selection) {
|
|
264
|
-
const anchor = selection.anchor;
|
|
265
|
-
const focus = selection.focus;
|
|
266
|
-
const anchorOffset = anchor.getCharacterOffset();
|
|
267
|
-
const focusOffset = focus.getCharacterOffset();
|
|
268
|
-
const anchorNode = anchor.getNode();
|
|
269
|
-
const focusNode = focus.getNode();
|
|
270
|
-
const anchorNodeParent = anchorNode.getParentOrThrow(); // Handle a single text node extraction
|
|
271
|
-
|
|
272
|
-
if (anchorNode === focusNode && lexical.$isTextNode(anchorNode) && (anchorNodeParent.canBeEmpty() || anchorNodeParent.getChildrenSize() > 1)) {
|
|
273
|
-
const clonedFirstNode = $cloneWithProperties(anchorNode);
|
|
274
|
-
const isBefore = focusOffset > anchorOffset;
|
|
275
|
-
const startOffset = isBefore ? anchorOffset : focusOffset;
|
|
276
|
-
const endOffset = isBefore ? focusOffset : anchorOffset;
|
|
277
|
-
clonedFirstNode.__text = clonedFirstNode.__text.slice(startOffset, endOffset);
|
|
278
|
-
const key = clonedFirstNode.getKey();
|
|
279
|
-
return {
|
|
280
|
-
nodeMap: [[key, clonedFirstNode]],
|
|
281
|
-
range: [key]
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const nodes = selection.getNodes();
|
|
286
|
-
|
|
287
|
-
if (nodes.length === 0) {
|
|
288
|
-
return {
|
|
289
|
-
nodeMap: [],
|
|
290
|
-
range: []
|
|
291
|
-
};
|
|
292
|
-
} // Check if we can use the parent of the nodes, if the
|
|
293
|
-
// parent can't be empty, then it's important that we
|
|
294
|
-
// also copy that element node along with its children.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
let nodesLength = nodes.length;
|
|
298
|
-
const firstNode = nodes[0];
|
|
299
|
-
const firstNodeParent = firstNode.getParent();
|
|
300
|
-
|
|
301
|
-
if (firstNodeParent !== null && (!firstNodeParent.canBeEmpty() || lexical.$isRootNode(firstNodeParent))) {
|
|
302
|
-
const parentChildren = firstNodeParent.__children;
|
|
303
|
-
const parentChildrenLength = parentChildren.length;
|
|
304
|
-
|
|
305
|
-
if (parentChildrenLength === nodesLength) {
|
|
306
|
-
let areTheSame = true;
|
|
307
|
-
|
|
308
|
-
for (let i = 0; i < parentChildren.length; i++) {
|
|
309
|
-
if (parentChildren[i] !== nodes[i].__key) {
|
|
310
|
-
areTheSame = false;
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (areTheSame) {
|
|
316
|
-
nodesLength++;
|
|
317
|
-
nodes.push(firstNodeParent);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
const lastNode = nodes[nodesLength - 1];
|
|
323
|
-
const isBefore = anchor.isBefore(focus);
|
|
324
|
-
const nodeMap = new Map();
|
|
325
|
-
const range = []; // Do first node to root
|
|
326
|
-
|
|
327
|
-
$copyLeafNodeBranchToRoot(firstNode, isBefore ? anchorOffset : focusOffset, true, range, nodeMap); // Copy all nodes between
|
|
328
|
-
|
|
329
|
-
for (let i = 0; i < nodesLength; i++) {
|
|
330
|
-
const node = nodes[i];
|
|
331
|
-
const key = node.getKey();
|
|
332
|
-
|
|
333
|
-
if (!nodeMap.has(key) && (!lexical.$isElementNode(node) || !node.excludeFromCopy())) {
|
|
334
|
-
const clone = $cloneWithProperties(node);
|
|
335
|
-
|
|
336
|
-
if (lexical.$isRootNode(node.getParent())) {
|
|
337
|
-
range.push(node.getKey());
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
nodeMap.set(key, clone);
|
|
341
|
-
}
|
|
342
|
-
} // Do last node to root
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
$copyLeafNodeBranchToRoot(lastNode, isBefore ? focusOffset : anchorOffset, false, range, nodeMap);
|
|
346
|
-
return {
|
|
347
|
-
nodeMap: Array.from(nodeMap.entries()),
|
|
348
|
-
range
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
173
|
function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {
|
|
353
174
|
selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);
|
|
354
175
|
}
|
|
@@ -361,6 +182,10 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
|
|
|
361
182
|
const isRTL = $isParentElementRTL(selection);
|
|
362
183
|
$moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
|
|
363
184
|
}
|
|
185
|
+
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
186
|
+
const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
|
|
187
|
+
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
|
188
|
+
}
|
|
364
189
|
|
|
365
190
|
/**
|
|
366
191
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -370,45 +195,50 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
|
|
|
370
195
|
*
|
|
371
196
|
*
|
|
372
197
|
*/
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (parent !== null) {
|
|
379
|
-
if (isBackward && focusOffset === 0) {
|
|
380
|
-
offset = block.getIndexWithinParent();
|
|
381
|
-
block = parent;
|
|
382
|
-
} else if (!isBackward && focusOffset === block.getChildrenSize()) {
|
|
383
|
-
offset = block.getIndexWithinParent() + 1;
|
|
384
|
-
block = parent;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
198
|
+
function onCutForRichText(event, editor) {
|
|
199
|
+
onCopyForRichText(event, editor);
|
|
200
|
+
editor.update(() => {
|
|
201
|
+
const selection = lexical.$getSelection();
|
|
387
202
|
|
|
388
|
-
|
|
203
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
204
|
+
selection.removeText();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
389
207
|
}
|
|
208
|
+
function onCopyForRichText(event, editor) {
|
|
209
|
+
event.preventDefault();
|
|
210
|
+
editor.update(() => {
|
|
211
|
+
const clipboardData = event.clipboardData;
|
|
212
|
+
const selection = lexical.$getSelection();
|
|
390
213
|
|
|
391
|
-
|
|
392
|
-
|
|
214
|
+
if (selection !== null) {
|
|
215
|
+
if (clipboardData != null) {
|
|
216
|
+
const htmlString = clipboard.getHtmlContent(editor);
|
|
217
|
+
const lexicalString = clipboard.$getLexicalContent(editor);
|
|
393
218
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
} else {
|
|
398
|
-
const focusNode = focus.getNode();
|
|
219
|
+
if (htmlString !== null) {
|
|
220
|
+
clipboardData.setData('text/html', htmlString);
|
|
221
|
+
}
|
|
399
222
|
|
|
400
|
-
|
|
401
|
-
|
|
223
|
+
if (lexicalString !== null) {
|
|
224
|
+
clipboardData.setData('application/x-lexical-editor', lexicalString);
|
|
225
|
+
}
|
|
402
226
|
|
|
403
|
-
|
|
404
|
-
return resolveElement(focusNode.getParentOrThrow(), isBackward, focusNode.getIndexWithinParent() + (isBackward ? 0 : 1));
|
|
227
|
+
clipboardData.setData('text/plain', selection.getTextContent());
|
|
405
228
|
}
|
|
406
|
-
|
|
407
|
-
return possibleNode;
|
|
408
229
|
}
|
|
409
|
-
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function onPasteForRichText(event, editor) {
|
|
233
|
+
event.preventDefault();
|
|
234
|
+
editor.update(() => {
|
|
235
|
+
const selection = lexical.$getSelection();
|
|
236
|
+
const clipboardData = event.clipboardData;
|
|
410
237
|
|
|
411
|
-
|
|
238
|
+
if (clipboardData != null && lexical.$isRangeSelection(selection)) {
|
|
239
|
+
clipboard.$insertDataTransferForRichText(clipboardData, selection, editor);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
412
242
|
}
|
|
413
243
|
|
|
414
244
|
/**
|
|
@@ -419,381 +249,52 @@ function getPossibleDecoratorNode(focus, isBackward) {
|
|
|
419
249
|
*
|
|
420
250
|
*
|
|
421
251
|
*/
|
|
422
|
-
|
|
423
|
-
const
|
|
424
|
-
|
|
252
|
+
// Convoluted logic to make this work with Flow. Order matters.
|
|
253
|
+
const options = {
|
|
254
|
+
tag: 'history-merge'
|
|
425
255
|
};
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
},
|
|
444
|
-
b: domNode => {
|
|
445
|
-
// $FlowFixMe[incompatible-type] domNode is a <b> since we matched it by nodeName
|
|
446
|
-
const b = domNode; // Google Docs wraps all copied HTML in a <b> with font-weight normal
|
|
447
|
-
|
|
448
|
-
const hasNormalFontWeight = b.style.fontWeight === 'normal';
|
|
449
|
-
return {
|
|
450
|
-
forChild: lexicalNode => {
|
|
451
|
-
if (lexical.$isTextNode(lexicalNode) && !hasNormalFontWeight) {
|
|
452
|
-
lexicalNode.toggleFormat('bold');
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
|
-
node: null
|
|
456
|
-
};
|
|
457
|
-
},
|
|
458
|
-
br: () => ({
|
|
459
|
-
node: lexical.$createLineBreakNode()
|
|
460
|
-
}),
|
|
461
|
-
div: domNode => {
|
|
462
|
-
// $FlowFixMe[incompatible-type] domNode is a <div> since we matched it by nodeName
|
|
463
|
-
const div = domNode;
|
|
464
|
-
return {
|
|
465
|
-
after: childLexicalNodes => {
|
|
466
|
-
const domParent = domNode.parentNode;
|
|
467
|
-
|
|
468
|
-
if (domParent != null && domNode !== domParent.lastChild) {
|
|
469
|
-
childLexicalNodes.push(lexical.$createLineBreakNode());
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return childLexicalNodes;
|
|
473
|
-
},
|
|
474
|
-
node: isCodeElement(div) ? CodeNode.$createCodeNode() : null
|
|
475
|
-
};
|
|
476
|
-
},
|
|
477
|
-
em: domNode => {
|
|
478
|
-
return {
|
|
479
|
-
forChild: lexicalNode => {
|
|
480
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
481
|
-
lexicalNode.toggleFormat('italic');
|
|
482
|
-
}
|
|
483
|
-
},
|
|
484
|
-
node: null
|
|
485
|
-
};
|
|
486
|
-
},
|
|
487
|
-
h1: () => ({
|
|
488
|
-
node: HeadingNode.$createHeadingNode('h1')
|
|
489
|
-
}),
|
|
490
|
-
h2: () => ({
|
|
491
|
-
node: HeadingNode.$createHeadingNode('h2')
|
|
492
|
-
}),
|
|
493
|
-
h3: () => ({
|
|
494
|
-
node: HeadingNode.$createHeadingNode('h3')
|
|
495
|
-
}),
|
|
496
|
-
h4: () => ({
|
|
497
|
-
node: HeadingNode.$createHeadingNode('h4')
|
|
498
|
-
}),
|
|
499
|
-
h5: () => ({
|
|
500
|
-
node: HeadingNode.$createHeadingNode('h5')
|
|
501
|
-
}),
|
|
502
|
-
i: domNode => {
|
|
503
|
-
return {
|
|
504
|
-
forChild: lexicalNode => {
|
|
505
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
506
|
-
lexicalNode.toggleFormat('italic');
|
|
507
|
-
}
|
|
508
|
-
},
|
|
509
|
-
node: null
|
|
510
|
-
};
|
|
511
|
-
},
|
|
512
|
-
li: () => ({
|
|
513
|
-
node: list.$createListItemNode()
|
|
514
|
-
}),
|
|
515
|
-
ol: () => ({
|
|
516
|
-
node: list.$createListNode('ol')
|
|
517
|
-
}),
|
|
518
|
-
p: () => ({
|
|
519
|
-
node: lexical.$createParagraphNode()
|
|
520
|
-
}),
|
|
521
|
-
pre: domNode => ({
|
|
522
|
-
node: CodeNode.$createCodeNode()
|
|
523
|
-
}),
|
|
524
|
-
span: domNode => {
|
|
525
|
-
// $FlowFixMe[incompatible-type] domNode is a <span> since we matched it by nodeName
|
|
526
|
-
const span = domNode; // Google Docs uses span tags + font-weight for bold text
|
|
527
|
-
|
|
528
|
-
const hasBoldFontWeight = span.style.fontWeight === '700';
|
|
529
|
-
return {
|
|
530
|
-
forChild: lexicalNode => {
|
|
531
|
-
if (lexical.$isTextNode(lexicalNode) && hasBoldFontWeight) {
|
|
532
|
-
lexicalNode.toggleFormat('bold');
|
|
533
|
-
}
|
|
534
|
-
},
|
|
535
|
-
node: null
|
|
536
|
-
};
|
|
537
|
-
},
|
|
538
|
-
strong: domNode => {
|
|
539
|
-
return {
|
|
540
|
-
forChild: lexicalNode => {
|
|
541
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
542
|
-
lexicalNode.toggleFormat('bold');
|
|
543
|
-
}
|
|
544
|
-
},
|
|
545
|
-
node: null
|
|
546
|
-
};
|
|
547
|
-
},
|
|
548
|
-
table: domNode => {
|
|
549
|
-
// $FlowFixMe[incompatible-type] domNode is a <table> since we matched it by nodeName
|
|
550
|
-
const table = domNode;
|
|
551
|
-
const isGitHubCodeTable = table.classList.contains('js-file-line-container');
|
|
552
|
-
return {
|
|
553
|
-
node: isGitHubCodeTable ? CodeNode.$createCodeNode() : null
|
|
554
|
-
};
|
|
555
|
-
},
|
|
556
|
-
td: domNode => {
|
|
557
|
-
// $FlowFixMe[incompatible-type] domNode is a <table> since we matched it by nodeName
|
|
558
|
-
const cell = domNode;
|
|
559
|
-
const isGitHubCodeCell = cell.classList.contains('js-file-line');
|
|
560
|
-
return {
|
|
561
|
-
after: childLexicalNodes => {
|
|
562
|
-
if (isGitHubCodeCell && cell.parentNode && cell.parentNode.nextSibling) {
|
|
563
|
-
// Append newline between code lines
|
|
564
|
-
childLexicalNodes.push(lexical.$createLineBreakNode());
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
return childLexicalNodes;
|
|
568
|
-
},
|
|
569
|
-
node: null
|
|
570
|
-
};
|
|
571
|
-
},
|
|
572
|
-
u: domNode => {
|
|
573
|
-
return {
|
|
574
|
-
forChild: lexicalNode => {
|
|
575
|
-
if (lexical.$isTextNode(lexicalNode)) {
|
|
576
|
-
lexicalNode.toggleFormat('underline');
|
|
256
|
+
const setEditorOptions = options;
|
|
257
|
+
const updateOptions = options;
|
|
258
|
+
function initializeEditor(editor, initialEditorState) {
|
|
259
|
+
if (initialEditorState === null) {
|
|
260
|
+
return;
|
|
261
|
+
} else if (initialEditorState === undefined) {
|
|
262
|
+
editor.update(() => {
|
|
263
|
+
const root = lexical.$getRoot();
|
|
264
|
+
const firstChild = root.getFirstChild();
|
|
265
|
+
|
|
266
|
+
if (firstChild === null) {
|
|
267
|
+
const paragraph = lexical.$createParagraphNode();
|
|
268
|
+
root.append(paragraph);
|
|
269
|
+
const activeElement = document.activeElement;
|
|
270
|
+
|
|
271
|
+
if (lexical.$getSelection() !== null || activeElement !== null && activeElement === editor.getRootElement()) {
|
|
272
|
+
paragraph.select();
|
|
577
273
|
}
|
|
578
|
-
},
|
|
579
|
-
node: null
|
|
580
|
-
};
|
|
581
|
-
},
|
|
582
|
-
ul: () => ({
|
|
583
|
-
node: list.$createListNode('ul')
|
|
584
|
-
})
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
function $generateNodes(nodeRange) {
|
|
588
|
-
const {
|
|
589
|
-
range,
|
|
590
|
-
nodeMap
|
|
591
|
-
} = nodeRange;
|
|
592
|
-
const parsedNodeMap = new Map(nodeMap);
|
|
593
|
-
const nodes = [];
|
|
594
|
-
|
|
595
|
-
for (let i = 0; i < range.length; i++) {
|
|
596
|
-
const key = range[i];
|
|
597
|
-
const parsedNode = parsedNodeMap.get(key);
|
|
598
|
-
|
|
599
|
-
if (parsedNode !== undefined) {
|
|
600
|
-
const node = lexical.$createNodeFromParse(parsedNode, parsedNodeMap);
|
|
601
|
-
nodes.push(node);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
return nodes;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
function $createNodesFromDOM(node, conversionMap, editor, forChildMap = new Map()) {
|
|
609
|
-
let lexicalNodes = [];
|
|
610
|
-
let currentLexicalNode = null;
|
|
611
|
-
const nodeName = node.nodeName.toLowerCase();
|
|
612
|
-
const customHtmlTransforms = editor._config.htmlTransforms || {};
|
|
613
|
-
const transformFunction = customHtmlTransforms[nodeName] || conversionMap[nodeName];
|
|
614
|
-
const transformOutput = transformFunction ? transformFunction(node) : null;
|
|
615
|
-
let postTransform = null;
|
|
616
|
-
|
|
617
|
-
if (transformOutput !== null) {
|
|
618
|
-
postTransform = transformOutput.after;
|
|
619
|
-
currentLexicalNode = transformOutput.node;
|
|
620
|
-
|
|
621
|
-
if (currentLexicalNode !== null) {
|
|
622
|
-
lexicalNodes.push(currentLexicalNode);
|
|
623
|
-
const forChildFunctions = Array.from(forChildMap.values());
|
|
624
|
-
|
|
625
|
-
for (let i = 0; i < forChildFunctions.length; i++) {
|
|
626
|
-
forChildFunctions[i](currentLexicalNode);
|
|
627
274
|
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const children = node.childNodes;
|
|
638
|
-
let childLexicalNodes = [];
|
|
639
|
-
|
|
640
|
-
for (let i = 0; i < children.length; i++) {
|
|
641
|
-
childLexicalNodes.push(...$createNodesFromDOM(children[i], conversionMap, editor, forChildMap));
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
if (postTransform != null) {
|
|
645
|
-
childLexicalNodes = postTransform(childLexicalNodes);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
if (currentLexicalNode == null) {
|
|
649
|
-
// If it hasn't been converted to a LexicalNode, we hoist its children
|
|
650
|
-
// up to the same level as it.
|
|
651
|
-
lexicalNodes = lexicalNodes.concat(childLexicalNodes);
|
|
652
|
-
} else {
|
|
653
|
-
if (lexical.$isElementNode(currentLexicalNode)) {
|
|
654
|
-
// If the current node is a ElementNode after conversion,
|
|
655
|
-
// we can append all the children to it.
|
|
656
|
-
currentLexicalNode.append(...childLexicalNodes);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
return lexicalNodes;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
function $generateNodesFromDOM(dom, conversionMap, editor) {
|
|
664
|
-
let lexicalNodes = [];
|
|
665
|
-
const elements = dom.body ? Array.from(dom.body.childNodes) : [];
|
|
666
|
-
const elementsLength = elements.length;
|
|
667
|
-
|
|
668
|
-
for (let i = 0; i < elementsLength; i++) {
|
|
669
|
-
const lexicalNode = $createNodesFromDOM(elements[i], conversionMap, editor);
|
|
670
|
-
|
|
671
|
-
if (lexicalNode !== null) {
|
|
672
|
-
lexicalNodes = lexicalNodes.concat(lexicalNode);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
return lexicalNodes;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
function $insertDataTransferForRichText(dataTransfer, selection, editor) {
|
|
680
|
-
const lexicalNodesString = dataTransfer.getData('application/x-lexical-editor');
|
|
681
|
-
|
|
682
|
-
if (lexicalNodesString) {
|
|
683
|
-
const namespace = editor._config.namespace;
|
|
684
|
-
|
|
685
|
-
try {
|
|
686
|
-
const lexicalClipboardData = JSON.parse(lexicalNodesString);
|
|
687
|
-
|
|
688
|
-
if (lexicalClipboardData.namespace === namespace) {
|
|
689
|
-
const nodeRange = lexicalClipboardData.state;
|
|
690
|
-
const nodes = $generateNodes(nodeRange);
|
|
691
|
-
selection.insertNodes(nodes);
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
} catch (e) {// Malformed, missing nodes..
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
const textHtmlMimeType = 'text/html';
|
|
699
|
-
const htmlString = dataTransfer.getData(textHtmlMimeType);
|
|
700
|
-
|
|
701
|
-
if (htmlString) {
|
|
702
|
-
const parser = new DOMParser();
|
|
703
|
-
const dom = parser.parseFromString(htmlString, textHtmlMimeType);
|
|
704
|
-
const nodes = $generateNodesFromDOM(dom, DOM_NODE_NAME_TO_LEXICAL_NODE, editor); // Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
|
|
705
|
-
|
|
706
|
-
const topLevelBlocks = [];
|
|
707
|
-
let currentBlock = null;
|
|
708
|
-
|
|
709
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
710
|
-
const node = nodes[i];
|
|
711
|
-
|
|
712
|
-
if (!lexical.$isElementNode(node) || node.isInline()) {
|
|
713
|
-
if (currentBlock === null) {
|
|
714
|
-
currentBlock = lexical.$createParagraphNode();
|
|
715
|
-
topLevelBlocks.push(currentBlock);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
if (currentBlock !== null) {
|
|
719
|
-
currentBlock.append(node);
|
|
275
|
+
}, updateOptions);
|
|
276
|
+
} else if (initialEditorState !== null) {
|
|
277
|
+
switch (typeof initialEditorState) {
|
|
278
|
+
case 'string':
|
|
279
|
+
{
|
|
280
|
+
const parsedEditorState = editor.parseEditorState(initialEditorState);
|
|
281
|
+
editor.setEditorState(parsedEditorState, setEditorOptions);
|
|
282
|
+
break;
|
|
720
283
|
}
|
|
721
|
-
} else {
|
|
722
|
-
topLevelBlocks.push(node);
|
|
723
|
-
currentBlock = null;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
selection.insertNodes(topLevelBlocks);
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
$insertDataTransferForPlainText(dataTransfer, selection);
|
|
732
|
-
}
|
|
733
|
-
function $insertDataTransferForPlainText(dataTransfer, selection) {
|
|
734
|
-
const text = dataTransfer.getData('text/plain');
|
|
735
|
-
|
|
736
|
-
if (text != null) {
|
|
737
|
-
selection.insertRawText(text);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
741
|
-
const possibleNode = getPossibleDecoratorNode(selection.focus, isBackward);
|
|
742
|
-
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
|
743
|
-
}
|
|
744
|
-
function onPasteForRichText(event, editor) {
|
|
745
|
-
event.preventDefault();
|
|
746
|
-
editor.update(() => {
|
|
747
|
-
const selection = lexical.$getSelection();
|
|
748
|
-
const clipboardData = event.clipboardData;
|
|
749
|
-
|
|
750
|
-
if (clipboardData != null && selection !== null) {
|
|
751
|
-
$insertDataTransferForRichText(clipboardData, selection, editor);
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
function onCutForRichText(event, editor) {
|
|
756
|
-
onCopyForRichText(event, editor);
|
|
757
|
-
editor.update(() => {
|
|
758
|
-
const selection = lexical.$getSelection();
|
|
759
|
-
|
|
760
|
-
if (selection !== null) {
|
|
761
|
-
selection.removeText();
|
|
762
|
-
}
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
function onCopyForRichText(event, editor) {
|
|
766
|
-
event.preventDefault();
|
|
767
|
-
editor.update(() => {
|
|
768
|
-
const clipboardData = event.clipboardData;
|
|
769
|
-
const selection = lexical.$getSelection();
|
|
770
|
-
|
|
771
|
-
if (selection !== null) {
|
|
772
|
-
if (clipboardData != null) {
|
|
773
|
-
const domSelection = window.getSelection(); // If we haven't selected a range, then don't copy anything
|
|
774
284
|
|
|
775
|
-
|
|
776
|
-
|
|
285
|
+
case 'object':
|
|
286
|
+
{
|
|
287
|
+
editor.setEditorState(initialEditorState, setEditorOptions);
|
|
288
|
+
break;
|
|
777
289
|
}
|
|
778
290
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
const frag = range.cloneContents();
|
|
784
|
-
container.appendChild(frag);
|
|
785
|
-
clipboardData.setData('text/html', container.innerHTML);
|
|
291
|
+
case 'function':
|
|
292
|
+
{
|
|
293
|
+
editor.update(initialEditorState, updateOptions);
|
|
294
|
+
break;
|
|
786
295
|
}
|
|
787
|
-
|
|
788
|
-
clipboardData.setData('text/plain', selection.getTextContent());
|
|
789
|
-
const namespace = editor._config.namespace;
|
|
790
|
-
clipboardData.setData('application/x-lexical-editor', JSON.stringify({
|
|
791
|
-
namespace,
|
|
792
|
-
state: $cloneContents(selection)
|
|
793
|
-
}));
|
|
794
|
-
}
|
|
795
296
|
}
|
|
796
|
-
}
|
|
297
|
+
}
|
|
797
298
|
}
|
|
798
299
|
|
|
799
300
|
/**
|
|
@@ -835,7 +336,7 @@ function useLexicalDragonSupport(editor) {
|
|
|
835
336
|
editor.update(() => {
|
|
836
337
|
const selection = lexical.$getSelection();
|
|
837
338
|
|
|
838
|
-
if (selection
|
|
339
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
839
340
|
const anchor = selection.anchor;
|
|
840
341
|
let anchorNode = anchor.getNode();
|
|
841
342
|
let setSelStart = 0;
|
|
@@ -892,13 +393,17 @@ function useLexicalDragonSupport(editor) {
|
|
|
892
393
|
*
|
|
893
394
|
*
|
|
894
395
|
*/
|
|
895
|
-
|
|
896
|
-
function useRichTextSetup(editor) {
|
|
396
|
+
function useRichTextSetup(editor, initialEditorState) {
|
|
897
397
|
useLayoutEffect(() => {
|
|
898
398
|
const removeListener = editor.addListener('command', (type, payload) => {
|
|
899
399
|
const selection = lexical.$getSelection();
|
|
900
400
|
|
|
901
|
-
if (
|
|
401
|
+
if (type === 'click' && lexical.$isNodeSelection(selection)) {
|
|
402
|
+
selection.clear();
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
902
407
|
return false;
|
|
903
408
|
}
|
|
904
409
|
|
|
@@ -934,7 +439,7 @@ function useRichTextSetup(editor) {
|
|
|
934
439
|
const dataTransfer = eventOrText.dataTransfer;
|
|
935
440
|
|
|
936
441
|
if (dataTransfer != null) {
|
|
937
|
-
|
|
442
|
+
clipboard.$insertDataTransferForRichText(dataTransfer, selection, editor);
|
|
938
443
|
} else {
|
|
939
444
|
const data = eventOrText.data;
|
|
940
445
|
|
|
@@ -1127,9 +632,10 @@ function useRichTextSetup(editor) {
|
|
|
1127
632
|
}
|
|
1128
633
|
|
|
1129
634
|
return false;
|
|
1130
|
-
},
|
|
1131
|
-
editor
|
|
1132
|
-
return removeListener;
|
|
635
|
+
}, 0);
|
|
636
|
+
initializeEditor(editor, initialEditorState);
|
|
637
|
+
return removeListener; // We only do this for init
|
|
638
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1133
639
|
}, [editor]);
|
|
1134
640
|
useLexicalDragonSupport(editor);
|
|
1135
641
|
}
|
|
@@ -1144,11 +650,12 @@ function useRichTextSetup(editor) {
|
|
|
1144
650
|
*/
|
|
1145
651
|
function RichTextPlugin({
|
|
1146
652
|
contentEditable,
|
|
1147
|
-
placeholder
|
|
653
|
+
placeholder,
|
|
654
|
+
initialEditorState
|
|
1148
655
|
}) {
|
|
1149
656
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
1150
657
|
const showPlaceholder = useLexicalCanShowPlaceholder(editor);
|
|
1151
|
-
useRichTextSetup(editor);
|
|
658
|
+
useRichTextSetup(editor, initialEditorState);
|
|
1152
659
|
const decorators = useDecorators(editor);
|
|
1153
660
|
return /*#__PURE__*/React.createElement(React.Fragment, null, contentEditable, showPlaceholder && placeholder, decorators);
|
|
1154
661
|
}
|