1056 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
		
		
			
		
	
	
			1056 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Copyright (c) Meta Platforms, Inc. and affiliates.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This source code is licensed under the MIT license found in the
							 | 
						||
| 
								 | 
							
								 * LICENSE file in the root directory of this source tree.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import type {
							 | 
						||
| 
								 | 
							
								  CommandPayloadType,
							 | 
						||
| 
								 | 
							
								  DOMConversionMap,
							 | 
						||
| 
								 | 
							
								  DOMConversionOutput,
							 | 
						||
| 
								 | 
							
								  DOMExportOutput,
							 | 
						||
| 
								 | 
							
								  EditorConfig,
							 | 
						||
| 
								 | 
							
								  ElementFormatType,
							 | 
						||
| 
								 | 
							
								  LexicalCommand,
							 | 
						||
| 
								 | 
							
								  LexicalEditor,
							 | 
						||
| 
								 | 
							
								  LexicalNode,
							 | 
						||
| 
								 | 
							
								  NodeKey,
							 | 
						||
| 
								 | 
							
								  ParagraphNode,
							 | 
						||
| 
								 | 
							
								  PasteCommandType,
							 | 
						||
| 
								 | 
							
								  RangeSelection,
							 | 
						||
| 
								 | 
							
								  SerializedElementNode,
							 | 
						||
| 
								 | 
							
								  Spread,
							 | 
						||
| 
								 | 
							
								  TextFormatType,
							 | 
						||
| 
								 | 
							
								} from 'lexical';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  $insertDataTransferForRichText,
							 | 
						||
| 
								 | 
							
								  copyToClipboard,
							 | 
						||
| 
								 | 
							
								} from '@lexical/clipboard';
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  $moveCharacter,
							 | 
						||
| 
								 | 
							
								  $shouldOverrideDefaultCharacterSelection,
							 | 
						||
| 
								 | 
							
								} from '@lexical/selection';
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  $findMatchingParent,
							 | 
						||
| 
								 | 
							
								  $getNearestBlockElementAncestorOrThrow,
							 | 
						||
| 
								 | 
							
								  addClassNamesToElement,
							 | 
						||
| 
								 | 
							
								  isHTMLElement,
							 | 
						||
| 
								 | 
							
								  mergeRegister,
							 | 
						||
| 
								 | 
							
								  objectKlassEquals,
							 | 
						||
| 
								 | 
							
								} from '@lexical/utils';
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  $applyNodeReplacement,
							 | 
						||
| 
								 | 
							
								  $createParagraphNode,
							 | 
						||
| 
								 | 
							
								  $createRangeSelection,
							 | 
						||
| 
								 | 
							
								  $createTabNode,
							 | 
						||
| 
								 | 
							
								  $getAdjacentNode,
							 | 
						||
| 
								 | 
							
								  $getNearestNodeFromDOMNode,
							 | 
						||
| 
								 | 
							
								  $getRoot,
							 | 
						||
| 
								 | 
							
								  $getSelection,
							 | 
						||
| 
								 | 
							
								  $insertNodes,
							 | 
						||
| 
								 | 
							
								  $isDecoratorNode,
							 | 
						||
| 
								 | 
							
								  $isElementNode,
							 | 
						||
| 
								 | 
							
								  $isNodeSelection,
							 | 
						||
| 
								 | 
							
								  $isRangeSelection,
							 | 
						||
| 
								 | 
							
								  $isRootNode,
							 | 
						||
| 
								 | 
							
								  $isTextNode,
							 | 
						||
| 
								 | 
							
								  $normalizeSelection__EXPERIMENTAL,
							 | 
						||
| 
								 | 
							
								  $selectAll,
							 | 
						||
| 
								 | 
							
								  $setSelection,
							 | 
						||
| 
								 | 
							
								  CLICK_COMMAND,
							 | 
						||
| 
								 | 
							
								  COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								  CONTROLLED_TEXT_INSERTION_COMMAND,
							 | 
						||
| 
								 | 
							
								  COPY_COMMAND,
							 | 
						||
| 
								 | 
							
								  createCommand,
							 | 
						||
| 
								 | 
							
								  CUT_COMMAND,
							 | 
						||
| 
								 | 
							
								  DELETE_CHARACTER_COMMAND,
							 | 
						||
| 
								 | 
							
								  DELETE_LINE_COMMAND,
							 | 
						||
| 
								 | 
							
								  DELETE_WORD_COMMAND,
							 | 
						||
| 
								 | 
							
								  DRAGOVER_COMMAND,
							 | 
						||
| 
								 | 
							
								  DRAGSTART_COMMAND,
							 | 
						||
| 
								 | 
							
								  DROP_COMMAND,
							 | 
						||
| 
								 | 
							
								  ElementNode,
							 | 
						||
| 
								 | 
							
								  FORMAT_ELEMENT_COMMAND,
							 | 
						||
| 
								 | 
							
								  FORMAT_TEXT_COMMAND,
							 | 
						||
| 
								 | 
							
								  INDENT_CONTENT_COMMAND,
							 | 
						||
| 
								 | 
							
								  INSERT_LINE_BREAK_COMMAND,
							 | 
						||
