@lexical/react 0.12.2 → 0.12.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.
Files changed (54) hide show
  1. package/LexicalAutoEmbedPlugin.d.ts +3 -2
  2. package/LexicalAutoEmbedPlugin.dev.js +4 -14
  3. package/LexicalAutoEmbedPlugin.prod.js +4 -3
  4. package/LexicalAutoFocusPlugin.dev.js +0 -1
  5. package/LexicalAutoLinkPlugin.dev.js +126 -73
  6. package/LexicalAutoLinkPlugin.prod.js +11 -7
  7. package/LexicalBlockWithAlignableContents.dev.js +0 -10
  8. package/LexicalCharacterLimitPlugin.dev.js +7 -46
  9. package/LexicalCheckListPlugin.dev.js +10 -48
  10. package/LexicalClearEditorPlugin.dev.js +1 -1
  11. package/LexicalClickableLinkPlugin.dev.js +2 -20
  12. package/LexicalCollaborationContext.dev.js +0 -3
  13. package/LexicalCollaborationPlugin.dev.js +8 -37
  14. package/LexicalComposer.d.ts +3 -7
  15. package/LexicalComposer.dev.js +9 -11
  16. package/LexicalComposer.js.flow +4 -4
  17. package/LexicalComposer.prod.js +2 -1
  18. package/LexicalComposerContext.dev.js +0 -6
  19. package/LexicalContentEditable.dev.js +1 -2
  20. package/LexicalContextMenuPlugin.d.ts +3 -2
  21. package/LexicalContextMenuPlugin.dev.js +28 -82
  22. package/LexicalContextMenuPlugin.prod.js +16 -15
  23. package/LexicalDecoratorBlockNode.dev.js +0 -6
  24. package/LexicalEditorRefPlugin.dev.js +0 -3
  25. package/LexicalHashtagPlugin.dev.js +73 -43
  26. package/LexicalHorizontalRuleNode.dev.js +0 -21
  27. package/LexicalHorizontalRulePlugin.dev.js +0 -4
  28. package/LexicalLinkPlugin.dev.js +4 -10
  29. package/LexicalListPlugin.dev.js +0 -2
  30. package/LexicalMarkdownShortcutPlugin.dev.js +2 -2
  31. package/LexicalNestedComposer.d.ts +2 -2
  32. package/LexicalNestedComposer.dev.js +18 -16
  33. package/LexicalNestedComposer.js.flow +7 -2
  34. package/LexicalNestedComposer.prod.js +4 -3
  35. package/LexicalNodeEventPlugin.dev.js +2 -6
  36. package/LexicalNodeMenuPlugin.d.ts +3 -2
  37. package/LexicalNodeMenuPlugin.dev.js +27 -83
  38. package/LexicalNodeMenuPlugin.prod.js +15 -15
  39. package/LexicalOnChangePlugin.dev.js +1 -1
  40. package/LexicalPlainTextPlugin.dev.js +8 -12
  41. package/LexicalRichTextPlugin.dev.js +8 -12
  42. package/LexicalTabIndentationPlugin.dev.js +7 -16
  43. package/LexicalTableOfContents.dev.js +5 -33
  44. package/LexicalTablePlugin.dev.js +11 -28
  45. package/LexicalTreeView.dev.js +14 -79
  46. package/LexicalTypeaheadMenuPlugin.d.ts +4 -3
  47. package/LexicalTypeaheadMenuPlugin.dev.js +39 -176
  48. package/LexicalTypeaheadMenuPlugin.prod.js +19 -20
  49. package/package.json +19 -19
  50. package/shared/LexicalMenu.d.ts +3 -2
  51. package/useLexicalEditable.dev.js +1 -5
  52. package/useLexicalIsTextContentEmpty.dev.js +1 -0
  53. package/useLexicalNodeSelection.dev.js +0 -7
  54. package/useLexicalSubscription.dev.js +1 -3
