@lexical/react 0.5.0 → 0.5.1-next.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.
@@ -213,12 +213,90 @@ function startTransition(callback) {
213
213
  } else {
214
214
  callback();
215
215
  }
216
+ } // Got from https://stackoverflow.com/a/42543908/2013580
217
+
218
+
219
+ function getScrollParent(element, includeHidden) {
220
+ let style = getComputedStyle(element);
221
+ const excludeStaticParent = style.position === 'absolute';
222
+ const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
223
+
224
+ if (style.position === 'fixed') {
225
+ return document.body;
226
+ }
227
+
228
+ for (let parent = element; parent = parent.parentElement;) {
229
+ style = getComputedStyle(parent);
230
+
231
+ if (excludeStaticParent && style.position === 'static') {
232
+ continue;
233
+ }
234
+
235
+ if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
236
+ return parent;
237
+ }
238
+ }
239
+
240
+ return document.body;
216
241
  }
217
242
 
243
+ function isTriggerVisibleInNearestScrollContainer(targetElement, containerElement) {
244
+ const tRect = targetElement.getBoundingClientRect();
245
+ const cRect = containerElement.getBoundingClientRect();
246
+ return tRect.top > cRect.top && tRect.top < cRect.bottom;
247
+ } // Reposition the menu on scroll, window resize, and element resize.
248
+
249
+
250
+ function useDynamicPositioning(resolution, targetElement, onReposition, onVisibilityChange) {
251
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
252
+ React.useEffect(() => {
253
+ if (targetElement != null && resolution != null) {
254
+ const rootElement = editor.getRootElement();
255
+ const rootScrollParent = rootElement != null ? getScrollParent(rootElement, false) : document.body;
256
+ let ticking = false;
257
+ let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
258
+
259
+ const handleScroll = function () {
260
+ if (!ticking) {
261
+ window.requestAnimationFrame(function () {
262
+ onReposition();
263
+ ticking = false;
264
+ });
265
+ ticking = true;
266
+ }
267
+
268
+ const isInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
269
+
270
+ if (isInView !== previousIsInView) {
271
+ previousIsInView = isInView;
272
+
273
+ if (onVisibilityChange != null) {
274
+ onVisibilityChange(isInView);
275
+ }
276
+ }
277
+ };
278
+
279
+ const resizeObserver = new ResizeObserver(onReposition);
280
+ window.addEventListener('resize', onReposition);
281
+ document.addEventListener('scroll', handleScroll, {
282
+ capture: true,
283
+ passive: true
284
+ });
285
+ resizeObserver.observe(targetElement);
286
+ return () => {
287
+ resizeObserver.unobserve(targetElement);
288
+ window.removeEventListener('resize', onReposition);
289
+ document.removeEventListener('scroll', handleScroll);
290
+ };
291
+ }
292
+ }, [targetElement, editor, onVisibilityChange, onReposition, resolution]);
293
+ }
294
+ const SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND = lexical.createCommand('SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND');
295
+
218
296
  function LexicalPopoverMenu({
219
297
  close,
220
298
  editor,
221
- anchorElement,
299
+ anchorElementRef,
222
300
  resolution,
223
301
  options,
224
302
  menuRenderFn,
@@ -258,6 +336,18 @@ function LexicalPopoverMenu({
258
336
  updateSelectedIndex(0);
259
337
  }
260
338
  }, [options, selectedIndex, updateSelectedIndex]);
339
+ React.useEffect(() => {
340
+ return utils.mergeRegister(editor.registerCommand(SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND, ({
341
+ option
342
+ }) => {
343
+ if (option.ref && option.ref.current != null) {
344
+ scrollIntoViewIfNeeded(option.ref.current);
345
+ return true;
346
+ }
347
+
348
+ return false;
349
+ }, lexical.COMMAND_PRIORITY_LOW));
350
+ }, [editor, updateSelectedIndex]);
261
351
  React.useEffect(() => {
262
352
  return utils.mergeRegister(editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, payload => {
263
353
  const event = payload;
@@ -268,7 +358,10 @@ function LexicalPopoverMenu({
268
358
  const option = options[newSelectedIndex];
269
359
 
270
360
  if (option.ref != null && option.ref.current) {
271
- scrollIntoViewIfNeeded(option.ref.current);
361
+ editor.dispatchCommand(SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND, {
362
+ index: newSelectedIndex,
363
+ option
364
+ });
272
365
  }
273
366
 
274
367
  event.preventDefault();
@@ -276,7 +369,7 @@ function LexicalPopoverMenu({
276
369
  }
277
370
 
278
371
  return true;
279
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, payload => {
372
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, payload => {
280
373
  const event = payload;
281
374
 
282
375
  if (options !== null && options.length && selectedIndex !== null) {
@@ -293,13 +386,13 @@ function LexicalPopoverMenu({
293
386
  }
294
387
 
295
388
  return true;
296
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, payload => {
389
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, payload => {
297
390
  const event = payload;
298
391
  event.preventDefault();
299
392
  event.stopImmediatePropagation();
300
393
  close();
301
394
  return true;
302
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_TAB_COMMAND, payload => {
395
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_TAB_COMMAND, payload => {
303
396
  const event = payload;
304
397
 
305
398
  if (options === null || selectedIndex === null || options[selectedIndex] == null) {
@@ -310,7 +403,7 @@ function LexicalPopoverMenu({
310
403
  event.stopImmediatePropagation();
311
404
  selectOptionAndCleanUp(options[selectedIndex]);
312
405
  return true;
313
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_ENTER_COMMAND, event => {
406
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_ENTER_COMMAND, event => {
314
407
  if (options === null || selectedIndex === null || options[selectedIndex] == null) {
315
408
  return false;
316
409
  }
@@ -322,14 +415,15 @@ function LexicalPopoverMenu({
322
415
 
323
416
  selectOptionAndCleanUp(options[selectedIndex]);
324
417
  return true;
325
- }, lexical.COMMAND_PRIORITY_NORMAL));
418
+ }, lexical.COMMAND_PRIORITY_CRITICAL));
326
419
  }, [selectOptionAndCleanUp, close, editor, options, selectedIndex, updateSelectedIndex]);
327
420
  const listItemProps = React.useMemo(() => ({
421
+ options,
328
422
  selectOptionAndCleanUp,
329
423
  selectedIndex,
330
424
  setHighlightedIndex
331
- }), [selectOptionAndCleanUp, selectedIndex]);
332
- return menuRenderFn(anchorElement, listItemProps, resolution.match.matchingString);
425
+ }), [selectOptionAndCleanUp, selectedIndex, options]);
426
+ return menuRenderFn(anchorElementRef, listItemProps, resolution.match.matchingString);
333
427
  }
334
428
 
335
429
  function useBasicTypeaheadTriggerMatch(trigger, {
@@ -358,51 +452,68 @@ function useBasicTypeaheadTriggerMatch(trigger, {
358
452
  }, [maxLength, minLength, trigger]);
359
453
  }
360
454
 
361
- function useAnchorElementRef(resolution) {
455
+ function useMenuAnchorRef(resolution, setResolution, className) {
362
456
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
363
457
  const anchorElementRef = React.useRef(document.createElement('div'));
364
- React.useEffect(() => {
458
+ const positionMenu = React.useCallback(() => {
365
459
  const rootElement = editor.getRootElement();
460
+ const containerDiv = anchorElementRef.current;
461
+
462
+ if (rootElement !== null && resolution !== null) {
463
+ const {
464
+ left,
465
+ top,
466
+ width,
467
+ height
468
+ } = resolution.getRect();
469
+ containerDiv.style.top = `${top + window.pageYOffset}px`;
470
+ containerDiv.style.left = `${left + window.pageXOffset}px`;
471
+ containerDiv.style.height = `${height}px`;
472
+ containerDiv.style.width = `${width}px`;
473
+
474
+ if (!containerDiv.isConnected) {
475
+ if (className != null) {
476
+ containerDiv.className = className;
477
+ }
366
478
 
367
- function positionMenu() {
368
- const containerDiv = anchorElementRef.current;
369
- containerDiv.setAttribute('aria-label', 'Typeahead menu');
370
- containerDiv.setAttribute('id', 'typeahead-menu');
371
- containerDiv.setAttribute('role', 'listbox');
372
-
373
- if (rootElement !== null && resolution !== null) {
374
- const {
375
- left,
376
- top,
377
- width,
378
- height
379
- } = resolution.getRect();
380
- containerDiv.style.top = `${top + height + 5 + window.pageYOffset}px`;
381
- containerDiv.style.left = `${left + (resolution.position === 'start' ? 0 : width) + window.pageXOffset}px`;
479
+ containerDiv.setAttribute('aria-label', 'Typeahead menu');
480
+ containerDiv.setAttribute('id', 'typeahead-menu');
481
+ containerDiv.setAttribute('role', 'listbox');
382
482
  containerDiv.style.display = 'block';
383
483
  containerDiv.style.position = 'absolute';
384
-
385
- if (!containerDiv.isConnected) {
386
- document.body.append(containerDiv);
387
- }
388
-
389
- anchorElementRef.current = containerDiv;
390
- rootElement.setAttribute('aria-controls', 'typeahead-menu');
484
+ document.body.append(containerDiv);
391
485
  }
486
+
487
+ anchorElementRef.current = containerDiv;
488
+ rootElement.setAttribute('aria-controls', 'typeahead-menu');
392
489
  }
490
+ }, [editor, resolution, className]);
491
+ React.useEffect(() => {
492
+ const rootElement = editor.getRootElement();
393
493
 
394
494
  if (resolution !== null) {
395
495
  positionMenu();
396
- window.addEventListener('resize', positionMenu);
397
496
  return () => {
398
- window.removeEventListener('resize', positionMenu);
399
-
400
497
  if (rootElement !== null) {
401
498
  rootElement.removeAttribute('aria-controls');
402
499
  }
500
+
501
+ const containerDiv = anchorElementRef.current;
502
+
503
+ if (containerDiv !== null && containerDiv.isConnected) {
504
+ containerDiv.remove();
505
+ }
403
506
  };
404
507
  }
405
- }, [editor, resolution]);
508
+ }, [editor, positionMenu, resolution]);
509
+ const onVisibilityChange = React.useCallback(isInView => {
510
+ if (resolution !== null) {
511
+ if (!isInView) {
512
+ setResolution(null);
513
+ }
514
+ }
515
+ }, [resolution, setResolution]);
516
+ useDynamicPositioning(resolution, anchorElementRef.current, positionMenu, onVisibilityChange);
406
517
  return anchorElementRef;
407
518
  }
408
519
 
@@ -410,13 +521,29 @@ function LexicalTypeaheadMenuPlugin({
410
521
  options,
411
522
  onQueryChange,
412
523
  onSelectOption,
524
+ onOpen,
525
+ onClose,
413
526
  menuRenderFn,
414
527
  triggerFn,
415
- position = 'start'
528
+ anchorClassName
416
529
  }) {
417
530
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
418
531
  const [resolution, setResolution] = React.useState(null);
419
- const anchorElementRef = useAnchorElementRef(resolution);
532
+ const anchorElementRef = useMenuAnchorRef(resolution, setResolution, anchorClassName);
533
+ const closeTypeahead = React.useCallback(() => {
534
+ setResolution(null);
535
+
536
+ if (onClose != null && resolution !== null) {
537
+ onClose();
538
+ }
539
+ }, [onClose, resolution]);
540
+ const openTypeahead = React.useCallback(res => {
541
+ setResolution(res);
542
+
543
+ if (onOpen != null && resolution === null) {
544
+ onOpen(res);
545
+ }
546
+ }, [onOpen, resolution]);
420
547
  React.useEffect(() => {
421
548
  let activeRange = document.createRange();
422
549
 
@@ -427,7 +554,7 @@ function LexicalTypeaheadMenuPlugin({
427
554
  const text = getQueryTextForSearch(editor);
428
555
 
429
556
  if (!lexical.$isRangeSelection(selection) || !selection.isCollapsed() || text === null || range === null) {
430
- setResolution(null);
557
+ closeTypeahead();
431
558
  return;
432
559
  }
433
560
 
@@ -438,16 +565,15 @@ function LexicalTypeaheadMenuPlugin({
438
565
  const isRangePositioned = tryToPositionRange(match.leadOffset, range);
439
566
 
440
567
  if (isRangePositioned !== null) {
441
- startTransition(() => setResolution({
568
+ startTransition(() => openTypeahead({
442
569
  getRect: () => range.getBoundingClientRect(),
443
- match,
444
- position
570
+ match
445
571
  }));
446
572
  return;
447
573
  }
448
574
  }
449
575
 
450
- setResolution(null);
576
+ closeTypeahead();
451
577
  });
452
578
  };
453
579
 
@@ -456,15 +582,12 @@ function LexicalTypeaheadMenuPlugin({
456
582
  activeRange = null;
457
583
  removeUpdateListener();
458
584
  };
459
- }, [editor, triggerFn, onQueryChange, resolution, position]);
460
- const closeTypeahead = React.useCallback(() => {
461
- setResolution(null);
462
- }, []);
585
+ }, [editor, triggerFn, onQueryChange, resolution, closeTypeahead, openTypeahead]);
463
586
  return resolution === null || editor === null ? null : /*#__PURE__*/React.createElement(LexicalPopoverMenu, {
464
587
  close: closeTypeahead,
465
588
  resolution: resolution,
466
589
  editor: editor,
467
- anchorElement: anchorElementRef.current,
590
+ anchorElementRef: anchorElementRef,
468
591
  options: options,
469
592
  menuRenderFn: menuRenderFn,
470
593
  onSelectOption: onSelectOption
@@ -473,14 +596,29 @@ function LexicalTypeaheadMenuPlugin({
473
596
  function LexicalNodeMenuPlugin({
474
597
  options,
475
598
  nodeKey,
476
- position = 'end',
477
599
  onClose,
600
+ onOpen,
478
601
  onSelectOption,
479
- menuRenderFn
602
+ menuRenderFn,
603
+ anchorClassName
480
604
  }) {
481
605
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
482
606
  const [resolution, setResolution] = React.useState(null);
483
- const anchorElementRef = useAnchorElementRef(resolution);
607
+ const anchorElementRef = useMenuAnchorRef(resolution, setResolution, anchorClassName);
608
+ const closeNodeMenu = React.useCallback(() => {
609
+ setResolution(null);
610
+
611
+ if (onClose != null && resolution !== null) {
612
+ onClose();
613
+ }
614
+ }, [onClose, resolution]);
615
+ const openNodeMenu = React.useCallback(res => {
616
+ setResolution(res);
617
+
618
+ if (onOpen != null && resolution === null) {
619
+ onOpen(res);
620
+ }
621
+ }, [onOpen, resolution]);
484
622
  React.useEffect(() => {
485
623
  if (nodeKey && resolution == null) {
486
624
  editor.update(() => {
@@ -489,26 +627,25 @@ function LexicalNodeMenuPlugin({
489
627
 
490
628
  if (node != null && domElement != null) {
491
629
  const text = node.getTextContent();
492
- startTransition(() => setResolution({
630
+ startTransition(() => openNodeMenu({
493
631
  getRect: () => domElement.getBoundingClientRect(),
494
632
  match: {
495
633
  leadOffset: text.length,
496
634
  matchingString: text,
497
635
  replaceableString: text
498
- },
499
- position
636
+ }
500
637
  }));
501
638
  }
502
639
  });
503
640
  } else if (nodeKey == null && resolution != null) {
504
- setResolution(null);
641
+ closeNodeMenu();
505
642
  }
506
- }, [editor, nodeKey, position, resolution]);
643
+ }, [closeNodeMenu, editor, nodeKey, openNodeMenu, resolution]);
507
644
  return resolution === null || editor === null ? null : /*#__PURE__*/React.createElement(LexicalPopoverMenu, {
508
- close: onClose,
645
+ close: closeNodeMenu,
509
646
  resolution: resolution,
510
647
  editor: editor,
511
- anchorElement: anchorElementRef.current,
648
+ anchorElementRef: anchorElementRef,
512
649
  options: options,
513
650
  menuRenderFn: menuRenderFn,
514
651
  onSelectOption: onSelectOption
@@ -518,5 +655,8 @@ function LexicalNodeMenuPlugin({
518
655
  exports.LexicalNodeMenuPlugin = LexicalNodeMenuPlugin;
519
656
  exports.LexicalTypeaheadMenuPlugin = LexicalTypeaheadMenuPlugin;
520
657
  exports.PUNCTUATION = PUNCTUATION;
658
+ exports.SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND = SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND;
521
659
  exports.TypeaheadOption = TypeaheadOption;
660
+ exports.getScrollParent = getScrollParent;
522
661
  exports.useBasicTypeaheadTriggerMatch = useBasicTypeaheadTriggerMatch;
662
+ exports.useDynamicPositioning = useDynamicPositioning;
@@ -7,7 +7,7 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
- import type {LexicalEditor, NodeKey, TextNode} from 'lexical';
10
+ import type {LexicalCommand, LexicalEditor, NodeKey, TextNode} from 'lexical';
11
11
  import * as React from 'react';
12
12
 
13
13
  export type QueryMatch = {
@@ -26,40 +26,33 @@ export const PUNCTUATION: string =
26
26
 
27
27
  declare export class TypeaheadOption {
28
28
  key: string;
29
- ref: React$ElementRef<HTMLElement | null>;
29
+ ref: {current: HTMLElement | null};
30
30
  constructor(key: string): void;
31
31
  setRefElement(element: HTMLElement | null): void;
32
32
  }
33
33
 
34
+ declare export var SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND: LexicalCommand<{
35
+ index: number,
36
+ option: TypeaheadOption,
37
+ }>;
38
+
34
39
  export type MenuRenderFn<TOption> = (
35
- anchorElement: HTMLElement | null,
40
+ anchorElementRef: {current: HTMLElement | null},
36
41
  itemProps: {
37
42
  selectedIndex: number | null,
38
43
  selectOptionAndCleanUp: (option: TOption) => void,
39
44
  setHighlightedIndex: (index: number) => void,
45
+ options: Array<TOption>,
40
46
  },
41
47
  matchingString: string,
42
48
  ) => React.Portal | React.MixedElement | null;
43
49
 
44
- const scrollIntoViewIfNeeded = (target: HTMLElement) => {
45
- const container = document.getElementById('typeahead-menu');
46
- if (container) {
47
- const containerRect = container.getBoundingClientRect();
48
- const targetRect = target.getBoundingClientRect();
49
- if (targetRect.bottom > containerRect.bottom) {
50
- target.scrollIntoView(false);
51
- } else if (targetRect.top < containerRect.top) {
52
- target.scrollIntoView();
53
- }
54
- }
55
- };
56
-
57
50
  declare export function useBasicTypeaheadTriggerMatch(
58
51
  trigger: string,
59
52
  options: {minLength?: number, maxLength?: number},
60
53
  ): TriggerFn;
61
54
 
62
- export type TypeaheadMenuPluginArgs<TOption> = {
55
+ export type TypeaheadMenuPluginProps<TOption> = {
63
56
  onQueryChange: (matchingString: string | null) => void,
64
57
  onSelectOption: (
65
58
  option: TOption,
@@ -70,6 +63,9 @@ export type TypeaheadMenuPluginArgs<TOption> = {
70
63
  options: Array<TOption>,
71
64
  menuRenderFn: MenuRenderFn<TOption>,
72
65
  triggerFn: TriggerFn,
66
+ onOpen?: (resolution: Resolution) => void,
67
+ onClose?: () => void,
68
+ anchorClassName?: string,
73
69
  };
74
70
 
75
71
  export type TriggerFn = (
@@ -78,10 +74,10 @@ export type TriggerFn = (
78
74
  ) => QueryMatch | null;
79
75
 
80
76
  declare export function LexicalTypeaheadMenuPlugin<TOption>(
81
- options: TypeaheadMenuPluginArgs<TOption>,
77
+ options: TypeaheadMenuPluginProps<TOption>,
82
78
  ): React.MixedElement | null;
83
79
 
84
- type NodeMenuPluginArgs<TOption> = {
80
+ type NodeMenuPluginProps<TOption> = {
85
81
  onSelectOption: (
86
82
  option: TOption,
87
83
  textNodeContainingQuery: TextNode | null,
@@ -90,10 +86,12 @@ type NodeMenuPluginArgs<TOption> = {
90
86
  ) => void,
91
87
  options: Array<TOption>,
92
88
  nodeKey: NodeKey | null,
93
- onClose: () => void,
89
+ onClose?: () => void,
90
+ onOpen?: (resolution: Resolution) => void,
94
91
  menuRenderFn: MenuRenderFn<TOption>,
92
+ anchorClassName?: string,
95
93
  };
96
94
 
97
95
  declare export function LexicalNodeMenuPlugin<TOption>(
98
- options: NodeMenuPluginArgs<TOption>,
96
+ options: NodeMenuPluginProps<TOption>,
99
97
  ): React.MixedElement | null;
@@ -4,19 +4,23 @@
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 m=require("@lexical/react/LexicalComposerContext"),n=require("@lexical/utils"),v=require("lexical"),w=require("react"),x="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?w.useLayoutEffect:w.useEffect;class y{constructor(b){this.key=b;this.ref={current:null};this.setRefElement=this.setRefElement.bind(this)}setRefElement(b){this.ref={current:b}}}
8
- let z=b=>{var a=document.getElementById("typeahead-menu");if(a){a=a.getBoundingClientRect();const c=b.getBoundingClientRect();c.bottom>a.bottom?b.scrollIntoView(!1):c.top<a.top&&b.scrollIntoView()}};function C(b,a){var c=window.getSelection();if(null===c||!c.isCollapsed)return!1;let d=c.anchorNode;c=c.anchorOffset;if(null==d||null==c)return!1;try{a.setStart(d,b),a.setEnd(d,c)}catch(e){return!1}return!0}
9
- function D(b){let a=null;b.getEditorState().read(()=>{var c=v.$getSelection();if(v.$isRangeSelection(c)){var d=c.anchor;"text"!==d.type?a=null:(c=d.getNode(),c.isSimpleText()?(d=d.offset,a=c.getTextContent().slice(0,d)):a=null)}});return a}
10
- function E(b,a){b=v.$getSelection();if(!v.$isRangeSelection(b)||!b.isCollapsed())return null;var c=b.anchor;if("text"!==c.type)return null;b=c.getNode();if(!b.isSimpleText())return null;c=c.offset;let d=b.getTextContent().slice(0,c);var e=a.matchingString;a=a.replaceableString.length;for(let h=a;h<=e.length;h++)d.substr(-h)===e.substr(0,h)&&(a=h);a=c-a;if(0>a)return null;let k;0===a?[k]=b.splitText(c):[,k]=b.splitText(a,c);return k}
11
- function F(b,a){return 0!==a?!1:b.getEditorState().read(()=>{var c=v.$getSelection();return v.$isRangeSelection(c)?(c=c.anchor.getNode().getPreviousSibling(),v.$isTextNode(c)&&c.isTextEntity()):!1})}function G(b){w.startTransition?w.startTransition(b):b()}
12
- function H({close:b,editor:a,anchorElement:c,resolution:d,options:e,menuRenderFn:k,onSelectOption:h}){let [f,p]=w.useState(null);w.useEffect(()=>{p(0)},[d.match.matchingString]);let q=w.useCallback(g=>{a.update(()=>{const l=E(a,d.match);h(g,l,b,d.match.matchingString)})},[b,a,d.match,h]),r=w.useCallback(g=>{const l=a.getRootElement();null!==l&&(l.setAttribute("aria-activedescendant","typeahead-item-"+g),p(g))},[a]);w.useEffect(()=>()=>{let g=a.getRootElement();null!==g&&g.removeAttribute("aria-activedescendant")},
13
- [a]);x(()=>{null===e?p(null):null===f&&r(0)},[e,f,r]);w.useEffect(()=>n.mergeRegister(a.registerCommand(v.KEY_ARROW_DOWN_COMMAND,g=>{if(null!==e&&e.length&&null!==f){var l=f!==e.length-1?f+1:0;r(l);l=e[l];null!=l.ref&&l.ref.current&&z(l.ref.current);g.preventDefault();g.stopImmediatePropagation()}return!0},v.COMMAND_PRIORITY_NORMAL),a.registerCommand(v.KEY_ARROW_UP_COMMAND,g=>{if(null!==e&&e.length&&null!==f){var l=0!==f?f-1:e.length-1;r(l);l=e[l];null!=l.ref&&l.ref.current&&z(l.ref.current);g.preventDefault();
14
- g.stopImmediatePropagation()}return!0},v.COMMAND_PRIORITY_NORMAL),a.registerCommand(v.KEY_ESCAPE_COMMAND,g=>{g.preventDefault();g.stopImmediatePropagation();b();return!0},v.COMMAND_PRIORITY_NORMAL),a.registerCommand(v.KEY_TAB_COMMAND,g=>{if(null===e||null===f||null==e[f])return!1;g.preventDefault();g.stopImmediatePropagation();q(e[f]);return!0},v.COMMAND_PRIORITY_NORMAL),a.registerCommand(v.KEY_ENTER_COMMAND,g=>{if(null===e||null===f||null==e[f])return!1;null!==g&&(g.preventDefault(),g.stopImmediatePropagation());
15
- q(e[f]);return!0},v.COMMAND_PRIORITY_NORMAL)),[q,b,a,e,f,r]);let t=w.useMemo(()=>({selectOptionAndCleanUp:q,selectedIndex:f,setHighlightedIndex:p}),[q,f]);return k(c,t,d.match.matchingString)}
16
- function I(b){let [a]=m.useLexicalComposerContext(),c=w.useRef(document.createElement("div"));w.useEffect(()=>{function d(){let k=c.current;k.setAttribute("aria-label","Typeahead menu");k.setAttribute("id","typeahead-menu");k.setAttribute("role","listbox");if(null!==e&&null!==b){let {left:h,top:f,width:p,height:q}=b.getRect();k.style.top=`${f+q+5+window.pageYOffset}px`;k.style.left=`${h+("start"===b.position?0:p)+window.pageXOffset}px`;k.style.display="block";k.style.position="absolute";k.isConnected||
17
- document.body.append(k);c.current=k;e.setAttribute("aria-controls","typeahead-menu")}}let e=a.getRootElement();if(null!==b)return d(),window.addEventListener("resize",d),()=>{window.removeEventListener("resize",d);null!==e&&e.removeAttribute("aria-controls")}},[a,b]);return c}
18
- exports.LexicalNodeMenuPlugin=function({options:b,nodeKey:a,position:c="end",onClose:d,onSelectOption:e,menuRenderFn:k}){let [h]=m.useLexicalComposerContext(),[f,p]=w.useState(null),q=I(f);w.useEffect(()=>{a&&null==f?h.update(()=>{let r=v.$getNodeByKey(a),t=h.getElementByKey(a);if(null!=r&&null!=t){let g=r.getTextContent();G(()=>p({getRect:()=>t.getBoundingClientRect(),match:{leadOffset:g.length,matchingString:g,replaceableString:g},position:c}))}}):null==a&&null!=f&&p(null)},[h,a,c,f]);return null===
19
- f||null===h?null:w.createElement(H,{close:d,resolution:f,editor:h,anchorElement:q.current,options:b,menuRenderFn:k,onSelectOption:e})};
20
- exports.LexicalTypeaheadMenuPlugin=function({options:b,onQueryChange:a,onSelectOption:c,menuRenderFn:d,triggerFn:e,position:k="start"}){let [h]=m.useLexicalComposerContext(),[f,p]=w.useState(null),q=I(f);w.useEffect(()=>{let t=document.createRange(),g=h.registerUpdateListener(()=>{h.getEditorState().read(()=>{const l=t,A=v.$getSelection(),B=D(h);if(v.$isRangeSelection(A)&&A.isCollapsed()&&null!==B&&null!==l){var u=e(B,h);a(u?u.matchingString:null);null===u||F(h,u.leadOffset)||null===C(u.leadOffset,
21
- l)?p(null):G(()=>p({getRect:()=>l.getBoundingClientRect(),match:u,position:k}))}else p(null)})});return()=>{t=null;g()}},[h,e,a,f,k]);let r=w.useCallback(()=>{p(null)},[]);return null===f||null===h?null:w.createElement(H,{close:r,resolution:f,editor:h,anchorElement:q.current,options:b,menuRenderFn:d,onSelectOption:c})};exports.PUNCTUATION="\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";exports.TypeaheadOption=y;
22
- exports.useBasicTypeaheadTriggerMatch=function(b,{minLength:a=1,maxLength:c=75}){return w.useCallback(d=>{d=(new RegExp("(^|\\s|\\()(["+b+"]((?:[^"+(b+"\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;\\s]){0,")+c+"}))$")).exec(d);if(null!==d){let e=d[1],k=d[3];if(k.length>=a)return{leadOffset:d.index+e.length,matchingString:k,replaceableString:d[2]}}return null},[c,a,b])}
7
+ 'use strict';var k=require("@lexical/react/LexicalComposerContext"),n=require("@lexical/utils"),w=require("lexical"),x=require("react"),z="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?x.useLayoutEffect:x.useEffect;class A{constructor(b){this.key=b;this.ref={current:null};this.setRefElement=this.setRefElement.bind(this)}setRefElement(b){this.ref={current:b}}}
8
+ let B=b=>{var a=document.getElementById("typeahead-menu");if(a){a=a.getBoundingClientRect();const c=b.getBoundingClientRect();c.bottom>a.bottom?b.scrollIntoView(!1):c.top<a.top&&b.scrollIntoView()}};function C(b,a){var c=window.getSelection();if(null===c||!c.isCollapsed)return!1;let e=c.anchorNode;c=c.anchorOffset;if(null==e||null==c)return!1;try{a.setStart(e,b),a.setEnd(e,c)}catch(f){return!1}return!0}
9
+ function D(b){let a=null;b.getEditorState().read(()=>{var c=w.$getSelection();if(w.$isRangeSelection(c)){var e=c.anchor;"text"!==e.type?a=null:(c=e.getNode(),c.isSimpleText()?(e=e.offset,a=c.getTextContent().slice(0,e)):a=null)}});return a}
10
+ function E(b,a){b=w.$getSelection();if(!w.$isRangeSelection(b)||!b.isCollapsed())return null;var c=b.anchor;if("text"!==c.type)return null;b=c.getNode();if(!b.isSimpleText())return null;c=c.offset;let e=b.getTextContent().slice(0,c);var f=a.matchingString;a=a.replaceableString.length;for(let p=a;p<=f.length;p++)e.substr(-p)===f.substr(0,p)&&(a=p);a=c-a;if(0>a)return null;let q;0===a?[q]=b.splitText(c):[,q]=b.splitText(a,c);return q}
11
+ function F(b,a){return 0!==a?!1:b.getEditorState().read(()=>{var c=w.$getSelection();return w.$isRangeSelection(c)?(c=c.anchor.getNode().getPreviousSibling(),w.$isTextNode(c)&&c.isTextEntity()):!1})}function G(b){x.startTransition?x.startTransition(b):b()}
12
+ function J(b,a){let c=getComputedStyle(b),e="absolute"===c.position;a=a?/(auto|scroll|hidden)/:/(auto|scroll)/;if("fixed"===c.position)return document.body;for(;b=b.parentElement;)if(c=getComputedStyle(b),(!e||"static"!==c.position)&&a.test(c.overflow+c.overflowY+c.overflowX))return b;return document.body}function K(b,a){b=b.getBoundingClientRect();a=a.getBoundingClientRect();return b.top>a.top&&b.top<a.bottom}
13
+ function L(b,a,c,e){let [f]=k.useLexicalComposerContext();x.useEffect(()=>{if(null!=a&&null!=b){let q=f.getRootElement(),p=null!=q?J(q,!1):document.body,g=!1,d=K(a,p),m=function(){g||(window.requestAnimationFrame(function(){c();g=!1}),g=!0);const t=K(a,p);t!==d&&(d=t,null!=e&&e(t))},r=new ResizeObserver(c);window.addEventListener("resize",c);document.addEventListener("scroll",m,{capture:!0,passive:!0});r.observe(a);return()=>{r.unobserve(a);window.removeEventListener("resize",c);document.removeEventListener("scroll",
14
+ m)}}},[a,f,e,c,b])}let M=w.createCommand("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");
15
+ function N({close:b,editor:a,anchorElementRef:c,resolution:e,options:f,menuRenderFn:q,onSelectOption:p}){let [g,d]=x.useState(null);x.useEffect(()=>{d(0)},[e.match.matchingString]);let m=x.useCallback(h=>{a.update(()=>{const l=E(a,e.match);p(h,l,b,e.match.matchingString)})},[b,a,e.match,p]),r=x.useCallback(h=>{const l=a.getRootElement();null!==l&&(l.setAttribute("aria-activedescendant","typeahead-item-"+h),d(h))},[a]);x.useEffect(()=>()=>{let h=a.getRootElement();null!==h&&h.removeAttribute("aria-activedescendant")},
16
+ [a]);z(()=>{null===f?d(null):null===g&&r(0)},[f,g,r]);x.useEffect(()=>n.mergeRegister(a.registerCommand(M,({option:h})=>h.ref&&null!=h.ref.current?(B(h.ref.current),!0):!1,w.COMMAND_PRIORITY_LOW)),[a,r]);x.useEffect(()=>n.mergeRegister(a.registerCommand(w.KEY_ARROW_DOWN_COMMAND,h=>{if(null!==f&&f.length&&null!==g){let l=g!==f.length-1?g+1:0;r(l);let u=f[l];null!=u.ref&&u.ref.current&&a.dispatchCommand(M,{index:l,option:u});h.preventDefault();h.stopImmediatePropagation()}return!0},w.COMMAND_PRIORITY_CRITICAL),
17
+ a.registerCommand(w.KEY_ARROW_UP_COMMAND,h=>{if(null!==f&&f.length&&null!==g){var l=0!==g?g-1:f.length-1;r(l);l=f[l];null!=l.ref&&l.ref.current&&B(l.ref.current);h.preventDefault();h.stopImmediatePropagation()}return!0},w.COMMAND_PRIORITY_CRITICAL),a.registerCommand(w.KEY_ESCAPE_COMMAND,h=>{h.preventDefault();h.stopImmediatePropagation();b();return!0},w.COMMAND_PRIORITY_CRITICAL),a.registerCommand(w.KEY_TAB_COMMAND,h=>{if(null===f||null===g||null==f[g])return!1;h.preventDefault();h.stopImmediatePropagation();
18
+ m(f[g]);return!0},w.COMMAND_PRIORITY_CRITICAL),a.registerCommand(w.KEY_ENTER_COMMAND,h=>{if(null===f||null===g||null==f[g])return!1;null!==h&&(h.preventDefault(),h.stopImmediatePropagation());m(f[g]);return!0},w.COMMAND_PRIORITY_CRITICAL)),[m,b,a,f,g,r]);let t=x.useMemo(()=>({options:f,selectOptionAndCleanUp:m,selectedIndex:g,setHighlightedIndex:d}),[m,g,f]);return q(c,t,e.match.matchingString)}
19
+ function O(b,a,c){let [e]=k.useLexicalComposerContext(),f=x.useRef(document.createElement("div")),q=x.useCallback(()=>{const g=e.getRootElement(),d=f.current;if(null!==g&&null!==b){const {left:m,top:r,width:t,height:h}=b.getRect();d.style.top=`${r+window.pageYOffset}px`;d.style.left=`${m+window.pageXOffset}px`;d.style.height=`${h}px`;d.style.width=`${t}px`;d.isConnected||(null!=c&&(d.className=c),d.setAttribute("aria-label","Typeahead menu"),d.setAttribute("id","typeahead-menu"),d.setAttribute("role",
20
+ "listbox"),d.style.display="block",d.style.position="absolute",document.body.append(d));f.current=d;g.setAttribute("aria-controls","typeahead-menu")}},[e,b,c]);x.useEffect(()=>{let g=e.getRootElement();if(null!==b)return q(),()=>{null!==g&&g.removeAttribute("aria-controls");let d=f.current;null!==d&&d.isConnected&&d.remove()}},[e,q,b]);let p=x.useCallback(g=>{null!==b&&(g||a(null))},[b,a]);L(b,f.current,q,p);return f}
21
+ exports.LexicalNodeMenuPlugin=function({options:b,nodeKey:a,onClose:c,onOpen:e,onSelectOption:f,menuRenderFn:q,anchorClassName:p}){let [g]=k.useLexicalComposerContext(),[d,m]=x.useState(null);p=O(d,m,p);let r=x.useCallback(()=>{m(null);null!=c&&null!==d&&c()},[c,d]),t=x.useCallback(h=>{m(h);null!=e&&null===d&&e(h)},[e,d]);x.useEffect(()=>{a&&null==d?g.update(()=>{let h=w.$getNodeByKey(a),l=g.getElementByKey(a);if(null!=h&&null!=l){let u=h.getTextContent();G(()=>t({getRect:()=>l.getBoundingClientRect(),
22
+ match:{leadOffset:u.length,matchingString:u,replaceableString:u}}))}}):null==a&&null!=d&&r()},[r,g,a,t,d]);return null===d||null===g?null:x.createElement(N,{close:r,resolution:d,editor:g,anchorElementRef:p,options:b,menuRenderFn:q,onSelectOption:f})};
23
+ exports.LexicalTypeaheadMenuPlugin=function({options:b,onQueryChange:a,onSelectOption:c,onOpen:e,onClose:f,menuRenderFn:q,triggerFn:p,anchorClassName:g}){let [d]=k.useLexicalComposerContext(),[m,r]=x.useState(null);g=O(m,r,g);let t=x.useCallback(()=>{r(null);null!=f&&null!==m&&f()},[f,m]),h=x.useCallback(l=>{r(l);null!=e&&null===m&&e(l)},[e,m]);x.useEffect(()=>{let l=document.createRange(),u=d.registerUpdateListener(()=>{d.getEditorState().read(()=>{const y=l,H=w.$getSelection(),I=D(d);if(w.$isRangeSelection(H)&&
24
+ H.isCollapsed()&&null!==I&&null!==y){var v=p(I,d);a(v?v.matchingString:null);null===v||F(d,v.leadOffset)||null===C(v.leadOffset,y)?t():G(()=>h({getRect:()=>y.getBoundingClientRect(),match:v}))}else t()})});return()=>{l=null;u()}},[d,p,a,m,t,h]);return null===m||null===d?null:x.createElement(N,{close:t,resolution:m,editor:d,anchorElementRef:g,options:b,menuRenderFn:q,onSelectOption:c})};exports.PUNCTUATION="\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";
25
+ exports.SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND=M;exports.TypeaheadOption=A;exports.getScrollParent=J;exports.useBasicTypeaheadTriggerMatch=function(b,{minLength:a=1,maxLength:c=75}){return x.useCallback(e=>{e=(new RegExp("(^|\\s|\\()(["+b+"]((?:[^"+(b+"\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;\\s]){0,")+c+"}))$")).exec(e);if(null!==e){let f=e[1],q=e[3];if(q.length>=a)return{leadOffset:e.index+f.length,matchingString:q,replaceableString:e[2]}}return null},[c,a,b])};
26
+ exports.useDynamicPositioning=L
package/README.md CHANGED
@@ -73,11 +73,11 @@ function Editor() {
73
73
 
74
74
  return (
75
75
  <LexicalComposer initialConfig={initialConfig}>
76
- <LexicalPlainTextPlugin
77
- contentEditable={<LexicalContentEditable />}
76
+ <PlainTextPlugin
77
+ contentEditable={<ContentEditable />}
78
78
  placeholder={<div>Enter some text...</div>}
79
79
  />
80
- <LexicalOnChangePlugin onChange={onChange} />
80
+ <OnChangePlugin onChange={onChange} />
81
81
  <HistoryPlugin />
82
82
  <MyCustomAutoFocusPlugin />
83
83
  </LexicalComposer>
package/package.json CHANGED
@@ -8,28 +8,28 @@
8
8
  "rich-text"
9
9
  ],
10
10
  "license": "MIT",
11
- "version": "0.5.0",
11
+ "version": "0.5.1-next.1",
12
12
  "dependencies": {
13
- "@lexical/clipboard": "0.5.0",
14
- "@lexical/code": "0.5.0",
15
- "@lexical/dragon": "0.5.0",
16
- "@lexical/hashtag": "0.5.0",
17
- "@lexical/history": "0.5.0",
18
- "@lexical/link": "0.5.0",
19
- "@lexical/list": "0.5.0",
20
- "@lexical/mark": "0.5.0",
21
- "@lexical/markdown": "0.5.0",
22
- "@lexical/overflow": "0.5.0",
23
- "@lexical/plain-text": "0.5.0",
24
- "@lexical/rich-text": "0.5.0",
25
- "@lexical/selection": "0.5.0",
26
- "@lexical/table": "0.5.0",
27
- "@lexical/text": "0.5.0",
28
- "@lexical/utils": "0.5.0",
29
- "@lexical/yjs": "0.5.0"
13
+ "@lexical/clipboard": "0.5.1-next.1",
14
+ "@lexical/code": "0.5.1-next.1",
15
+ "@lexical/dragon": "0.5.1-next.1",
16
+ "@lexical/hashtag": "0.5.1-next.1",
17
+ "@lexical/history": "0.5.1-next.1",
18
+ "@lexical/link": "0.5.1-next.1",
19
+ "@lexical/list": "0.5.1-next.1",
20
+ "@lexical/mark": "0.5.1-next.1",
21
+ "@lexical/markdown": "0.5.1-next.1",
22
+ "@lexical/overflow": "0.5.1-next.1",
23
+ "@lexical/plain-text": "0.5.1-next.1",
24
+ "@lexical/rich-text": "0.5.1-next.1",
25
+ "@lexical/selection": "0.5.1-next.1",
26
+ "@lexical/table": "0.5.1-next.1",
27
+ "@lexical/text": "0.5.1-next.1",
28
+ "@lexical/utils": "0.5.1-next.1",
29
+ "@lexical/yjs": "0.5.1-next.1"
30
30
  },
31
31
  "peerDependencies": {
32
- "lexical": "0.5.0",
32
+ "lexical": "0.5.1-next.1",
33
33
  "react": ">=17.x",
34
34
  "react-dom": ">=17.x"
35
35
  },