/**
 * 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.
 *
 * @flow strict
 */

/**
 * LexicalCommands
 */

export type LexicalCommand<P> = $ReadOnly<{type?: string}>;

declare export var SELECTION_CHANGE_COMMAND: LexicalCommand<void>;
declare export var CLICK_COMMAND: LexicalCommand<MouseEvent>;
declare export var DELETE_CHARACTER_COMMAND: LexicalCommand<boolean>;
declare export var INSERT_LINE_BREAK_COMMAND: LexicalCommand<boolean>;
declare export var INSERT_PARAGRAPH_COMMAND: LexicalCommand<void>;
declare export var CONTROLLED_TEXT_INSERTION_COMMAND: LexicalCommand<string>;
declare export var PASTE_COMMAND: LexicalCommand<ClipboardEvent>;
declare export var REMOVE_TEXT_COMMAND: LexicalCommand<InputEvent | null>;
declare export var DELETE_WORD_COMMAND: LexicalCommand<boolean>;
declare export var DELETE_LINE_COMMAND: LexicalCommand<boolean>;
declare export var FORMAT_TEXT_COMMAND: LexicalCommand<TextFormatType>;
declare export var UNDO_COMMAND: LexicalCommand<void>;
declare export var REDO_COMMAND: LexicalCommand<void>;
declare export var KEY_DOWN_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_ARROW_RIGHT_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_ARROW_LEFT_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_ARROW_UP_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_ARROW_DOWN_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_ENTER_COMMAND: LexicalCommand<KeyboardEvent | null>;
declare export var KEY_SPACE_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_BACKSPACE_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_ESCAPE_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_DELETE_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var KEY_TAB_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var INSERT_TAB_COMMAND: LexicalCommand<void>;
declare export var KEY_MODIFIER_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var INDENT_CONTENT_COMMAND: LexicalCommand<void>;
declare export var OUTDENT_CONTENT_COMMAND: LexicalCommand<void>;
declare export var DROP_COMMAND: LexicalCommand<DragEvent>;
declare export var FORMAT_ELEMENT_COMMAND: LexicalCommand<ElementFormatType>;
declare export var DRAGSTART_COMMAND: LexicalCommand<DragEvent>;
declare export var DRAGOVER_COMMAND: LexicalCommand<DragEvent>;
declare export var DRAGEND_COMMAND: LexicalCommand<DragEvent>;
declare export var COPY_COMMAND: LexicalCommand<
  ClipboardEvent | KeyboardEvent | null,
>;
declare export var CUT_COMMAND: LexicalCommand<
  ClipboardEvent | KeyboardEvent | null,
>;
declare export var CLEAR_EDITOR_COMMAND: LexicalCommand<void>;
declare export var CLEAR_HISTORY_COMMAND: LexicalCommand<void>;
declare export var CAN_REDO_COMMAND: LexicalCommand<boolean>;
declare export var CAN_UNDO_COMMAND: LexicalCommand<boolean>;
declare export var FOCUS_COMMAND: LexicalCommand<FocusEvent>;
declare export var BLUR_COMMAND: LexicalCommand<FocusEvent>;
declare export var SELECT_ALL_COMMAND: LexicalCommand<KeyboardEvent>;
declare export var MOVE_TO_END: LexicalCommand<KeyboardEvent>;
declare export var MOVE_TO_START: LexicalCommand<KeyboardEvent>;
declare export var SELECTION_INSERT_CLIPBOARD_NODES_COMMAND: LexicalCommand<{
  nodes: Array<LexicalNode>;
  selection: BaseSelection;
}>;

declare export function createCommand<T>(type?: string): LexicalCommand<T>;

/**
 * LexicalConstants
 */

declare export var IS_ALL_FORMATTING: number;
declare export var IS_BOLD: number;
declare export var IS_CODE: number;
declare export var IS_HIGHLIGHT: number;
declare export var IS_ITALIC: number;
declare export var IS_STRIKETHROUGH: number;
declare export var IS_SUBSCRIPT: number;
declare export var IS_SUPERSCRIPT: number;
declare export var IS_UNDERLINE: number;
declare export var IS_UPPERCASE: number;
declare export var IS_LOWERCASE: number;
declare export var IS_CAPITALIZE: number;
declare export var TEXT_TYPE_TO_FORMAT: Record<TextFormatType | string, number>;

/**
 * LexicalEditor
 */
type IntentionallyMarkedAsDirtyElement = boolean;

type MutationListeners = Map<MutationListener, Class<LexicalNode>>;
export type NodeMutation = 'created' | 'updated' | 'destroyed';
type UpdateListener = ({
  tags: Set<string>,
  prevEditorState: EditorState,
  editorState: EditorState,
  dirtyLeaves: Set<NodeKey>,
  dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
  normalizedNodes: Set<NodeKey>,
}) => void;
type DecoratorListener = (decorator: {
  // $FlowFixMe: defined by user
  [NodeKey]: any,
}) => void;
type RootListener = (
  rootElement: null | HTMLElement,
  prevRootElement: null | HTMLElement,
) => void;
type TextContentListener = (text: string) => void;
type ErrorHandler = (error: Error) => void;
export type MutationListener = (
  nodes: Map<NodeKey, NodeMutation>,
  {
    updateTags: Set<string>,
    dirtyLeaves: Set<string>,
    prevEditorState: EditorState,
  },
) => void;
export type MutationListenerOptions = {
  skipInitialization?: boolean;
};
export type EditableListener = (editable: boolean) => void;
type Listeners = {
  decorator: Set<DecoratorListener>,
  mutation: MutationListeners,
  textcontent: Set<TextContentListener>,
  root: Set<RootListener>,
  update: Set<UpdateListener>,
};
export type CommandListener<P> = (payload: P, editor: LexicalEditor) => boolean;
// $FlowFixMe[unclear-type]
type Commands = Map<LexicalCommand<any>, Array<Set<CommandListener<any>>>>;
type RegisteredNodes = Map<string, RegisteredNode>;
type RegisteredNode = {
  klass: Class<LexicalNode>,
  transforms: Set<Transform<LexicalNode>>,
};
export type Transform<T> = (node: T) => void;

type DOMConversionCache = Map<
  string,
  Array<(node: Node) => DOMConversion | null>,
>;