@@ -57,14 +57,12 @@ function TreeView({
57
57
  const generateTree = React.useCallback(editorState => {
58
58
  const treeText = generateContent(editor, commandsLog, showExportDOM);
59
59
  setContent(treeText);
60
-
61
60
  if (!timeTravelEnabled) {
62
61
  setTimeStampedEditorStates(currentEditorStates => [...currentEditorStates, [Date.now(), editorState]]);
63
62
  }
64
63
  }, [commandsLog, editor, timeTravelEnabled, showExportDOM]);
65
64
  React.useEffect(() => {
66
65
  const editorState = editor.getEditorState();
67
-
68
66
  if (!showLimited && editorState._nodeMap.size < 1000) {
69
67
  setContent(generateContent(editor, commandsLog, showExportDOM));
70
68
  }
@@ -76,12 +74,10 @@ function TreeView({
76
74
  if (!showLimited && editorState._nodeMap.size > 1000) {
77
75
  lastEditorStateRef.current = editorState;
78
76
  setIsLimited(true);
79
-
80
77
  if (!showLimited) {
81
78
  return;
82
79
  }
83
80
  }
84
-
85
81
  generateTree(editorState);
86
82
  }), editor.registerEditableListener(() => {
87
83
  const treeText = generateContent(editor, commandsLog, showExportDOM);
@@ -92,15 +88,12 @@ function TreeView({
92
88
  React.useEffect(() => {
93
89
  if (isPlaying) {
94
90
  let timeoutId;
95
-
96
91
  const play = () => {
97
92
  const currentIndex = playingIndexRef.current;
98
-
99
93
  if (currentIndex === totalEditorStates - 1) {
100
94
  setIsPlaying(false);
101
95
  return;
102
96
  }
103
-
104
97
  const currentTime = timeStampedEditorStates[currentIndex][0];
105
98
  const nextTime = timeStampedEditorStates[currentIndex + 1][0];
106
99
  const timeDiff = nextTime - currentTime;
@@ -108,16 +101,13 @@ function TreeView({
108
101
  playingIndexRef.current++;
109
102
  const index = playingIndexRef.current;
110
103
  const input = inputRef.current;
111
-
112
104
  if (input !== null) {
113
105
  input.value = String(index);
114
106
  }
115
-
116
107
  editor.setEditorState(timeStampedEditorStates[index][1]);
117
108
  play();
118
109
  }, timeDiff);
119
110
  };
120
-
121
111
  play();
122
112
  return () => {
123
113
  clearTimeout(timeoutId);
@@ -126,7 +116,6 @@ function TreeView({
126
116
  }, [timeStampedEditorStates, isPlaying, editor, totalEditorStates]);
127
117
  React.useEffect(() => {
128
118
  const element = treeElementRef.current;
129
-
130
119
  if (element !== null) {
131
120
  // @ts-ignore Internal field
132
121
  element.__lexicalEditor = editor;
@@ -150,7 +139,6 @@ function TreeView({
150
139
  onClick: () => {
151
140
  setShowLimited(true);
152
141
  const editorState = lastEditorStateRef.current;
153
-
154
142
  if (editorState !== null) {
155
143
  lastEditorStateRef.current = null;
156
144
  generateTree(editorState);
@@ -170,7 +158,6 @@ function TreeView({
170
158
  }, showExportDOM ? 'Tree' : 'Export DOM') : null, !timeTravelEnabled && (showLimited || !isLimited) && totalEditorStates > 2 && /*#__PURE__*/React.createElement("button", {
171
159
  onClick: () => {
172
160
  const rootElement = editor.getRootElement();
173
-
174
161
  if (rootElement !== null) {
175
162
  rootElement.contentEditable = 'false';
176
163
  playingIndexRef.current = totalEditorStates - 1;
@@ -189,7 +176,6 @@ function TreeView({
189
176
  if (playingIndexRef.current === totalEditorStates - 1) {
190
177
  playingIndexRef.current = 1;
191
178
  }
192
-
193
179
  setIsPlaying(!isPlaying);
194
180
  },
195
181
  type: "button"
@@ -199,7 +185,6 @@ function TreeView({
199
185
  onChange: event => {
200
186
  const editorStateIndex = Number(event.target.value);
201
187
  const timeStampedEditorState = timeStampedEditorStates[editorStateIndex];
202
-
203
188
  if (timeStampedEditorState) {
204
189
  playingIndexRef.current = editorStateIndex;
205
190
  editor.setEditorState(timeStampedEditorState[1]);
@@ -212,18 +197,15 @@ function TreeView({
212
197
  className: timeTravelPanelButtonClassName,
213
198
  onClick: () => {
214
199
  const rootElement = editor.getRootElement();
215
-
216
200
  if (rootElement !== null) {
217
201
  rootElement.contentEditable = 'true';
218
202
  const index = timeStampedEditorStates.length - 1;
219
203
  const timeStampedEditorState = timeStampedEditorStates[index];
220
204
  editor.setEditorState(timeStampedEditorState[1]);
221
205
  const input = inputRef.current;
222
-
223
206
  if (input !== null) {
224
207
  input.value = String(index);
225
208
  }
226
-
227
209
  setTimeTravelEnabled(false);
228
210
  setIsPlaying(false);
229
211
  }
@@ -231,12 +213,10 @@ function TreeView({
231
213
  type: "button"
232
214
  }, "Exit")));
233
215
  }
234
-
235
216
  function useLexicalCommandsLog(editor) {
236
217
  const [loggedCommands, setLoggedCommands] = React.useState([]);
237
218
  React.useEffect(() => {
238
219
  const unregisterCommandListeners = new Set();
239
-
240
220
  for (const [command] of editor._commands) {
241
221
  unregisterCommandListeners.add(editor.registerCommand(command, payload => {
242
222
  setLoggedCommands(state => {
@@ -245,22 +225,18 @@ function useLexicalCommandsLog(editor) {
245
225
  payload,
246
226
  type: command.type ? command.type : 'UNKNOWN'
247
227
  });
248
-
249
228
  if (newState.length > 10) {
250
229
  newState.shift();
251
230
  }
252
-
253
231
  return newState;
254
232
  });
255
233
  return false;
256
234
  }, lexical.COMMAND_PRIORITY_HIGH));
257
235
  }
258
-
259
236
  return () => unregisterCommandListeners.forEach(unregister => unregister());
260
237
  }, [editor]);
261
238
  return React.useMemo(() => loggedCommands, [loggedCommands]);
262
239
  }
263
-
264
240
  function printRangeSelection(selection) {
265
241
  let res = '';
266
242
  const formatText = printFormatProperties(selection);
@@ -273,21 +249,17 @@ function printRangeSelection(selection) {
273
249
  res += `\n └ focus { key: ${focus.key}, offset: ${focusOffset === null ? 'null' : focusOffset}, type: ${focus.type} }`;
274
250
  return res;
275
251
  }
276
-
277
252
  function printNodeSelection(selection) {
278
253
  return `: node\n └ [${Array.from(selection._nodes).join(', ')}]`;
279
254
  }
280
-
281
255
  function printGridSelection(selection) {
282
256
  return `: grid\n └ { grid: ${selection.gridKey}, anchorCell: ${selection.anchor.key}, focusCell: ${selection.focus.key} }`;
283
257
  }
284
-
285
258
  function generateContent(editor, commandsLog, exportDOM) {
286
259
  const editorState = editor.getEditorState();
287
260
  const editorConfig = editor._config;
288
261
  const compositionKey = editor._compositionKey;
289
262
  const editable = editor._editable;
290
-
291
263
  if (exportDOM) {
292
264
  let htmlString = '';
293
265
  editorState.read(() => {
@@ -295,7 +267,6 @@ function generateContent(editor, commandsLog, exportDOM) {
295
267
  });
296
268
  return htmlString;
297
269
  }
298
-
299
270
  let res = ' root\n';
300
271
  const selectionString = editorState.read(() => {
301
272
  const selection = lexical.$getSelection();
@@ -319,7 +290,6 @@ function generateContent(editor, commandsLog, exportDOM) {
319
290
  });
320
291
  res += '\n selection' + selectionString;
321
292
  res += '\n\n commands:';
322
-
323
293
  if (commandsLog.length) {
324
294
  for (const {
325
295
  type,
@@ -330,35 +300,29 @@ function generateContent(editor, commandsLog, exportDOM) {
330
300
  } else {
331
301
  res += '\n └ None dispatched.';
332
302
  }
333
-
334
303
  res += '\n\n editor:';
335
304
  res += `\n └ namespace ${editorConfig.namespace}`;
336
-
337
305
  if (compositionKey !== null) {
338
306
  res += `\n └ compositionKey ${compositionKey}`;
339
307
  }
340
-
341
308
  res += `\n └ editable ${String(editable)}`;
342
309
  return res;
343
310
  }
344
-
345
311
  function visitTree(currentNode, visitor, indent = []) {
346
312
  const childNodes = currentNode.getChildren();
347
313
  const childNodesLength = childNodes.length;
348
314
  childNodes.forEach((childNode, i) => {
349
315
  visitor(childNode, indent.concat(i === childNodesLength - 1 ? SYMBOLS.isLastChild : SYMBOLS.hasNextSibling));
350
-
351
316
  if (lexical.$isElementNode(childNode)) {
352
317
  visitTree(childNode, visitor, indent.concat(i === childNodesLength - 1 ? SYMBOLS.ancestorIsLastChild : SYMBOLS.ancestorHasNextSibling));
353
318
  }
354
319
  });
355
320
  }
356
-
357
321
  function normalize(text) {
358
322
  return Object.entries(NON_SINGLE_WIDTH_CHARS_REPLACEMENT).reduce((acc, [key, value]) => acc.replace(new RegExp(key, 'g'), String(value)), text);
359
- } // TODO Pass via props to allow customizability
360
-
323
+ }
361
324
 
325
+ // TODO Pass via props to allow customizability
362
326
  function printNode(node) {
363
327
  if (lexical.$isTextNode(node)) {
364
328
  const text = node.getTextContent();
@@ -374,79 +338,60 @@ function printNode(node) {
374
338
  return '';
375
339
  }
376
340
  }
377
-
378
341
  const FORMAT_PREDICATES = [node => node.hasFormat('bold') && 'Bold', node => node.hasFormat('code') && 'Code', node => node.hasFormat('italic') && 'Italic', node => node.hasFormat('strikethrough') && 'Strikethrough', node => node.hasFormat('subscript') && 'Subscript', node => node.hasFormat('superscript') && 'Superscript', node => node.hasFormat('underline') && 'Underline'];
379
342
  const DETAIL_PREDICATES = [node => node.isDirectionless() && 'Directionless', node => node.isUnmergeable() && 'Unmergeable'];
380
343
  const MODE_PREDICATES = [node => node.isToken() && 'Token', node => node.isSegmented() && 'Segmented'];
381
-
382
344
  function printAllTextNodeProperties(node) {
383
345
  return [printFormatProperties(node), printDetailProperties(node), printModeProperties(node)].filter(Boolean).join(', ');
384
346
  }
385
-
386
347
  function printAllLinkNodeProperties(node) {
387
348
  return [printTargetProperties(node), printRelProperties(node), printTitleProperties(node)].filter(Boolean).join(', ');
388
349
  }
389
-
390
350
  function printDetailProperties(nodeOrSelection) {
391
351
  let str = DETAIL_PREDICATES.map(predicate => predicate(nodeOrSelection)).filter(Boolean).join(', ').toLocaleLowerCase();
392
-
393
352
  if (str !== '') {
394
353
  str = 'detail: ' + str;
395
354
  }
396
-
397
355
  return str;
398
356
  }
399
-
400
357
  function printModeProperties(nodeOrSelection) {
401
358
  let str = MODE_PREDICATES.map(predicate => predicate(nodeOrSelection)).filter(Boolean).join(', ').toLocaleLowerCase();
402
-
403
359
  if (str !== '') {
404
360
  str = 'mode: ' + str;
405
361
  }
406
-
407
362
  return str;
408
363
  }
409
-
410
364
  function printFormatProperties(nodeOrSelection) {
411
365
  let str = FORMAT_PREDICATES.map(predicate => predicate(nodeOrSelection)).filter(Boolean).join(', ').toLocaleLowerCase();
412
-
413
366
  if (str !== '') {
414
367
  str = 'format: ' + str;
415
368
  }
416
-
417
369
  return str;
418
370
  }
419
-
420
371
  function printTargetProperties(node) {
421
- let str = node.getTarget(); // TODO Fix nullish on LinkNode
422
-
372
+ let str = node.getTarget();
373
+ // TODO Fix nullish on LinkNode
423
374
  if (str != null) {
424
375
  str = 'target: ' + str;
425
376
  }
426
-
427
377
  return str;
428
378
  }
429
-
430
379
  function printRelProperties(node) {
431
- let str = node.getRel(); // TODO Fix nullish on LinkNode
432
-
380
+ let str = node.getRel();
381
+ // TODO Fix nullish on LinkNode
433
382
  if (str != null) {
434
383
  str = 'rel: ' + str;
435
384
  }
436
-
437
385
  return str;
438
386
  }
439
-
440
387
  function printTitleProperties(node) {
441
- let str = node.getTitle(); // TODO Fix nullish on LinkNode
442
-
388
+ let str = node.getTitle();
389
+ // TODO Fix nullish on LinkNode
443
390
  if (str != null) {
444
391
  str = 'title: ' + str;
445
392
  }
446
-
447
393
  return str;
448
394
  }
449
-
450
395
  function printSelectedCharsLine({
451
396
  indent,
452
397
  isSelected,
@@ -458,22 +403,18 @@ function printSelectedCharsLine({
458
403
  // No selection or node is not selected.
459
404
  if (!lexical.$isTextNode(node) || !lexical.$isRangeSelection(selection) || !isSelected || lexical.$isElementNode(node)) {
460
405
  return '';
461
- } // No selected characters.
462
-
406
+ }
463
407
 
408
+ // No selected characters.
464
409
  const anchor = selection.anchor;
465
410
  const focus = selection.focus;
466
-
467
411
  if (node.getTextContent() === '' || anchor.getNode() === selection.focus.getNode() && anchor.offset === focus.offset) {
468
412
  return '';
469
413
  }
470
-
471
414
  const [start, end] = $getSelectionStartEnd(node, selection);
472
-
473
415
  if (start === end) {
474
416
  return '';
475
417
  }
476
-
477
418
  const selectionLastIndent = indent[indent.length - 1] === SYMBOLS.hasNextSibling ? SYMBOLS.ancestorHasNextSibling : SYMBOLS.ancestorIsLastChild;
478
419
  const indentionChars = [...indent.slice(0, indent.length - 1), selectionLastIndent];
479
420
  const unselectedChars = Array(start + 1).fill(' ');
@@ -483,44 +424,38 @@ function printSelectedCharsLine({
483
424
  const nodePrintSpaces = Array(nodeKeyDisplay.length + paddingLength).fill(' ');
484
425
  return [SYMBOLS.selectedLine, indentionChars.join(' '), [...nodePrintSpaces, ...unselectedChars, ...selectedChars].join('')].join(' ') + '\n';
485
426
  }
486
-
487
427
  function printPrettyHTML(str) {
488
428
  const div = document.createElement('div');
489
429
  div.innerHTML = str.trim();
490
430
  return prettifyHTML(div, 0).innerHTML;
491
431
  }
492
-
493
432
  function prettifyHTML(node, level) {
494
433
  const indentBefore = new Array(level++ + 1).join(' ');
495
434
  const indentAfter = new Array(level - 1).join(' ');
496
435
  let textNode;
497
-
498
436
  for (let i = 0; i < node.children.length; i++) {
499
437
  textNode = document.createTextNode('\n' + indentBefore);
500
438
  node.insertBefore(textNode, node.children[i]);
501
439
  prettifyHTML(node.children[i], level);
502
-
503
440
  if (node.lastElementChild === node.children[i]) {
504
441
  textNode = document.createTextNode('\n' + indentAfter);
505
442
  node.appendChild(textNode);
506
443
  }
507
444
  }
508
-
509
445
  return node;
510
446
  }
511
-
512
447
  function $getSelectionStartEnd(node, selection) {
513
448
  const anchor = selection.anchor;
514
449
  const focus = selection.focus;
515
450
  const textContent = node.getTextContent();
516
451
  const textLength = textContent.length;
517
452
  let start = -1;
518
- let end = -1; // Only one node is being selected.
453
+ let end = -1;
519
454
 
455
+ // Only one node is being selected.
520
456
  if (anchor.type === 'text' && focus.type === 'text') {
521
457
  const anchorNode = anchor.getNode();
522
458
  const focusNode = focus.getNode();
523
-
524
459
  if (anchorNode === focusNode && node === anchorNode && anchor.offset !== focus.offset) {
525
460
  [start, end] = anchor.offset < focus.offset ? [anchor.offset, focus.offset] : [focus.offset, anchor.offset];
526
461
  } else if (node === anchorNode) {
@@ -531,9 +466,9 @@ function $getSelectionStartEnd(node, selection) {
531
466
  // Node is within selection but not the anchor nor focus.
532
467
  [start, end] = [0, textLength];
533
468
  }
534
- } // Account for non-single width characters.
535
-
469
+ }
536
470
 
471
+ // Account for non-single width characters.
537
472
  const numNonSingleWidthCharBeforeSelection = (textContent.slice(0, start).match(NON_SINGLE_WIDTH_CHARS_REGEX) || []).length;
538
473
  const numNonSingleWidthCharInSelection = (textContent.slice(start, end).match(NON_SINGLE_WIDTH_CHARS_REGEX) || []).length;
539
474
  return [start + numNonSingleWidthCharBeforeSelection, end + numNonSingleWidthCharBeforeSelection + numNonSingleWidthCharInSelection];
@@ -7,11 +7,11 @@
7
7
  */
8
8
  /// <reference types="react" />
9
9
  import type { MenuRenderFn, MenuResolution, MenuTextMatch, TriggerFn } from './shared/LexicalMenu';
10
- import { LexicalCommand, TextNode } from 'lexical';
10
+ import { CommandListenerPriority, LexicalCommand, TextNode } from 'lexical';
11
11
  import { MenuOption } from './shared/LexicalMenu';
12
12
  export declare const PUNCTUATION = "\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";
13
13
  export declare function getScrollParent(element: HTMLElement, includeHidden: boolean): HTMLElement | HTMLBodyElement;
14
- export declare function useDynamicPositioning(resolution: MenuResolution | null, targetElement: HTMLElement | null, onReposition: () => void, onVisibilityChange?: (isInView: boolean) => void): void;
14
+ export { useDynamicPositioning } from './shared/LexicalMenu';
15
15
  export declare const SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND: LexicalCommand<{
16
16
  index: number;
17
17
  option: MenuOption;
@@ -29,6 +29,7 @@ export type TypeaheadMenuPluginProps<TOption extends MenuOption> = {
29
29
  onOpen?: (resolution: MenuResolution) => void;
30
30
  onClose?: () => void;
31
31
  anchorClassName?: string;
32
+ commandPriority?: CommandListenerPriority;
32
33
  };
33
- export declare function LexicalTypeaheadMenuPlugin<TOption extends MenuOption>({ options, onQueryChange, onSelectOption, onOpen, onClose, menuRenderFn, triggerFn, anchorClassName, }: TypeaheadMenuPluginProps<TOption>): JSX.Element | null;
34
+ export declare function LexicalTypeaheadMenuPlugin<TOption extends MenuOption>({ options, onQueryChange, onSelectOption, onOpen, onClose, menuRenderFn, triggerFn, anchorClassName, commandPriority, }: TypeaheadMenuPluginProps<TOption>): JSX.Element | null;
34
35
  export { MenuOption, MenuRenderFn, MenuResolution, MenuTextMatch, TriggerFn };