| 
								 | 
							
								  INSERT_PARAGRAPH_COMMAND,
							 | 
						||
| 
								 | 
							
								  INSERT_TAB_COMMAND,
							 | 
						||
| 
								 | 
							
								  isSelectionCapturedInDecoratorInput,
							 | 
						||
| 
								 | 
							
								  KEY_ARROW_DOWN_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_ARROW_LEFT_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_ARROW_RIGHT_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_ARROW_UP_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_BACKSPACE_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_DELETE_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_ENTER_COMMAND,
							 | 
						||
| 
								 | 
							
								  KEY_ESCAPE_COMMAND,
							 | 
						||
| 
								 | 
							
								  OUTDENT_CONTENT_COMMAND,
							 | 
						||
| 
								 | 
							
								  PASTE_COMMAND,
							 | 
						||
| 
								 | 
							
								  REMOVE_TEXT_COMMAND,
							 | 
						||
| 
								 | 
							
								  SELECT_ALL_COMMAND,
							 | 
						||
| 
								 | 
							
								} from 'lexical';
							 | 
						||
| 
								 | 
							
								import caretFromPoint from 'lexical/shared/caretFromPoint';
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  CAN_USE_BEFORE_INPUT,
							 | 
						||
| 
								 | 
							
								  IS_APPLE_WEBKIT,
							 | 
						||
| 
								 | 
							
								  IS_IOS,
							 | 
						||
| 
								 | 
							
								  IS_SAFARI,
							 | 
						||
| 
								 | 
							
								} from 'lexical/shared/environment';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export type SerializedHeadingNode = Spread<
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  SerializedElementNode
							 | 
						||
| 
								 | 
							
								>;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export const DRAG_DROP_PASTE: LexicalCommand<Array<File>> = createCommand(
							 | 
						||
| 
								 | 
							
								  'DRAG_DROP_PASTE_FILE',
							 | 
						||
| 
								 | 
							
								);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export type SerializedQuoteNode = SerializedElementNode;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @noInheritDoc */
							 | 
						||