export type CreateEditorArgs = {
  disableEvents?: boolean;
  editorState?: EditorState;
  namespace?: string;
  nodes?: $ReadOnlyArray<Class<LexicalNode> | LexicalNodeReplacement>;
  onError?: ErrorHandler;
  parentEditor?: LexicalEditor;
  editable?: boolean;
  theme?: EditorThemeClasses;
  html?: HTMLConfig;
};

declare export class LexicalEditor {
  _parentEditor: null | LexicalEditor;
  _rootElement: null | HTMLElement;
  _editorState: EditorState;
  _htmlConversions: DOMConversionCache;
  _pendingEditorState: null | EditorState;
  _compositionKey: null | NodeKey;
  _deferred: Array<() => void>;
  _updates: Array<[() => void, void | EditorUpdateOptions]>;
  _updating: boolean;
  _keyToDOMMap: Map<NodeKey, HTMLElement>;
  _listeners: Listeners;
  _commands: Commands;
  _nodes: RegisteredNodes;
  _onError: ErrorHandler;
  _decorators: {
    [NodeKey]: mixed,
  };
  _pendingDecorators: null | {
    [NodeKey]: mixed,
  };
  _createEditorArgs?: CreateEditorArgs;
  _config: EditorConfig;
  _dirtyType: 0 | 1 | 2;
  _cloneNotNeeded: Set<NodeKey>;
  _dirtyLeaves: Set<NodeKey>;
  _dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>;
  _normalizedNodes: Set<NodeKey>;
  _updateTags: Set<string>;
  _observer: null | MutationObserver;
  _key: string;
  _editable: boolean;
  _headless: boolean;
  isComposing(): boolean;
  registerUpdateListener(listener: UpdateListener): () => void;
  registerRootListener(listener: RootListener): () => void;
  registerDecoratorListener(listener: DecoratorListener): () => void;
  registerTextContentListener(listener: TextContentListener): () => void;
  registerCommand<P>(
    command: LexicalCommand<P>,
    listener: CommandListener<P>,
    priority: CommandListenerPriority,
  ): () => void;
  registerEditableListener(listener: EditableListener): () => void;
  registerMutationListener(
    klass: Class<LexicalNode>,
    listener: MutationListener,
    options?: MutationListenerOptions,
  ): () => void;
  registerNodeTransform<T: LexicalNode>(
    klass: Class<T>,
    listener: Transform<T>,
  ): () => void;
  dispatchCommand<P>(command: LexicalCommand<P>, payload: P): boolean;
  hasNode(node: Class<LexicalNode>): boolean;
  hasNodes(nodes: Array<Class<LexicalNode>>): boolean;
  getKey(): string;
  getDecorators<X>(): {
    [NodeKey]: X,
  };
  getRootElement(): null | HTMLElement;
  setRootElement(rootElement: null | HTMLElement): void;
  getElementByKey(key: NodeKey): null | HTMLElement;
  getEditorState(): EditorState;
  setEditorState(editorState: EditorState, options?: EditorSetOptions): void;
  parseEditorState(
    maybeStringifiedEditorState: string | SerializedEditorState,
    updateFn?: () => void,
  ): EditorState;
  read<V>(callbackFn: () => V, options?: EditorReadOptions): V;
  update(updateFn: () => void, options?: EditorUpdateOptions): boolean;
  focus(callbackFn?: () => void, options?: EditorFocusOptions): void;
  blur(): void;
  isEditable(): boolean;
  setEditable(editable: boolean): void;
  toJSON(): SerializedEditor;
}
type EditorReadOptions = {
  pending?: boolean,
};
type EditorUpdateOptions = {
  onUpdate?: () => void,
  tag?: string | Array<string>,
  skipTransforms?: true,
  discrete?: true,
};
type EditorFocusOptions = {
  defaultSelection?: 'rootStart' | 'rootEnd',
};
type EditorSetOptions = {
  tag?: string,
};
type EditorThemeClassName = string;
type TextNodeThemeClasses = {
  base?: EditorThemeClassName,
  bold?: EditorThemeClassName,
  underline?: EditorThemeClassName,
  strikethrough?: EditorThemeClassName,
  underlineStrikethrough?: EditorThemeClassName,
  italic?: EditorThemeClassName,
  code?: EditorThemeClassName,
  subscript?: EditorThemeClassName,
  superscript?: EditorThemeClassName,
  lowercase?: EditorThemeClassName,
  uppercase?: EditorThemeClassName,
  capitalize?: EditorThemeClassName,
};
export type EditorThemeClasses = {
  characterLimit?: EditorThemeClassName,
  ltr?: EditorThemeClassName,
  rtl?: EditorThemeClassName,
  text?: TextNodeThemeClasses,
  paragraph?: EditorThemeClassName,
  image?: EditorThemeClassName,
  list?: {
    ul?: EditorThemeClassName,
    ulDepth?: Array<EditorThemeClassName>,
    ol?: EditorThemeClassName,
    olDepth?: Array<EditorThemeClassName>,
    checklist?: EditorThemeClassName,
    listitem?: EditorThemeClassName,
    listitemChecked?: EditorThemeClassName,
    listitemUnchecked?: EditorThemeClassName,
    nested?: {
      list?: EditorThemeClassName,
      listitem?: EditorThemeClassName,
    },
  },
  table?: EditorThemeClassName,
  tableRow?: EditorThemeClassName,
  tableCell?: EditorThemeClassName,
  tableCellHeader?: EditorThemeClassName,
  mark?: EditorThemeClassName,
  markOverlap?: EditorThemeClassName,
  link?: EditorThemeClassName,
  quote?: EditorThemeClassName,
  code?: EditorThemeClassName,
  codeHighlight?: {[string]: EditorThemeClassName},
  hashtag?: EditorThemeClassName,
  heading?: {
    h1?: EditorThemeClassName,
    h2?: EditorThemeClassName,
    h3?: EditorThemeClassName,
    h4?: EditorThemeClassName,
    h5?: EditorThemeClassName,
    h6?: EditorThemeClassName,
  },
  embedBlock?: {
    base?: EditorThemeClassName,
    focus?: EditorThemeClassName,
  },
  // Handle other generic values
  [string]: EditorThemeClassName | {[string]: EditorThemeClassName},
};
export type EditorConfig = {
  theme: EditorThemeClasses,
  namespace: string,
  disableEvents?: boolean,
};
export type CommandListenerPriority = 0 | 1 | 2 | 3 | 4;
export const COMMAND_PRIORITY_EDITOR = 0;
export const COMMAND_PRIORITY_LOW = 1;
export const COMMAND_PRIORITY_NORMAL = 2;
export const COMMAND_PRIORITY_HIGH = 3;
export const COMMAND_PRIORITY_CRITICAL = 4;

