/** * 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'>;