| 
								 | 
							
								export class QuoteNode extends ElementNode {
							 | 
						||
| 
								 | 
							
								  static getType(): string {
							 | 
						||
| 
								 | 
							
								    return 'quote';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static clone(node: QuoteNode): QuoteNode {
							 | 
						||
| 
								 | 
							
								    return new QuoteNode(node.__key);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(key?: NodeKey) {
							 | 
						||
| 
								 | 
							
								    super(key);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // View
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  createDOM(config: EditorConfig): HTMLElement {
							 | 
						||
| 
								 | 
							
								    const element = document.createElement('blockquote');
							 | 
						||
| 
								 | 
							
								    addClassNamesToElement(element, config.theme.quote);
							 | 
						||
| 
								 | 
							
								    return element;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  updateDOM(prevNode: QuoteNode, dom: HTMLElement): boolean {
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static importDOM(): DOMConversionMap | null {
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      blockquote: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertBlockquoteElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  exportDOM(editor: LexicalEditor): DOMExportOutput {
							 | 
						||
| 
								 | 
							
								    const {element} = super.exportDOM(editor);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (element && isHTMLElement(element)) {
							 | 
						||
| 
								 | 
							
								      if (this.isEmpty()) {
							 | 
						||
| 
								 | 
							
								        element.append(document.createElement('br'));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const formatType = this.getFormatType();
							 | 
						||
| 
								 | 
							
								      element.style.textAlign = formatType;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      element,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static importJSON(serializedNode: SerializedQuoteNode): QuoteNode {
							 | 
						||
| 
								 | 
							
								    const node = $createQuoteNode();
							 | 
						||
| 
								 | 
							
								    node.setFormat(serializedNode.format);
							 | 
						||
| 
								 | 
							
								    node.setIndent(serializedNode.indent);
							 | 
						||
| 
								 | 
							
								    return node;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  exportJSON(): SerializedElementNode {
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      ...super.exportJSON(),
							 | 
						||
| 
								 | 
							
								      type: 'quote',
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Mutation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ParagraphNode {
							 | 
						||
| 
								 | 
							
								    const newBlock = $createParagraphNode();
							 | 
						||
| 
								 | 
							
								    const direction = this.getDirection();
							 | 
						||
| 
								 | 
							
								    newBlock.setDirection(direction);
							 | 
						||
| 
								 | 
							
								    this.insertAfter(newBlock, restoreSelection);
							 | 
						||
| 
								 | 
							
								    return newBlock;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  collapseAtStart(): true {
							 | 
						||
| 
								 | 
							
								    const paragraph = $createParagraphNode();
							 | 
						||
| 
								 | 
							
								    const children = this.getChildren();
							 | 
						||
| 
								 | 
							
								    children.forEach((child) => paragraph.append(child));
							 | 
						||
| 
								 | 
							
								    this.replace(paragraph);
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  canMergeWhenEmpty(): true {
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function $createQuoteNode(): QuoteNode {
							 | 
						||
| 
								 | 
							
								  return $applyNodeReplacement(new QuoteNode());
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function $isQuoteNode(
							 | 
						||
| 
								 | 
							
								  node: LexicalNode | null | undefined,
							 | 
						||
| 
								 | 
							
								): node is QuoteNode {
							 | 
						||
| 
								 | 
							
								  return node instanceof QuoteNode;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export type HeadingTagType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @noInheritDoc */
							 | 
						||
| 
								 | 
							
								export class HeadingNode extends ElementNode {
							 | 
						||
| 
								 | 
							
								  /** @internal */
							 | 
						||
| 
								 | 
							
								  __tag: HeadingTagType;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static getType(): string {
							 | 
						||
| 
								 | 
							
								    return 'heading';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static clone(node: HeadingNode): HeadingNode {
							 | 
						||
| 
								 | 
							
								    return new HeadingNode(node.__tag, node.__key);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(tag: HeadingTagType, key?: NodeKey) {
							 | 
						||
| 
								 | 
							
								    super(key);
							 | 
						||
| 
								 | 
							
								    this.__tag = tag;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getTag(): HeadingTagType {
							 | 
						||
| 
								 | 
							
								    return this.__tag;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // View
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  createDOM(config: EditorConfig): HTMLElement {
							 | 
						||
| 
								 | 
							
								    const tag = this.__tag;
							 | 
						||
| 
								 | 
							
								    const element = document.createElement(tag);
							 | 
						||
| 
								 | 
							
								    const theme = config.theme;
							 | 
						||
| 
								 | 
							
								    const classNames = theme.heading;
							 | 
						||
| 
								 | 
							
								    if (classNames !== undefined) {
							 | 
						||
| 
								 | 
							
								      const className = classNames[tag];
							 | 
						||
| 
								 | 
							
								      addClassNamesToElement(element, className);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return element;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  updateDOM(prevNode: HeadingNode, dom: HTMLElement): boolean {
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static importDOM(): DOMConversionMap | null {
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      h1: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertHeadingElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								      h2: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertHeadingElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								      h3: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertHeadingElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								      h4: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertHeadingElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								      h5: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertHeadingElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								      h6: (node: Node) => ({
							 | 
						||
| 
								 | 
							
								        conversion: $convertHeadingElement,
							 | 
						||
| 
								 | 
							
								        priority: 0,
							 | 
						||
| 
								 | 
							
								      }),
							 | 
						||
| 
								 | 
							
								      p: (node: Node) => {
							 | 
						||
| 
								 | 
							
								        // domNode is a <p> since we matched it by nodeName
							 | 
						||
| 
								 | 
							
								        const paragraph = node as HTMLParagraphElement;
							 | 
						||
| 
								 | 
							
								        const firstChild = paragraph.firstChild;
							 | 
						||
| 
								 | 
							
								        if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
							 | 
						||
| 
								 | 
							
								          return {
							 | 
						||
| 
								 | 
							
								            conversion: () => ({node: null}),
							 | 
						||
| 
								 | 
							
								            priority: 3,
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      span: (node: Node) => {
							 | 
						||
| 
								 | 
							
								        if (isGoogleDocsTitle(node)) {
							 | 
						||
| 
								 | 
							
								          return {
							 | 
						||
| 
								 | 
							
								            conversion: (domNode: Node) => {
							 | 
						||
| 
								 | 
							
								              return {
							 | 
						||
| 
								 | 
							
								                node: $createHeadingNode('h1'),
							 | 
						||
| 
								 | 
							
								              };
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            priority: 3,
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return null;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  exportDOM(editor: LexicalEditor): DOMExportOutput {
							 | 
						||
| 
								 | 
							
								    const {element} = super.exportDOM(editor);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (element && isHTMLElement(element)) {
							 | 
						||
| 
								 | 
							
								      if (this.isEmpty()) {
							 | 
						||
| 
								 | 
							
								        element.append(document.createElement('br'));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const formatType = this.getFormatType();
							 | 
						||
| 
								 | 
							
								      element.style.textAlign = formatType;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      element,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static importJSON(serializedNode: SerializedHeadingNode): HeadingNode {
							 | 
						||
| 
								 | 
							
								    const node = $createHeadingNode(serializedNode.tag);
							 | 
						||
| 
								 | 
							
								    node.setFormat(serializedNode.format);
							 | 
						||
| 
								 | 
							
								    node.setIndent(serializedNode.indent);
							 | 
						||
| 
								 | 
							
								    return node;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  exportJSON(): SerializedHeadingNode {
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      ...super.exportJSON(),
							 | 
						||
| 
								 | 
							
								      tag: this.getTag(),
							 | 
						||
| 
								 | 
							
								      type: 'heading',
							 | 
						||
| 
								 | 
							
								      version: 1,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Mutation
							 | 
						||
| 
								 | 
							
								  insertNewAfter(
							 | 
						||
| 
								 | 
							
								    selection?: RangeSelection,
							 | 
						||
| 
								 | 
							
								    restoreSelection = true,
							 | 
						||
| 
								 | 
							
								  ): ParagraphNode | HeadingNode {
							 | 
						||
| 
								 | 
							
								    const anchorOffet = selection ? selection.anchor.offset : 0;
							 | 
						||
| 
								 | 
							
								    const lastDesc = this.getLastDescendant();
							 | 
						||
| 
								 | 
							
								    const isAtEnd =
							 | 
						||
| 
								 | 
							
								      !lastDesc ||
							 | 
						||
| 
								 | 
							
								      (selection &&
							 | 
						||
| 
								 | 
							
								        selection.anchor.key === lastDesc.getKey() &&
							 | 
						||
| 
								 | 
							
								        anchorOffet === lastDesc.getTextContentSize());
							 | 
						||
| 
								 | 
							
								    const newElement =
							 | 
						||
| 
								 | 
							
								      isAtEnd || !selection
							 | 
						||
| 
								 | 
							
								        ? $createParagraphNode()
							 | 
						||
| 
								 | 
							
								        : $createHeadingNode(this.getTag());
							 | 
						||
| 
								 | 
							
								    const direction = this.getDirection();
							 | 
						||
| 
								 | 
							
								    newElement.setDirection(direction);
							 | 
						||
| 
								 | 
							
								    this.insertAfter(newElement, restoreSelection);
							 | 
						||
| 
								 | 
							
								    if (anchorOffet === 0 && !this.isEmpty() && selection) {
							 | 
						||
| 
								 | 
							
								      const paragraph = $createParagraphNode();
							 | 
						||
| 
								 | 
							
								      paragraph.select();
							 | 
						||
| 
								 | 
							
								      this.replace(paragraph, true);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return newElement;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  collapseAtStart(): true {
							 | 
						||
| 
								 | 
							
								    const newElement = !this.isEmpty()
							 | 
						||
| 
								 | 
							
								      ? $createHeadingNode(this.getTag())
							 | 
						||
| 
								 | 
							
								      : $createParagraphNode();
							 | 
						||
| 
								 | 
							
								    const children = this.getChildren();
							 | 
						||
| 
								 | 
							
								    children.forEach((child) => newElement.append(child));
							 | 
						||
| 
								 | 
							
								    this.replace(newElement);
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  extractWithChild(): boolean {
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function isGoogleDocsTitle(domNode: Node): boolean {
							 | 
						||
| 
								 | 
							
								  if (domNode.nodeName.toLowerCase() === 'span') {
							 | 
						||
| 
								 | 
							
								    return (domNode as HTMLSpanElement).style.fontSize === '26pt';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return false;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
							 | 
						||
| 
								 | 
							
								  const nodeName = element.nodeName.toLowerCase();
							 | 
						||
| 
								 | 
							
								  let node = null;
							 | 
						||
| 
								 | 
							
								  if (
							 | 
						||
| 
								 | 
							
								    nodeName === 'h1' ||
							 | 
						||
| 
								 | 
							
								    nodeName === 'h2' ||
							 | 
						||
| 
								 | 
							
								    nodeName === 'h3' ||
							 | 
						||
| 
								 | 
							
								    nodeName === 'h4' ||
							 | 
						||
| 
								 | 
							
								    nodeName === 'h5' ||
							 | 
						||
| 
								 | 
							
								    nodeName === 'h6'
							 | 
						||
| 
								 | 
							
								  ) {
							 | 
						||
| 
								 | 
							
								    node = $createHeadingNode(nodeName);
							 | 
						||
| 
								 | 
							
								    if (element.style !== null) {
							 | 
						||
| 
								 | 
							
								      node.setFormat(element.style.textAlign as ElementFormatType);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return {node};
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
							 | 
						||
| 
								 | 
							
								  const node = $createQuoteNode();
							 | 
						||
| 
								 | 
							
								  if (element.style !== null) {
							 | 
						||
| 
								 | 
							
								    node.setFormat(element.style.textAlign as ElementFormatType);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return {node};
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function $createHeadingNode(headingTag: HeadingTagType): HeadingNode {
							 | 
						||
| 
								 | 
							
								  return $applyNodeReplacement(new HeadingNode(headingTag));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function $isHeadingNode(
							 | 
						||
| 
								 | 
							
								  node: LexicalNode | null | undefined,
							 | 
						||
| 
								 | 
							
								): node is HeadingNode {
							 | 
						||
| 
								 | 
							
								  return node instanceof HeadingNode;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function onPasteForRichText(
							 | 
						||
| 
								 | 
							
								  event: CommandPayloadType<typeof PASTE_COMMAND>,
							 | 
						||
| 
								 | 
							
								  editor: LexicalEditor,
							 | 
						||
| 
								 | 
							
								): void {
							 | 
						||
| 
								 | 
							
								  event.preventDefault();
							 | 
						||
| 
								 | 
							
								  editor.update(
							 | 
						||
| 
								 | 
							
								    () => {
							 | 
						||
| 
								 | 
							
								      const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								      const clipboardData =
							 | 
						||
| 
								 | 
							
								        objectKlassEquals(event, InputEvent) ||
							 | 
						||
| 
								 | 
							
								        objectKlassEquals(event, KeyboardEvent)
							 | 
						||
| 
								 | 
							
								          ? null
							 | 
						||
| 
								 | 
							
								          : (event as ClipboardEvent).clipboardData;
							 | 
						||
| 
								 | 
							
								      if (clipboardData != null && selection !== null) {
							 | 
						||
| 
								 | 
							
								        $insertDataTransferForRichText(clipboardData, selection, editor);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      tag: 'paste',
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								async function onCutForRichText(
							 | 
						||
| 
								 | 
							
								  event: CommandPayloadType<typeof CUT_COMMAND>,
							 | 
						||
| 
								 | 
							
								  editor: LexicalEditor,
							 | 
						||
| 
								 | 
							
								): Promise<void> {
							 | 
						||
| 
								 | 
							
								  await copyToClipboard(
							 | 
						||
| 
								 | 
							
								    editor,
							 | 
						||
| 
								 | 
							
								    objectKlassEquals(event, ClipboardEvent) ? (event as ClipboardEvent) : null,
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								  editor.update(() => {
							 | 
						||
| 
								 | 
							
								    const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								    if ($isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								      selection.removeText();
							 | 
						||
| 
								 | 
							
								    } else if ($isNodeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								      selection.getNodes().forEach((node) => node.remove());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Clipboard may contain files that we aren't allowed to read. While the event is arguably useless,
							 | 
						||
| 
								 | 
							
								// in certain occasions, we want to know whether it was a file transfer, as opposed to text. We
							 | 
						||
| 
								 | 
							
								// control this with the first boolean flag.
							 | 
						||
| 
								 | 
							
								export function eventFiles(
							 | 
						||
| 
								 | 
							
								  event: DragEvent | PasteCommandType,
							 | 
						||
| 
								 | 
							
								): [boolean, Array<File>, boolean] {
							 | 
						||
| 
								 | 
							
								  let dataTransfer: null | DataTransfer = null;
							 | 
						||
| 
								 | 
							
								  if (objectKlassEquals(event, DragEvent)) {
							 | 
						||
| 
								 | 
							
								    dataTransfer = (event as DragEvent).dataTransfer;
							 | 
						||
| 
								 | 
							
								  } else if (objectKlassEquals(event, ClipboardEvent)) {
							 | 
						||
| 
								 | 
							
								    dataTransfer = (event as ClipboardEvent).clipboardData;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (dataTransfer === null) {
							 | 
						||
| 
								 | 
							
								    return [false, [], false];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const types = dataTransfer.types;
							 | 
						||
| 
								 | 
							
								  const hasFiles = types.includes('Files');
							 | 
						||
| 
								 | 
							
								  const hasContent =
							 | 
						||
| 
								 | 
							
								    types.includes('text/html') || types.includes('text/plain');
							 | 
						||
| 
								 | 
							
								  return [hasFiles, Array.from(dataTransfer.files), hasContent];
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function $handleIndentAndOutdent(
							 | 
						||
| 
								 | 
							
								  indentOrOutdent: (block: ElementNode) => void,
							 | 
						||
| 
								 | 
							
								): boolean {
							 | 
						||
| 
								 | 
							
								  const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								  if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  const alreadyHandled = new Set();
							 | 
						||
| 
								 | 
							
								  const nodes = selection.getNodes();
							 | 
						||
| 
								 | 
							
								  for (let i = 0; i < nodes.length; i++) {
							 | 
						||
| 
								 | 
							
								    const node = nodes[i];
							 | 
						||
| 
								 | 
							
								    const key = node.getKey();
							 | 
						||
| 
								 | 
							
								    if (alreadyHandled.has(key)) {
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const parentBlock = $findMatchingParent(
							 | 
						||
| 
								 | 
							
								      node,
							 | 
						||
| 
								 | 
							
								      (parentNode): parentNode is ElementNode =>
							 | 
						||
| 
								 | 
							
								        $isElementNode(parentNode) && !parentNode.isInline(),
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    if (parentBlock === null) {
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const parentKey = parentBlock.getKey();
							 | 
						||
| 
								 | 
							
								    if (parentBlock.canIndent() && !alreadyHandled.has(parentKey)) {
							 | 
						||
| 
								 | 
							
								      alreadyHandled.add(parentKey);
							 | 
						||
| 
								 | 
							
								      indentOrOutdent(parentBlock);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return alreadyHandled.size > 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function $isTargetWithinDecorator(target: HTMLElement): boolean {
							 | 
						||
| 
								 | 
							
								  const node = $getNearestNodeFromDOMNode(target);
							 | 
						||
| 
								 | 
							
								  return $isDecoratorNode(node);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function $isSelectionAtEndOfRoot(selection: RangeSelection) {
							 | 
						||
| 
								 | 
							
								  const focus = selection.focus;
							 | 
						||
| 
								 | 
							
								  return focus.key === 'root' && focus.offset === $getRoot().getChildrenSize();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function registerRichText(editor: LexicalEditor): () => void {
							 | 
						||
| 
								 | 
							
								  const removeListener = mergeRegister(
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      CLICK_COMMAND,
							 | 
						||
| 
								 | 
							
								      (payload) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if ($isNodeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          selection.clear();
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      0,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<boolean>(
							 | 
						||
| 
								 | 
							
								      DELETE_CHARACTER_COMMAND,
							 | 
						||
| 
								 | 
							
								      (isBackward) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.deleteCharacter(isBackward);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<boolean>(
							 | 
						||
| 
								 | 
							
								      DELETE_WORD_COMMAND,
							 | 
						||
| 
								 | 
							
								      (isBackward) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.deleteWord(isBackward);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<boolean>(
							 | 
						||
| 
								 | 
							
								      DELETE_LINE_COMMAND,
							 | 
						||
| 
								 | 
							
								      (isBackward) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.deleteLine(isBackward);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      CONTROLLED_TEXT_INSERTION_COMMAND,
							 | 
						||
| 
								 | 
							
								      (eventOrText) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (typeof eventOrText === 'string') {
							 | 
						||
| 
								 | 
							
								          if (selection !== null) {
							 | 
						||
| 
								 | 
							
								            selection.insertText(eventOrText);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          if (selection === null) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          const dataTransfer = eventOrText.dataTransfer;
							 | 
						||
| 
								 | 
							
								          if (dataTransfer != null) {
							 | 
						||
| 
								 | 
							
								            $insertDataTransferForRichText(dataTransfer, selection, editor);
							 | 
						||
| 
								 | 
							
								          } else if ($isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								            const data = eventOrText.data;
							 | 
						||
| 
								 | 
							
								            if (data) {
							 | 
						||
| 
								 | 
							
								              selection.insertText(data);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      REMOVE_TEXT_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.removeText();
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<TextFormatType>(
							 | 
						||
| 
								 | 
							
								      FORMAT_TEXT_COMMAND,
							 | 
						||
| 
								 | 
							
								      (format) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.formatText(format);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<ElementFormatType>(
							 | 
						||
| 
								 | 
							
								      FORMAT_ELEMENT_COMMAND,
							 | 
						||
| 
								 | 
							
								      (format) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection) && !$isNodeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const nodes = selection.getNodes();
							 | 
						||
| 
								 | 
							
								        for (const node of nodes) {
							 | 
						||
| 
								 | 
							
								          const element = $findMatchingParent(
							 | 
						||
| 
								 | 
							
								            node,
							 | 
						||
| 
								 | 
							
								            (parentNode): parentNode is ElementNode =>
							 | 
						||
| 
								 | 
							
								              $isElementNode(parentNode) && !parentNode.isInline(),
							 | 
						||
| 
								 | 
							
								          );
							 | 
						||
| 
								 | 
							
								          if (element !== null) {
							 | 
						||
| 
								 | 
							
								            element.setFormat(format);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<boolean>(
							 | 
						||
| 
								 | 
							
								      INSERT_LINE_BREAK_COMMAND,
							 | 
						||
| 
								 | 
							
								      (selectStart) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.insertLineBreak(selectStart);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      INSERT_PARAGRAPH_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        selection.insertParagraph();
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      INSERT_TAB_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        $insertNodes([$createTabNode()]);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      INDENT_CONTENT_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        return $handleIndentAndOutdent((block) => {
							 | 
						||
| 
								 | 
							
								          const indent = block.getIndent();
							 | 
						||
| 
								 | 
							
								          block.setIndent(indent + 1);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      OUTDENT_CONTENT_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        return $handleIndentAndOutdent((block) => {
							 | 
						||
| 
								 | 
							
								          const indent = block.getIndent();
							 | 
						||
| 
								 | 
							
								          if (indent > 0) {
							 | 
						||
| 
								 | 
							
								            block.setIndent(indent - 1);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent>(
							 | 
						||
| 
								 | 
							
								      KEY_ARROW_UP_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								          $isNodeSelection(selection) &&
							 | 
						||
| 
								 | 
							
								          !$isTargetWithinDecorator(event.target as HTMLElement)
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								          // If selection is on a node, let's try and move selection
							 | 
						||
| 
								 | 
							
								          // back to being a range selection.
							 | 
						||
| 
								 | 
							
								          const nodes = selection.getNodes();
							 | 
						||
| 
								 | 
							
								          if (nodes.length > 0) {
							 | 
						||
| 
								 | 
							
								            nodes[0].selectPrevious();
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else if ($isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          const possibleNode = $getAdjacentNode(selection.focus, true);
							 | 
						||
| 
								 | 
							
								          if (
							 | 
						||
| 
								 | 
							
								            !event.shiftKey &&
							 | 
						||
| 
								 | 
							
								            $isDecoratorNode(possibleNode) &&
							 | 
						||
| 
								 | 
							
								            !possibleNode.isIsolated() &&
							 | 
						||
| 
								 | 
							
								            !possibleNode.isInline()
							 | 
						||
| 
								 | 
							
								          ) {
							 | 
						||
| 
								 | 
							
								            possibleNode.selectPrevious();
							 | 
						||
| 
								 | 
							
								            event.preventDefault();
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent>(
							 | 
						||
| 
								 | 
							
								      KEY_ARROW_DOWN_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if ($isNodeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          // If selection is on a node, let's try and move selection
							 | 
						||
| 
								 | 
							
								          // back to being a range selection.
							 | 
						||
| 
								 | 
							
								          const nodes = selection.getNodes();
							 | 
						||
| 
								 | 
							
								          if (nodes.length > 0) {
							 | 
						||
| 
								 | 
							
								            nodes[0].selectNext(0, 0);
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else if ($isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          if ($isSelectionAtEndOfRoot(selection)) {
							 | 
						||
| 
								 | 
							
								            event.preventDefault();
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          const possibleNode = $getAdjacentNode(selection.focus, false);
							 | 
						||
| 
								 | 
							
								          if (
							 | 
						||
| 
								 | 
							
								            !event.shiftKey &&
							 | 
						||
| 
								 | 
							
								            $isDecoratorNode(possibleNode) &&
							 | 
						||
| 
								 | 
							
								            !possibleNode.isIsolated() &&
							 | 
						||
| 
								 | 
							
								            !possibleNode.isInline()
							 | 
						||
| 
								 | 
							
								          ) {
							 | 
						||
| 
								 | 
							
								            possibleNode.selectNext();
							 | 
						||
| 
								 | 
							
								            event.preventDefault();
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent>(
							 | 
						||
| 
								 | 
							
								      KEY_ARROW_LEFT_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if ($isNodeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          // If selection is on a node, let's try and move selection
							 | 
						||
| 
								 | 
							
								          // back to being a range selection.
							 | 
						||
| 
								 | 
							
								          const nodes = selection.getNodes();
							 | 
						||
| 
								 | 
							
								          if (nodes.length > 0) {
							 | 
						||
| 
								 | 
							
								            event.preventDefault();
							 | 
						||
| 
								 | 
							
								            nodes[0].selectPrevious();
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if ($shouldOverrideDefaultCharacterSelection(selection, true)) {
							 | 
						||
| 
								 | 
							
								          const isHoldingShift = event.shiftKey;
							 | 
						||
| 
								 | 
							
								          event.preventDefault();
							 | 
						||
| 
								 | 
							
								          $moveCharacter(selection, isHoldingShift, true);
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent>(
							 | 
						||
| 
								 | 
							
								      KEY_ARROW_RIGHT_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								          $isNodeSelection(selection) &&
							 | 
						||
| 
								 | 
							
								          !$isTargetWithinDecorator(event.target as HTMLElement)
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								          // If selection is on a node, let's try and move selection
							 | 
						||
| 
								 | 
							
								          // back to being a range selection.
							 | 
						||
| 
								 | 
							
								          const nodes = selection.getNodes();
							 | 
						||
| 
								 | 
							
								          if (nodes.length > 0) {
							 | 
						||
| 
								 | 
							
								            event.preventDefault();
							 | 
						||
| 
								 | 
							
								            nodes[0].selectNext(0, 0);
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const isHoldingShift = event.shiftKey;
							 | 
						||
| 
								 | 
							
								        if ($shouldOverrideDefaultCharacterSelection(selection, false)) {
							 | 
						||
| 
								 | 
							
								          event.preventDefault();
							 | 
						||
| 
								 | 
							
								          $moveCharacter(selection, isHoldingShift, false);
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent>(
							 | 
						||
| 
								 | 
							
								      KEY_BACKSPACE_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        if ($isTargetWithinDecorator(event.target as HTMLElement)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        event.preventDefault();
							 | 
						||
| 
								 | 
							
								        const {anchor} = selection;
							 | 
						||
| 
								 | 
							
								        const anchorNode = anchor.getNode();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								          selection.isCollapsed() &&
							 | 
						||
| 
								 | 
							
								          anchor.offset === 0 &&
							 | 
						||
| 
								 | 
							
								          !$isRootNode(anchorNode)
							 | 
						||
| 
								 | 
							
								        ) {
							 | 
						||
| 
								 | 
							
								          const element = $getNearestBlockElementAncestorOrThrow(anchorNode);
							 | 
						||
| 
								 | 
							
								          if (element.getIndent() > 0) {
							 | 
						||
| 
								 | 
							
								            return editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, undefined);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return editor.dispatchCommand(DELETE_CHARACTER_COMMAND, true);
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent>(
							 | 
						||
| 
								 | 
							
								      KEY_DELETE_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        if ($isTargetWithinDecorator(event.target as HTMLElement)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        event.preventDefault();
							 | 
						||
| 
								 | 
							
								        return editor.dispatchCommand(DELETE_CHARACTER_COMMAND, false);
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<KeyboardEvent | null>(
							 | 
						||
| 
								 | 
							
								      KEY_ENTER_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (event !== null) {
							 | 
						||
| 
								 | 
							
								          // If we have beforeinput, then we can avoid blocking
							 | 
						||
| 
								 | 
							
								          // the default behavior. This ensures that the iOS can
							 | 
						||
| 
								 | 
							
								          // intercept that we're actually inserting a paragraph,
							 | 
						||
| 
								 | 
							
								          // and autocomplete, autocapitalize etc work as intended.
							 | 
						||
| 
								 | 
							
								          // This can also cause a strange performance issue in
							 | 
						||
| 
								 | 
							
								          // Safari, where there is a noticeable pause due to
							 | 
						||
| 
								 | 
							
								          // preventing the key down of enter.
							 | 
						||
| 
								 | 
							
								          if (
							 | 
						||
| 
								 | 
							
								            (IS_IOS || IS_SAFARI || IS_APPLE_WEBKIT) &&
							 | 
						||
| 
								 | 
							
								            CAN_USE_BEFORE_INPUT
							 | 
						||
| 
								 | 
							
								          ) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          event.preventDefault();
							 | 
						||
| 
								 | 
							
								          if (event.shiftKey) {
							 | 
						||
| 
								 | 
							
								            return editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      KEY_ESCAPE_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (!$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        editor.blur();
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<DragEvent>(
							 | 
						||
| 
								 | 
							
								      DROP_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const [, files] = eventFiles(event);
							 | 
						||
| 
								 | 
							
								        if (files.length > 0) {
							 | 
						||
| 
								 | 
							
								          const x = event.clientX;
							 | 
						||
| 
								 | 
							
								          const y = event.clientY;
							 | 
						||
| 
								 | 
							
								          const eventRange = caretFromPoint(x, y);
							 | 
						||
| 
								 | 
							
								          if (eventRange !== null) {
							 | 
						||
| 
								 | 
							
								            const {offset: domOffset, node: domNode} = eventRange;
							 | 
						||
| 
								 | 
							
								            const node = $getNearestNodeFromDOMNode(domNode);
							 | 
						||
| 
								 | 
							
								            if (node !== null) {
							 | 
						||
| 
								 | 
							
								              const selection = $createRangeSelection();
							 | 
						||
| 
								 | 
							
								              if ($isTextNode(node)) {
							 | 
						||
| 
								 | 
							
								                selection.anchor.set(node.getKey(), domOffset, 'text');
							 | 
						||
| 
								 | 
							
								                selection.focus.set(node.getKey(), domOffset, 'text');
							 | 
						||
| 
								 | 
							
								              } else {
							 | 
						||
| 
								 | 
							
								                const parentKey = node.getParentOrThrow().getKey();
							 | 
						||
| 
								 | 
							
								                const offset = node.getIndexWithinParent() + 1;
							 | 
						||
| 
								 | 
							
								                selection.anchor.set(parentKey, offset, 'element');
							 | 
						||
| 
								 | 
							
								                selection.focus.set(parentKey, offset, 'element');
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								              const normalizedSelection =
							 | 
						||
| 
								 | 
							
								                $normalizeSelection__EXPERIMENTAL(selection);
							 | 
						||
| 
								 | 
							
								              $setSelection(normalizedSelection);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            editor.dispatchCommand(DRAG_DROP_PASTE, files);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          event.preventDefault();
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if ($isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<DragEvent>(
							 | 
						||
| 
								 | 
							
								      DRAGSTART_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const [isFileTransfer] = eventFiles(event);
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (isFileTransfer && !$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand<DragEvent>(
							 | 
						||
| 
								 | 
							
								      DRAGOVER_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const [isFileTransfer] = eventFiles(event);
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (isFileTransfer && !$isRangeSelection(selection)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const x = event.clientX;
							 | 
						||
| 
								 | 
							
								        const y = event.clientY;
							 | 
						||
| 
								 | 
							
								        const eventRange = caretFromPoint(x, y);
							 | 
						||
| 
								 | 
							
								        if (eventRange !== null) {
							 | 
						||
| 
								 | 
							
								          const node = $getNearestNodeFromDOMNode(eventRange.node);
							 | 
						||
| 
								 | 
							
								          if ($isDecoratorNode(node)) {
							 | 
						||
| 
								 | 
							
								            // Show browser caret as the user is dragging the media across the screen. Won't work
							 | 
						||
| 
								 | 
							
								            // for DecoratorNode nor it's relevant.
							 | 
						||
| 
								 | 
							
								            event.preventDefault();
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      SELECT_ALL_COMMAND,
							 | 
						||
| 
								 | 
							
								      () => {
							 | 
						||
| 
								 | 
							
								        $selectAll();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      COPY_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        copyToClipboard(
							 | 
						||
| 
								 | 
							
								          editor,
							 | 
						||
| 
								 | 
							
								          objectKlassEquals(event, ClipboardEvent)
							 | 
						||
| 
								 | 
							
								            ? (event as ClipboardEvent)
							 | 
						||
| 
								 | 
							
								            : null,
							 | 
						||
| 
								 | 
							
								        );
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      CUT_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        onCutForRichText(event, editor);
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								    editor.registerCommand(
							 | 
						||
| 
								 | 
							
								      PASTE_COMMAND,
							 | 
						||
| 
								 | 
							
								      (event) => {
							 | 
						||
| 
								 | 
							
								        const [, files, hasTextContent] = eventFiles(event);
							 | 
						||
| 
								 | 
							
								        if (files.length > 0 && !hasTextContent) {
							 | 
						||
| 
								 | 
							
								          editor.dispatchCommand(DRAG_DROP_PASTE, files);
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // if inputs then paste within the input ignore creating a new node on paste event
							 | 
						||
| 
								 | 
							
								        if (isSelectionCapturedInDecoratorInput(event.target as Node)) {
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        const selection = $getSelection();
							 | 
						||
| 
								 | 
							
								        if (selection !== null) {
							 | 
						||
| 
								 | 
							
								          onPasteForRichText(event, editor);
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      COMMAND_PRIORITY_EDITOR,
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								  return removeListener;
							 | 
						||
| 
								 | 
							
								}
							 |