export type LexicalNodeReplacement = {
  replace: Class<LexicalNode>,
  with: (node: LexicalNode) => LexicalNode,
  withKlass?: Class<LexicalNode>,
};

export type HTMLConfig = {
  export?: Map<
    Class<LexicalNode>,
    (editor: LexicalEditor, target: LexicalNode) => DOMExportOutput,
  >,
  import?: DOMConversionMap,
};

declare export function createEditor(editorConfig?: {
  editorState?: EditorState,
  namespace: string,
  theme?: EditorThemeClasses,
  parentEditor?: LexicalEditor,
  nodes?: $ReadOnlyArray<Class<LexicalNode> | LexicalNodeReplacement>,
  onError: (error: Error) => void,
  disableEvents?: boolean,
  editable?: boolean,
  html?: HTMLConfig,
}): LexicalEditor;

/**
 * LexicalEditorState
 */

export interface EditorState {
  _nodeMap: NodeMap;
  _selection: null | BaseSelection;
  _flushSync: boolean;
  _readOnly: boolean;
  constructor(nodeMap: NodeMap, selection?: BaseSelection | null): void;
  isEmpty(): boolean;
  read<V>(callbackFn: () => V, options?: EditorStateReadOptions): V;
  toJSON(): SerializedEditorState;
  clone(selection?: BaseSelection | null): EditorState;
}
type EditorStateReadOptions = {
  editor?: LexicalEditor | null;
}

/**
 * LexicalNode
 */

export type DOMConversion = {
  conversion: DOMConversionFn,
  priority: 0 | 1 | 2 | 3 | 4,
};
export type DOMConversionFn = (element: Node) => DOMConversionOutput | null;
export type DOMChildConversion = (
  lexicalNode: LexicalNode,
  parentLexicalNode: ?LexicalNode | null,
) => LexicalNode | null | void;
export type DOMConversionMap = {
  [NodeName]: <T: HTMLElement>(node: T) => DOMConversion | null,
};
type NodeName = string;
export type DOMConversionOutput = {
  after?: (childLexicalNodes: Array<LexicalNode>) => Array<LexicalNode>,
  forChild?: DOMChildConversion,
  node: null | LexicalNode | Array<LexicalNode>,
};
export type DOMExportOutput = {
  after?: (generatedElement: ?HTMLElement) => ?HTMLElement,
  element?: HTMLElement | null,
};
export type NodeKey = string;
declare export class LexicalNode {
  __type: string;
  __key: NodeKey;
  __parent: null | NodeKey;
  __next: null | NodeKey;
  __prev: null | NodeKey;
  static getType(): string;
  static clone(data: $FlowFixMe): LexicalNode;
  static importDOM(): DOMConversionMap | null;
  constructor(key?: NodeKey): void;
  exportDOM(editor: LexicalEditor): DOMExportOutput;
  exportJSON(): SerializedLexicalNode;
  updateFromJSON(serializedNode: $FlowFixMe): this;
  getType(): string;
  isAttached(): boolean;
  isSelected(): boolean;
  getKey(): NodeKey;
  getIndexWithinParent(): number;
  getParent<T: ElementNode>(): T | null;
  getParentOrThrow<T: ElementNode>(): T;
  getTopLevelElement(): DecoratorNode<mixed> | ElementNode | null;
  getTopLevelElementOrThrow(): DecoratorNode<mixed> | ElementNode;
  getParents<T: ElementNode>(): Array<T>;
  getParentKeys(): Array<NodeKey>;
  getPreviousSibling<T: LexicalNode>(): T | null;
  getPreviousSiblings<T: LexicalNode>(): Array<T>;
  getNextSibling<T: LexicalNode>(): T | null;
  getNextSiblings<T: LexicalNode>(): Array<T>;
  getCommonAncestor<T: ElementNode>(node: LexicalNode): T | null;
  is(object: ?LexicalNode): boolean;
  isBefore(targetNode: LexicalNode): boolean;
  isParentOf(targetNode: LexicalNode): boolean;
  getNodesBetween(targetNode: LexicalNode): Array<LexicalNode>;
  isDirty(): boolean;
  // $FlowFixMe[incompatible-type]
  getLatest<T: LexicalNode>(this: T): T;
  // $FlowFixMe[incompatible-type]
  getWritable<T: LexicalNode>(this: T): T;
  getTextContent(includeDirectionless?: boolean): string;
  getTextContentSize(includeDirectionless?: boolean): number;
  createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement;
  updateDOM(
    // $FlowFixMe[unclear-type]
    prevNode: any,
    dom: HTMLElement,
    config: EditorConfig,
  ): boolean;
  remove(preserveEmptyParent?: boolean): void;
  replace<N: LexicalNode>(replaceWith: N): N;
  insertAfter(
    nodeToInsert: LexicalNode,
    restoreSelection?: boolean,
  ): LexicalNode;
  insertBefore(
    nodeToInsert: LexicalNode,
    restoreSelection?: boolean,
  ): LexicalNode;
  selectPrevious(anchorOffset?: number, focusOffset?: number): RangeSelection;
  selectNext(anchorOffset?: number, focusOffset?: number): RangeSelection;
  markDirty(): void;
  reconcileObservedMutation(dom: HTMLElement, editor: LexicalEditor): void;
}
export type NodeMap = Map<NodeKey, LexicalNode>;

/**
 * LexicalSelection
 */

declare export function $isBlockElementNode(
  node: ?LexicalNode,
): node is ElementNode;

export interface BaseSelection {
  dirty: boolean;
  clone(): BaseSelection;
  extract(): Array<LexicalNode>;
  getNodes(): Array<LexicalNode>;
  getStartEndPoints(): null | [PointType, PointType];
  getTextContent(): string;
  insertRawText(text: string): void;
  is(selection: null | BaseSelection): boolean;
  isBackward(): boolean;
  isCollapsed(): boolean;
  insertText(text: string): void;
  insertNodes(nodes: Array<LexicalNode>): void;
  getCachedNodes(): null | Array<LexicalNode>;
  setCachedNodes(nodes: null | Array<LexicalNode>): void;
}

declare export class NodeSelection implements BaseSelection {
  _nodes: Set<NodeKey>;
  dirty: boolean;
  constructor(objects: Set<NodeKey>): void;
  is(selection: null | BaseSelection): boolean;
  isBackward(): boolean;
  isCollapsed(): boolean;
  add(key: NodeKey): void;
  delete(key: NodeKey): void;
  clear(): void;
  has(key: NodeKey): boolean;
  clone(): NodeSelection;
  extract(): Array<LexicalNode>;
  insertRawText(): void;
  insertText(): void;
  getNodes(): Array<LexicalNode>;
  getStartEndPoints(): null;
  getTextContent(): string;
  insertNodes(nodes: Array<LexicalNode>): void;
  getCachedNodes(): null | Array<LexicalNode>;
  setCachedNodes(nodes: null | Array<LexicalNode>): void;
}

declare export function $isNodeSelection(
  x: ?mixed,
): x is NodeSelection;

declare export class RangeSelection implements BaseSelection {
  anchor: PointType;
  focus: PointType;
  dirty: boolean;
  format: number;
  style: string;
  constructor(anchor: PointType, focus: PointType, format: number): void;
  is(selection: null | BaseSelection): boolean;
  isBackward(): boolean;
  isCollapsed(): boolean;
  getNodes(): Array<LexicalNode>;
  setTextNodeRange(
    anchorNode: TextNode,
    anchorOffset: number,
    focusNode: TextNode,
    focusOffset: number,
  ): void;
  getTextContent(): string;
  // $FlowFixMe[cannot-resolve-name] DOM API
  applyDOMRange(range: StaticRange): void;
  clone(): RangeSelection;
  toggleFormat(format: TextFormatType): void;
  setStyle(style: string): void;
  hasFormat(type: TextFormatType): boolean;
  insertText(text: string): void;
  insertRawText(text: string): void;
  removeText(): void;
  formatText(formatType: TextFormatType): void;
  insertNodes(nodes: Array<LexicalNode>): void;
  insertParagraph(): void;
  insertLineBreak(selectStart?: boolean): void;
  extract(): Array<LexicalNode>;
  modify(
    alter: 'move' | 'extend',
    isBackward: boolean,
    granularity: 'character' | 'word' | 'lineboundary',
  ): void;
  deleteCharacter(isBackward: boolean): void;
  deleteLine(isBackward: boolean): void;
  deleteWord(isBackward: boolean): void;
  insertNodes(nodes: Array<LexicalNode>): void;
  getCachedNodes(): null | Array<LexicalNode>;
  setCachedNodes(nodes: null | Array<LexicalNode>): void;
  forwardDeletion(anchor: PointType, anchorNode: ElementNode | TextNode, isBackward: boolean): boolean;
  getStartEndPoints(): null | [PointType, PointType];
}
export type TextPoint = TextPointType;
type TextPointType = {
  key: NodeKey,
  offset: number,
  type: 'text',
  is: (PointType) => boolean,
  isBefore: (PointType) => boolean,
  getNode: () => TextNode,
  set: (key: NodeKey, offset: number, type: 'text' | 'element') => void,
  getCharacterOffset: () => number,
};
export type ElementPoint = ElementPointType;
type ElementPointType = {
  key: NodeKey,
  offset: number,
  type: 'element',
  is: (PointType) => boolean,
  isBefore: (PointType) => boolean,
  getNode: () => ElementNode,
  set: (key: NodeKey, offset: number, type: 'text' | 'element') => void,
};
export type Point = PointType;
export type PointType = TextPointType | ElementPointType;
declare class _Point {
  key: NodeKey;
  offset: number;
  type: 'text' | 'element';
  constructor(key: NodeKey, offset: number, type: 'text' | 'element'): void;
  is(point: PointType): boolean;
  isBefore(b: PointType): boolean;
  getNode(): LexicalNode;
  set(key: NodeKey, offset: number, type: 'text' | 'element', onlyIfChanged?: boolean): void;
}

declare export function $createRangeSelection(): RangeSelection;
declare export function $createNodeSelection(): NodeSelection;
declare export function $isRangeSelection(
  x: ?mixed,
): x is RangeSelection;
declare export function $getSelection(): null | BaseSelection;
declare export function $getPreviousSelection(): null | BaseSelection;
declare export function $insertNodes(nodes: Array<LexicalNode>): void;
declare export function $getCharacterOffsets(
  selection: BaseSelection,
): [number, number];


/**
 * LexicalTextNode
 */

export type TextFormatType =
  | 'bold'
  | 'underline'
  | 'strikethrough'
  | 'italic'
  | 'highlight'
  | 'code'
  | 'subscript'
  | 'superscript'
  | 'lowercase'
  | 'uppercase'
  | 'capitalize';

type TextModeType = 'normal' | 'token' | 'segmented';

declare export class TextNode extends LexicalNode {
  __text: string;
  __format: number;
  __style: string;
  __mode: 0 | 1 | 2 | 3;
  __detail: number;
  static getType(): string;
  static clone(node: $FlowFixMe): TextNode;
  constructor(text: string, key?: NodeKey): void;
  getTopLevelElement(): ElementNode | null;
  getTopLevelElementOrThrow(): ElementNode;
  getFormat(): number;
  getStyle(): string;
  isComposing(): boolean;
  isInline(): true;
  isToken(): boolean;
  isSegmented(): boolean;
  isDirectionless(): boolean;
  isUnmergeable(): boolean;
  hasFormat(type: TextFormatType): boolean;
  isSimpleText(): boolean;
  getTextContent(): string;
  getFormatFlags(type: TextFormatType, alignWithFormat: null | number): number;
  createDOM(config: EditorConfig): HTMLElement;
  selectionTransform(
    prevSelection: null | BaseSelection,
    nextSelection: RangeSelection,
  ): void;
  setFormat(format: number): this;
  setStyle(style: string): this;
  toggleFormat(type: TextFormatType): TextNode;
  toggleDirectionless(): this;
  toggleUnmergeable(): this;
  setMode(type: TextModeType): this;
  setDetail(detail: number): this;
  getDetail(): number;
  getMode(): TextModeType;
  setTextContent(text: string): TextNode;
  select(_anchorOffset?: number, _focusOffset?: number): RangeSelection;
  spliceText(
    offset: number,
    delCount: number,
    newText: string,
    moveSelection?: boolean,
  ): TextNode;
  canInsertTextBefore(): boolean;
  canInsertTextAfter(): boolean;
  splitText(...splitOffsets: Array<number>): Array<TextNode>;
  mergeWithSibling(target: TextNode): TextNode;
  isTextEntity(): boolean;
  static importJSON(serializedTextNode: SerializedTextNode): TextNode;
  exportJSON(): SerializedTextNode;
}
declare export function $createTextNode(text?: string): TextNode;
declare export function $isTextNode(
  node: ?LexicalNode,
): node is TextNode;

/**
 * LexicalTabNode
 */

export type SerializedTabNode = SerializedTextNode;

declare export function $createTabNode(): TabNode;

declare export function $isTabNode(
  node: LexicalNode | null | void,
): node is TabNode;

declare export class TabNode extends TextNode {
  static getType(): string;
  static clone(node: TabNode): TabNode;
  constructor(key?: NodeKey): void;
  static importDOM(): DOMConversionMap | null;
  static importJSON(serializedTabNode: SerializedTabNode): TabNode;
  exportJSON(): SerializedTabNode;
}

/**
 * LexicalLineBreakNode
 */

declare export class LineBreakNode extends LexicalNode {
  static getType(): string;
  static clone(node: LineBreakNode): LineBreakNode;
  constructor(key?: NodeKey): void;
  getTextContent(): '\n';
  createDOM(): HTMLElement;
  updateDOM(): false;
  isInline(): true;
  static importJSON(
    serializedLineBreakNode: SerializedLineBreakNode,
  ): LineBreakNode;
  exportJSON(): SerializedLexicalNode;
}
declare export function $createLineBreakNode(): LineBreakNode;
declare export function $isLineBreakNode(
  node: ?LexicalNode,
): node is LineBreakNode;

/**
 * LexicalRootNode
 */

declare export class RootNode extends ElementNode {
  __cachedText: null | string;
  static getType(): string;
  static clone(): RootNode;
  constructor(): void;
  getTextContent(): string;
  select(_anchorOffset?: number, _focusOffset?: number): RangeSelection;
  remove(): void;
  replace<N: LexicalNode>(node: N): N;
  insertBefore<T: LexicalNode>(nodeToInsert: T): T;
  insertAfter<T: LexicalNode>(nodeToInsert: T): T;
  append(...nodesToAppend: Array<LexicalNode>): this;
  canBeEmpty(): false;
}
declare export function $isRootNode(
  node: ?LexicalNode,
): node is RootNode;

/**
 * LexicalElementNode
 */
export type ElementFormatType =
  | 'left'
  | 'start'
  | 'center'
  | 'right'
  | 'end'
  | 'justify'
  | '';
declare export class ElementNode extends LexicalNode {
  __first: null | NodeKey;
  __last: null | NodeKey;
  __size: number;
  __format: number;
  __indent: number;
  __dir: 'ltr' | 'rtl' | null;
  constructor(key?: NodeKey): void;
  getTopLevelElement(): ElementNode | null;
  getTopLevelElementOrThrow(): ElementNode;
  getFormat(): number;
  getFormatType(): ElementFormatType;
  getIndent(): number;
  getChildren<T: LexicalNode>(): Array<T>;
  getChildren<T: Array<LexicalNode>>(): T;
  getChildrenKeys(): Array<NodeKey>;
  getChildrenSize(): number;
  isEmpty(): boolean;
  isDirty(): boolean;
  getAllTextNodes(): Array<TextNode>;
  getFirstDescendant<T: LexicalNode>(): null | T;
  getLastDescendant<T: LexicalNode>(): null | T;
  getDescendantByIndex<T: LexicalNode>(index: number): null | T;
  getFirstChild<T: LexicalNode>(): null | T;
  getFirstChildOrThrow<T: LexicalNode>(): T;
  getLastChild<T: LexicalNode>(): null | T;
  getLastChildOrThrow<T: LexicalNode>(): T;
  getChildAtIndex<T: LexicalNode>(index: number): null | T;
  getTextContent(): string;
  getDirection(): 'ltr' | 'rtl' | null;
  hasFormat(type: ElementFormatType): boolean;
  select(_anchorOffset?: number, _focusOffset?: number): RangeSelection;
  selectStart(): RangeSelection;
  selectEnd(): RangeSelection;
  clear(): this;
  append(...nodesToAppend: Array<LexicalNode>): this;
  setDirection(direction: 'ltr' | 'rtl' | null): this;
  setFormat(type: ElementFormatType): this;
  setIndent(indentLevel: number): this;
  insertNewAfter(
    selection: RangeSelection,
    restoreSelection?: boolean,
  ): null | LexicalNode;
  canIndent(): boolean;
  collapseAtStart(selection: RangeSelection): boolean;
  excludeFromCopy(destination: 'clone' | 'html'): boolean;
  canReplaceWith(replacement: LexicalNode): boolean;
  canInsertAfter(node: LexicalNode): boolean;
  extractWithChild(
    child: LexicalNode,
    selection: BaseSelection,
    destination: 'clone' | 'html',
  ): boolean;
  canBeEmpty(): boolean;
  canInsertTextBefore(): boolean;
  canInsertTextAfter(): boolean;
  isInline(): boolean;
  isShadowRoot(): boolean;
  canSelectionRemove(): boolean;
  splice(
    start: number,
    deleteCount: number,
    nodesToInsert: Array<LexicalNode>,
  ): this;
  exportJSON(): SerializedElementNode;
  getDOMSlot(dom: HTMLElement): ElementDOMSlot<HTMLElement>;
}
declare export function $isElementNode(
  node: ?LexicalNode,
): node is ElementNode;

/**
 * ElementDOMSlot
 */
declare export class ElementDOMSlot<+T: HTMLElement> {
  +element: HTMLElement;
  +before: Node | null;
  +after: Node | null;
  constructor(element: HTMLElement, before?: Node | null | void, after?: Node | null | void): void;
  withBefore(before: Node | null | void): ElementDOMSlot<T>;
  withAfter(after: Node | null | void): ElementDOMSlot<T>;
  withElement<ElementType: HTMLElement>(element: ElementType): ElementDOMSlot<ElementType>;
  insertChild(dom: Node): this;
  removeChild(dom: Node): this;
  replaceChild(dom: Node, prevDom: Node): this;
  getFirstChild(): Node | null;
  //
  getManagedLineBreak(): HTMLElement | null;
  removeManagedLineBreak(): void;
  insertManagedLineBreak(webkitHack: boolean): void;
  getFirstChildOffset(): number;
  resolveChildIndex(element: ElementNode, elementDOM: HTMLElement, initialDOM: Node, initialOffset: number): [node: ElementNode, idx: number];
}

declare export function setDOMUnmanaged(elementDOM: HTMLElement): void;
declare export function isDOMUnmanaged(elementDOM: HTMLElement): boolean;

/**
 * LexicalDecoratorNode
 */

declare export class DecoratorNode<X> extends LexicalNode {
  constructor(key?: NodeKey): void;
  // Not sure how to get flow to agree that the DecoratorNode<mixed> is compatible with this,
  // so we have a less precise type than in TS
  // getTopLevelElement(): this | ElementNode | null;
  // getTopLevelElementOrThrow(): this | ElementNode;
  decorate(editor: LexicalEditor, config: EditorConfig): X;
  isIsolated(): boolean;
  isInline(): boolean;
  isKeyboardSelectable(): boolean;
}
declare export function $isDecoratorNode<T = mixed>(
  node: ?LexicalNode,
): node is DecoratorNode<T>;

/**
 * LexicalParagraphNode
 */
declare export class ParagraphNode extends ElementNode {
  static getType(): string;
  static clone(node: ParagraphNode): ParagraphNode;
  constructor(key?: NodeKey): void;
  createDOM(config: EditorConfig): HTMLElement;
  insertNewAfter(
    selection: RangeSelection,
    restoreSelection?: boolean,
  ): ParagraphNode;
  collapseAtStart(): boolean;
  static importJSON(
    serializedParagraphNode: SerializedParagraphNode,
  ): ParagraphNode;
  exportJSON(): SerializedElementNode;
}
declare export function $createParagraphNode(): ParagraphNode;
declare export function $isParagraphNode(
  node: ?LexicalNode,
): node is ParagraphNode;

/**
 * LexicalUtils
 */
export type EventHandler = (event: Event, editor: LexicalEditor) => void;
declare export function $hasUpdateTag(tag: string): boolean;
declare export function $addUpdateTag(tag: string): void;
declare export function $onUpdate(updateFn: () => void): void;
declare export function getNearestEditorFromDOMNode(
  node: Node | null,
): LexicalEditor | null;
declare export function $getNearestNodeFromDOMNode(
  startingDOM: Node,
): LexicalNode | null;
declare export function $getNodeByKey<N: LexicalNode>(key: NodeKey): N | null;
declare export function $getNodeByKeyOrThrow<N: LexicalNode>(key: NodeKey): N;
declare export function $getRoot(): RootNode;
declare export function $isLeafNode<T = mixed>(
  node: ?LexicalNode,
): node is TextNode | LineBreakNode |  DecoratorNode<T>;
declare export function $setCompositionKey(
  compositionKey: null | NodeKey,
): void;
declare export function $setSelection(selection: null | BaseSelection): void;
declare export function $nodesOfType<T: LexicalNode>(klass: Class<T>): Array<T>;
declare export function $getAdjacentNode(
  focus: Point,
  isBackward: boolean,
): null | LexicalNode;
declare export function resetRandomKey(): void;
declare export function generateRandomKey(): string;
declare export function $isInlineElementOrDecoratorNode<T = mixed>(
  node: LexicalNode,
): node is ElementNode|  DecoratorNode<T>;
declare export function $getNearestRootOrShadowRoot(
  node: LexicalNode,
): RootNode | ElementNode;
declare export function $isRootOrShadowRoot(
  node: ?LexicalNode,
): node is RootNode | ElementNode;
declare export function $hasAncestor(
  child: LexicalNode,
  targetNode: LexicalNode,
): boolean;
declare export function $cloneWithProperties<T: LexicalNode>(node: T): T;
declare export function $copyNode(
  node: ElementNode,
  offset: number,
): [ElementNode, ElementNode];
declare export function $getEditor(): LexicalEditor;

/**
 * LexicalNormalization
 */

declare export function $normalizeSelection__EXPERIMENTAL(
  selection: RangeSelection,
): RangeSelection;

/**
 * Serialization/Deserialization
 * */

type InternalSerializedNode = {
  children?: Array<InternalSerializedNode>,
  type: string,
  version: number,
};

declare export function $parseSerializedNode(
  serializedNode: InternalSerializedNode,
): LexicalNode;

declare export function $applyNodeReplacement<N: LexicalNode>(
  node: LexicalNode,
): N;

export type SerializedLexicalNode = {
  type: string,
  version: number,
  ...
};

export type SerializedTextNode = {
  ...SerializedLexicalNode,
  detail: number,
  format: number,
  mode: TextModeType,
  style: string,
  text: string,
  ...
};

export type SerializedElementNode = {
  ...SerializedLexicalNode,
  children: Array<SerializedLexicalNode>,
  direction: 'ltr' | 'rtl' | null,
  format: ElementFormatType,
  indent: number,
  ...
};

export type SerializedParagraphNode = {
  ...SerializedElementNode,
  ...
};

export type SerializedLineBreakNode = {
  ...SerializedLexicalNode,
  ...
};

export type SerializedDecoratorNode = {
  ...SerializedLexicalNode,
  ...
};

export type SerializedRootNode = {
  ...SerializedElementNode,
  ...
};

export type SerializedGridCellNode = {
  ...SerializedElementNode,
  colSpan: number,
  ...
};

export interface SerializedEditorState {
  root: SerializedRootNode;
}

export type SerializedEditor = {
  editorState: SerializedEditorState,
};

/**
 * LexicalCaret
 */
export interface BaseCaret<T: LexicalNode, D: CaretDirection, Type> extends Iterable<SiblingCaret<LexicalNode, D>> {
  +origin: T;
  +type: Type;
  +direction: D;
  getParentAtCaret(): null | ElementNode;
  getNodeAtCaret(): null | LexicalNode;
  getAdjacentCaret(): null | SiblingCaret<LexicalNode, D>;
  getSiblingCaret(): SiblingCaret<T, D>;
  remove(): BaseCaret<T, D, Type>; // this
  insert(node: LexicalNode): BaseCaret<T, D, Type>; // this
  replaceOrInsert(node: LexicalNode, includeChildren?: boolean): BaseCaret<T, D, Type>; // this
  splice(deleteCount: number, nodes: Iterable<LexicalNode>, nodesDirection?: CaretDirection): BaseCaret<T, D, Type>; // this
}
export type CaretDirection = 'next' | 'previous';
type FLIP_DIRECTION = {'next' : 'previous', 'previous': 'next'};
export interface CaretRange<D: CaretDirection = CaretDirection> extends Iterable<NodeCaret<D>> {
  +type: 'node-caret-range';
  +direction: D;
  anchor: PointCaret<D>;
  focus: PointCaret<D>;
  isCollapsed(): boolean;
  iterNodeCarets(rootMode?: RootMode): Iterable<NodeCaret<D>>;
  getTextSlices(): TextPointCaretSliceTuple<D>;
}
export type CaretType = 'sibling' | 'child';
export interface ChildCaret<T: ElementNode = ElementNode, D: CaretDirection = CaretDirection> extends BaseCaret<T, D, 'child'> {
  getLatest(): ChildCaret<T, D>;
  getParentCaret(mode?: RootMode): null | SiblingCaret<T, D>;
  getParentAtCaret(): T;
  getChildCaret(): ChildCaret<T, D>;
  isSameNodeCaret(other: null | void | PointCaret<CaretDirection>): boolean; // other is ChildCaret<T, D>;
  isSamePointCaret(other: null | void | PointCaret<CaretDirection>): boolean; // other is ChildCaret<T, D>;
  getFlipped(): NodeCaret<FlipDirection<D>>;
  // Refine chained types
  remove(): ChildCaret<T, D>;
  insert(node: LexicalNode): ChildCaret<T, D>;
  replaceOrInsert(node: LexicalNode, includeChildren?: boolean): ChildCaret<T, D>;
  splice(deleteCount: number, nodes: Iterable<LexicalNode>, nodesDirection?: CaretDirection): ChildCaret<T, D>;
}
export type FlipDirection<D: CaretDirection> = FLIP_DIRECTION[D];
export type NodeCaret<D: CaretDirection = CaretDirection> = ChildCaret<ElementNode, D> | SiblingCaret<LexicalNode, D>;
export type PointCaret<D: CaretDirection = CaretDirection> = ChildCaret<ElementNode, D> | SiblingCaret<LexicalNode, D> | TextPointCaret<TextNode, D>;
export type RootMode = 'root' | 'shadowRoot';
export interface SiblingCaret<T: LexicalNode = LexicalNode, D: CaretDirection = CaretDirection> extends BaseCaret<T, D, 'sibling'> {
  getLatest(): SiblingCaret<T, D>;
  getChildCaret(): null | ChildCaret<T & ElementNode, D>;
  getParentCaret(mode?: RootMode): null | SiblingCaret<ElementNode, D>;
  isSameNodeCaret(other: null | void | PointCaret<CaretDirection>): boolean; // </CaretDirection>other is SiblingCaret<T, D> | T extends TextNode ? TextPointCaret<T & TextNode, D> : empty;
  isSamePointCaret(other: null | void | PointCaret<CaretDirection>): boolean; // other is SiblingCaret<T, D>;
  getFlipped(): NodeCaret<FlipDirection<D>>;
  // Refine chained types
  remove(): SiblingCaret<T, D>;
  insert(node: LexicalNode): SiblingCaret<T, D>;
  replaceOrInsert(node: LexicalNode, includeChildren?: boolean): SiblingCaret<T, D>;
  splice(deleteCount: number, nodes: Iterable<LexicalNode>, nodesDirection?: CaretDirection): SiblingCaret<T, D>;
}
export interface StepwiseIteratorConfig<State, Stop, Value> {
  +initial: State | Stop;
  +hasNext: (value: State | Stop) => implies value is State;
  +step: (value: State) => State | Stop;
  +map: (value: State) => Value;
}
export interface TextPointCaret<T: TextNode = TextNode, D: CaretDirection = CaretDirection> extends BaseCaret<T, D, 'text'> {
  +offset: number;
  getLatest(): TextPointCaret<T, D>;
  getChildCaret(): null;
  getParentCaret(): null | SiblingCaret<ElementNode, D>;
  isSameNodeCaret(other: null | void | PointCaret<CaretDirection>): boolean; // other is TextPointCaret<T, D> | SiblingCaret<T, D>;
  isSamePointCaret(other: null | void | PointCaret<CaretDirection>): boolean; // other is TextPointCaret<T, D>;
  getFlipped(): TextPointCaret<T, FlipDirection<D>>;
}
export interface TextPointCaretSlice<T: TextNode = TextNode, D: CaretDirection = CaretDirection> {
  +type: 'slice';
  +caret: TextPointCaret<T, D>;
  +distance: number;
  getSliceIndices(): [startIndex: number, endIndex: number];
  getTextContent(): string;
  getTextContentSize(): number;
  removeTextSlice(): TextPointCaret<T, D>;
}
export type TextPointCaretSliceTuple<D: CaretDirection> = [
  +anchorSlice: null | TextPointCaretSlice<TextNode, D>,
  +focusSlice: null | TextPointCaretSlice<TextNode, D>,
];
declare export function $getAdjacentChildCaret<D: CaretDirection>(caret: null | NodeCaret<D>): null | NodeCaret<D>;
declare export function $getCaretRange<D: CaretDirection>(anchor: PointCaret<D>, focus: PointCaret<D>): CaretRange<D>;
declare export function $getChildCaret<T: null | ElementNode, D: CaretDirection>(origin: T, direction: D): ChildCaret<Exclude<null, T>, D> | Extract<null, T>;
declare export function $getChildCaretOrSelf<Caret: null | PointCaret<CaretDirection>>(caret: Caret): Caret | ChildCaret<ElementNode, Exclude<null, Caret>['direction']>;
declare export function $getSiblingCaret<T: null | LexicalNode, D: CaretDirection>(origin: T, direction: D): SiblingCaret<Exclude<null, T>, D> | Extract<null, T>;
declare export function $getTextNodeOffset(origin: TextNode, offset: number | CaretDirection): number;
declare export function $getTextPointCaret<T: null | TextNode, D: CaretDirection>(origin: T, direction: D, offset: number | CaretDirection): TextPointCaret<Exclude<null, T>, D> | Extract<null, T>;
declare export function $getTextPointCaretSlice<T: TextNode, D: CaretDirection>(caret: TextPointCaret<T, D>, distance: number): TextPointCaretSlice<T, D>;
declare export function $isChildCaret<D: CaretDirection>(caret: null | void | PointCaret<D>): caret is ChildCaret<ElementNode, D>;
declare export function $isNodeCaret<D: CaretDirection>(caret: null | void | PointCaret<D>): caret is NodeCaret<D>;
declare export function $isSiblingCaret<D: CaretDirection>(caret: null | void | PointCaret<D>): caret is SiblingCaret<LexicalNode, D>;
declare export function $isTextPointCaret<D: CaretDirection>(caret: null | void | PointCaret<D>): caret is TextPointCaret<TextNode, D>;
declare export function $isTextPointCaretSlice<D: CaretDirection>(caret: null | void | PointCaret<D> | TextPointCaretSlice<TextNode, D>): caret is TextPointCaretSlice<TextNode, D>;
declare export function flipDirection<D: CaretDirection>(direction: D): FlipDirection<D>;
declare export function makeStepwiseIterator<State, Stop, Value>(
  config: StepwiseIteratorConfig<State, Stop, Value>,
): Iterator<Value>;
/**
 * LexicalCaretUtils
 */
declare export function $caretFromPoint<D: CaretDirection>(
  point: PointType,
  direction: D,
): PointCaret<D>;
declare export function $caretRangeFromSelection(
  selection: RangeSelection,
): CaretRange<CaretDirection>;
declare export function $getAdjacentSiblingOrParentSiblingCaret<
  D: CaretDirection,
>(
  startCaret: NodeCaret<D>,
  rootMode?: RootMode
): null | [NodeCaret<D>, number]
declare export function $getCaretInDirection<
  Caret: PointCaret<CaretDirection>,
  D: CaretDirection,
>(
  caret: Caret,
  direction: D,
):
  | NodeCaret<D>
  | (Caret extends TextPointCaret<TextNode, CaretDirection>
      ? TextPointCaret<TextNode, D>
      : empty);
declare export function $getCaretRangeInDirection<D: CaretDirection>(
  range: CaretRange<CaretDirection>,
  direction: D,
): CaretRange<D>;
declare export function $getChildCaretAtIndex<D: CaretDirection>(
  parent: ElementNode,
  index: number,
  direction: D,
): NodeCaret<D>;
declare export function $normalizeCaret<D: CaretDirection>(
  initialCaret: PointCaret<D>,
): PointCaret<D>;
declare export function $removeTextFromCaretRange<D: CaretDirection>(
  initialRange: CaretRange<D>,
  sliceMode?:
    | 'removeEmptySlices'
    | 'preserveEmptyTextSliceCaret'
): CaretRange<D>;
declare export function $rewindSiblingCaret<
  T: LexicalNode,
  D: CaretDirection,
>(caret: SiblingCaret<T, D>): NodeCaret<D>;
declare export function $setPointFromCaret<D: CaretDirection>(
  point: PointType,
  caret: PointCaret<D>,
): void;
declare export function $setSelectionFromCaretRange(
  caretRange: CaretRange<CaretDirection>,
): RangeSelection;
declare export function $updateRangeSelectionFromCaretRange(
  selection: RangeSelection,
  caretRange: CaretRange<CaretDirection>,
): void;

export type CommonAncestorResult<
  A: LexicalNode,
  B: LexicalNode,
> =
  | CommonAncestorResultSame<A>
  | CommonAncestorResultAncestor<A & ElementNode>
  | CommonAncestorResultDescendant<B & ElementNode>
  | CommonAncestorResultBranch<A, B>;
export interface CommonAncestorResultBranch<
  A: LexicalNode,
  B: LexicalNode,
> {
  +type: 'branch';
  +commonAncestor: ElementNode;
  +a: A | ElementNode;
  +b: B | ElementNode;
}
export interface CommonAncestorResultAncestor<A: ElementNode> {
  +type: 'ancestor';
  +commonAncestor: A;
}
export interface CommonAncestorResultDescendant<B: ElementNode> {
  +type: 'descendant';
  +commonAncestor: B;
}
export interface CommonAncestorResultSame<A: LexicalNode> {
  +type: 'same';
  +commonAncestor: A;
}
declare export function $comparePointCaretNext(
  a: PointCaret<'next'>,
  b: PointCaret<'next'>,
): -1 | 0 | 1;
declare export function $getCommonAncestorResultBranchOrder<
  A: LexicalNode,
  B: LexicalNode,
>(compare: CommonAncestorResultBranch<A, B>): -1 | 1 ;
declare export function $getCommonAncestor<
  A: LexicalNode,
  B: LexicalNode,
>(a: A, b: B): null | CommonAncestorResult<A, B>;
declare export function $extendCaretToRange<D: CaretDirection>(
  anchor: PointCaret<D>,
): CaretRange<D>;
declare export function $getCollapsedCaretRange<D: CaretDirection>(
  anchor: PointCaret<D>,
): CaretRange<D>;
declare export function $isExtendableTextPointCaret<D: CaretDirection>(
  caret: PointCaret<D>
): implies caret is TextPointCaret<TextNode, D>;

export interface SplitAtPointCaretNextOptions {
  $copyElementNode?: (node: ElementNode) => ElementNode;
  $splitTextPointCaretNext?: (
    caret: TextPointCaret<TextNode, 'next'>,
  ) => NodeCaret<'next'>;
  rootMode?: RootMode;
  $shouldSplit?: (node: ElementNode, edge: 'first' | 'last') => boolean;
}
declare export function $splitAtPointCaretNext(
  pointCaret: PointCaret<'next'>,
  options?: SplitAtPointCaretNextOptions,
): null | NodeCaret<'next'>;