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

= $ReadOnly<{type?: string}>; declare export var SELECTION_CHANGE_COMMAND: LexicalCommand; declare export var CLICK_COMMAND: LexicalCommand; declare export var DELETE_CHARACTER_COMMAND: LexicalCommand; declare export var INSERT_LINE_BREAK_COMMAND: LexicalCommand; declare export var INSERT_PARAGRAPH_COMMAND: LexicalCommand; declare export var CONTROLLED_TEXT_INSERTION_COMMAND: LexicalCommand; declare export var PASTE_COMMAND: LexicalCommand; declare export var REMOVE_TEXT_COMMAND: LexicalCommand; declare export var DELETE_WORD_COMMAND: LexicalCommand; declare export var DELETE_LINE_COMMAND: LexicalCommand; declare export var FORMAT_TEXT_COMMAND: LexicalCommand; declare export var UNDO_COMMAND: LexicalCommand; declare export var REDO_COMMAND: LexicalCommand; declare export var KEY_DOWN_COMMAND: LexicalCommand; declare export var KEY_ARROW_RIGHT_COMMAND: LexicalCommand; declare export var KEY_ARROW_LEFT_COMMAND: LexicalCommand; declare export var KEY_ARROW_UP_COMMAND: LexicalCommand; declare export var KEY_ARROW_DOWN_COMMAND: LexicalCommand; declare export var KEY_ENTER_COMMAND: LexicalCommand; declare export var KEY_SPACE_COMMAND: LexicalCommand; declare export var KEY_BACKSPACE_COMMAND: LexicalCommand; declare export var KEY_ESCAPE_COMMAND: LexicalCommand; declare export var KEY_DELETE_COMMAND: LexicalCommand; declare export var KEY_TAB_COMMAND: LexicalCommand; declare export var INSERT_TAB_COMMAND: LexicalCommand; declare export var KEY_MODIFIER_COMMAND: LexicalCommand; declare export var INDENT_CONTENT_COMMAND: LexicalCommand; declare export var OUTDENT_CONTENT_COMMAND: LexicalCommand; declare export var DROP_COMMAND: LexicalCommand; declare export var FORMAT_ELEMENT_COMMAND: LexicalCommand; declare export var DRAGSTART_COMMAND: LexicalCommand; declare export var DRAGOVER_COMMAND: LexicalCommand; declare export var DRAGEND_COMMAND: LexicalCommand; 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; declare export var CLEAR_HISTORY_COMMAND: LexicalCommand; declare export var CAN_REDO_COMMAND: LexicalCommand; declare export var CAN_UNDO_COMMAND: LexicalCommand; declare export var FOCUS_COMMAND: LexicalCommand; declare export var BLUR_COMMAND: LexicalCommand; declare export var SELECT_ALL_COMMAND: LexicalCommand; declare export var MOVE_TO_END: LexicalCommand; declare export var MOVE_TO_START: LexicalCommand; declare export var SELECTION_INSERT_CLIPBOARD_NODES_COMMAND: LexicalCommand<{ nodes: Array; selection: BaseSelection; }>; declare export function createCommand(type?: string): LexicalCommand; /** * 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; /** * LexicalEditor */ type IntentionallyMarkedAsDirtyElement = boolean; type MutationListeners = Map>; export type NodeMutation = 'created' | 'updated' | 'destroyed'; export type UpdateListenerPayload = { tags: Set, prevEditorState: EditorState, editorState: EditorState, dirtyLeaves: Set, dirtyElements: Map, normalizedNodes: Set, }; export type UpdateListener = (payload: UpdateListenerPayload) => void; type DecoratorListener = (decorator: { // $FlowFixMe[unclear-type]: 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, { updateTags: Set, dirtyLeaves: Set, prevEditorState: EditorState, }, ) => void; export type MutationListenerOptions = { skipInitialization?: boolean; }; export type EditableListener = (editable: boolean) => void; type Listeners = { decorator: Set, mutation: MutationListeners, textcontent: Set, root: Set, update: Set, }; export type CommandListener

= (payload: P, editor: LexicalEditor) => boolean; // $FlowFixMe[unclear-type] type Commands = Map, Array>>>; type RegisteredNodes = Map; type RegisteredNode = { klass: Class, transforms: Set>, }; export type Transform = (node: T) => void; type DOMConversionCache = Map< string, Array<(node: Node) => DOMConversion | null>, >; export type CreateEditorArgs = { disableEvents?: boolean; editorState?: EditorState; namespace?: string; nodes?: $ReadOnlyArray | 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; _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; _dirtyLeaves: Set; _dirtyElements: Map; _normalizedNodes: Set; _updateTags: Set; _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

( command: LexicalCommand

, listener: CommandListener

, priority: CommandListenerPriority, ): () => void; registerEditableListener(listener: EditableListener): () => void; registerMutationListener( klass: Class, listener: MutationListener, options?: MutationListenerOptions, ): () => void; registerNodeTransform( klass: Class, listener: Transform, ): () => void; dispatchCommand

(command: LexicalCommand

, payload: P): boolean; hasNode(node: Class): boolean; hasNodes(nodes: Array>): boolean; getKey(): string; getDecorators(): { [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(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, 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, ol?: EditorThemeClassName, olDepth?: Array, 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, with: (node: LexicalNode) => LexicalNode, withKlass?: Class, }; export type HTMLConfig = { export?: Map< Class, (editor: LexicalEditor, target: LexicalNode) => DOMExportOutput, >, import?: DOMConversionMap, }; declare export function createEditor(editorConfig?: { editorState?: EditorState, namespace: string, theme?: EditorThemeClasses, parentEditor?: LexicalEditor, nodes?: $ReadOnlyArray | 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(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]: (node: T) => DOMConversion | null, }; type NodeName = string; export type DOMConversionOutput = { after?: (childLexicalNodes: Array) => Array, forChild?: DOMChildConversion, node: null | LexicalNode | Array, }; 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 | null; getParentOrThrow(): T; getTopLevelElement(): DecoratorNode | ElementNode | null; getTopLevelElementOrThrow(): DecoratorNode | ElementNode; getParents(): Array; getParentKeys(): Array; getPreviousSibling(): T | null; getPreviousSiblings(): Array; getNextSibling(): T | null; getNextSiblings(): Array; getCommonAncestor(node: LexicalNode): T | null; is(object: ?LexicalNode): boolean; isBefore(targetNode: LexicalNode): boolean; isParentOf(targetNode: LexicalNode): boolean; getNodesBetween(targetNode: LexicalNode): Array; isDirty(): boolean; // $FlowFixMe[incompatible-type] getLatest(this: T): T; // $FlowFixMe[incompatible-type] getWritable(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(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; /** * LexicalSelection */ declare export function $isBlockElementNode( node: ?LexicalNode, ): node is ElementNode; export interface BaseSelection { dirty: boolean; clone(): BaseSelection; extract(): Array; getNodes(): Array; 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): void; getCachedNodes(): null | Array; setCachedNodes(nodes: null | Array): void; } declare export class NodeSelection implements BaseSelection { _nodes: Set; dirty: boolean; constructor(objects: Set): 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; insertRawText(): void; insertText(): void; getNodes(): Array; getStartEndPoints(): null; getTextContent(): string; insertNodes(nodes: Array): void; getCachedNodes(): null | Array; setCachedNodes(nodes: null | Array): 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; 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): void; insertParagraph(): void; insertLineBreak(selectStart?: boolean): void; extract(): Array; 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): void; getCachedNodes(): null | Array; setCachedNodes(nodes: null | Array): 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): 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): Array; 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(node: N): N; insertBefore(nodeToInsert: T): T; insertAfter(nodeToInsert: T): T; append(...nodesToAppend: Array): 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(): Array; getChildren>(): T; getChildrenKeys(): Array; getChildrenSize(): number; isEmpty(): boolean; isDirty(): boolean; getAllTextNodes(): Array; getFirstDescendant(): null | T; getLastDescendant(): null | T; getDescendantByIndex(index: number): null | T; getFirstChild(): null | T; getFirstChildOrThrow(): T; getLastChild(): null | T; getLastChildOrThrow(): T; getChildAtIndex(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): 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, ): this; exportJSON(): SerializedElementNode; getDOMSlot(dom: HTMLElement): ElementDOMSlot; } 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; withAfter(after: Node | null | void): ElementDOMSlot; withElement(element: ElementType): ElementDOMSlot; 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 extends LexicalNode { constructor(key?: NodeKey): void; // Not sure how to get flow to agree that the DecoratorNode 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( node: ?LexicalNode, ): node is DecoratorNode; /** * 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: UpdateTag): boolean; declare export function $addUpdateTag(tag: UpdateTag): 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(key: NodeKey): N | null; declare export function $getNodeByKeyOrThrow(key: NodeKey): N; declare export function $getRoot(): RootNode; declare export function $isLeafNode( node: ?LexicalNode, ): node is TextNode | LineBreakNode | DecoratorNode; declare export function $setCompositionKey( compositionKey: null | NodeKey, ): void; declare export function $setSelection(selection: null | BaseSelection): void; declare export function $nodesOfType(klass: Class): Array; declare export function $getAdjacentNode( focus: Point, isBackward: boolean, ): null | LexicalNode; declare export function resetRandomKey(): void; declare export function generateRandomKey(): string; declare export function $isInlineElementOrDecoratorNode( node: LexicalNode, ): node is ElementNode| DecoratorNode; 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(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, type: string, version: number, }; declare export function $parseSerializedNode( serializedNode: InternalSerializedNode, ): LexicalNode; declare export function $applyNodeReplacement( 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, 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 extends Iterable> { +origin: T; +type: Type; +direction: D; getParentAtCaret(): null | ElementNode; getNodeAtCaret(): null | LexicalNode; getAdjacentCaret(): null | SiblingCaret; getSiblingCaret(): SiblingCaret; remove(): BaseCaret; // this insert(node: LexicalNode): BaseCaret; // this replaceOrInsert(node: LexicalNode, includeChildren?: boolean): BaseCaret; // this splice(deleteCount: number, nodes: Iterable, nodesDirection?: CaretDirection): BaseCaret; // this } export type CaretDirection = 'next' | 'previous'; type FLIP_DIRECTION = {'next' : 'previous', 'previous': 'next'}; export interface CaretRange extends Iterable> { +type: 'node-caret-range'; +direction: D; anchor: PointCaret; focus: PointCaret; isCollapsed(): boolean; iterNodeCarets(rootMode?: RootMode): Iterable>; getTextSlices(): TextPointCaretSliceTuple; } export type CaretType = 'sibling' | 'child'; export interface ChildCaret extends BaseCaret { getLatest(): ChildCaret; getParentCaret(mode?: RootMode): null | SiblingCaret; getParentAtCaret(): T; getChildCaret(): ChildCaret; isSameNodeCaret(other: null | void | PointCaret): boolean; // other is ChildCaret; isSamePointCaret(other: null | void | PointCaret): boolean; // other is ChildCaret; getFlipped(): NodeCaret>; // Refine chained types remove(): ChildCaret; insert(node: LexicalNode): ChildCaret; replaceOrInsert(node: LexicalNode, includeChildren?: boolean): ChildCaret; splice(deleteCount: number, nodes: Iterable, nodesDirection?: CaretDirection): ChildCaret; } export type FlipDirection = FLIP_DIRECTION[D]; export type NodeCaret = ChildCaret | SiblingCaret; export type PointCaret = ChildCaret | SiblingCaret | TextPointCaret; export type RootMode = 'root' | 'shadowRoot'; export interface SiblingCaret extends BaseCaret { getLatest(): SiblingCaret; getChildCaret(): null | ChildCaret; getParentCaret(mode?: RootMode): null | SiblingCaret; isSameNodeCaret(other: null | void | PointCaret): boolean; // other is SiblingCaret | T extends TextNode ? TextPointCaret : empty; isSamePointCaret(other: null | void | PointCaret): boolean; // other is SiblingCaret; getFlipped(): NodeCaret>; // Refine chained types remove(): SiblingCaret; insert(node: LexicalNode): SiblingCaret; replaceOrInsert(node: LexicalNode, includeChildren?: boolean): SiblingCaret; splice(deleteCount: number, nodes: Iterable, nodesDirection?: CaretDirection): SiblingCaret; } export interface StepwiseIteratorConfig { +initial: State | Stop; +hasNext: (value: State | Stop) => implies value is State; +step: (value: State) => State | Stop; +map: (value: State) => Value; } export interface TextPointCaret extends BaseCaret { +offset: number; getLatest(): TextPointCaret; getChildCaret(): null; getParentCaret(): null | SiblingCaret; isSameNodeCaret(other: null | void | PointCaret): boolean; // other is TextPointCaret | SiblingCaret; isSamePointCaret(other: null | void | PointCaret): boolean; // other is TextPointCaret; getFlipped(): TextPointCaret>; } export interface TextPointCaretSlice { +type: 'slice'; +caret: TextPointCaret; +distance: number; getSliceIndices(): [startIndex: number, endIndex: number]; getTextContent(): string; getTextContentSize(): number; removeTextSlice(): TextPointCaret; } export type TextPointCaretSliceTuple = [ +anchorSlice: null | TextPointCaretSlice, +focusSlice: null | TextPointCaretSlice, ]; declare export function $getAdjacentChildCaret(caret: null | NodeCaret): null | NodeCaret; declare export function $getCaretRange(anchor: PointCaret, focus: PointCaret): CaretRange; declare export function $getChildCaret(origin: T, direction: D): ChildCaret, D> | Extract; declare export function $getChildCaretOrSelf>(caret: Caret): Caret | ChildCaret['direction']>; declare export function $getSiblingCaret(origin: T, direction: D): SiblingCaret, D> | Extract; declare export function $getTextNodeOffset(origin: TextNode, offset: number | CaretDirection): number; declare export function $getTextPointCaret(origin: T, direction: D, offset: number | CaretDirection): TextPointCaret, D> | Extract; declare export function $getTextPointCaretSlice(caret: TextPointCaret, distance: number): TextPointCaretSlice; declare export function $isChildCaret(caret: null | void | PointCaret): caret is ChildCaret; declare export function $isNodeCaret(caret: null | void | PointCaret): caret is NodeCaret; declare export function $isSiblingCaret(caret: null | void | PointCaret): caret is SiblingCaret; declare export function $isTextPointCaret(caret: null | void | PointCaret): caret is TextPointCaret; declare export function $isTextPointCaretSlice(caret: null | void | PointCaret | TextPointCaretSlice): caret is TextPointCaretSlice; declare export function flipDirection(direction: D): FlipDirection; declare export function makeStepwiseIterator( config: StepwiseIteratorConfig, ): Iterator; /** * LexicalCaretUtils */ declare export function $caretFromPoint( point: PointType, direction: D, ): PointCaret; declare export function $caretRangeFromSelection( selection: RangeSelection, ): CaretRange; declare export function $getAdjacentSiblingOrParentSiblingCaret< D: CaretDirection, >( startCaret: NodeCaret, rootMode?: RootMode ): null | [NodeCaret, number] declare export function $getCaretInDirection< Caret: PointCaret, D: CaretDirection, >( caret: Caret, direction: D, ): | NodeCaret | (Caret extends TextPointCaret ? TextPointCaret : empty); declare export function $getCaretRangeInDirection( range: CaretRange, direction: D, ): CaretRange; declare export function $getChildCaretAtIndex( parent: ElementNode, index: number, direction: D, ): NodeCaret; declare export function $normalizeCaret( initialCaret: PointCaret, ): PointCaret; declare export function $removeTextFromCaretRange( initialRange: CaretRange, sliceMode?: | 'removeEmptySlices' | 'preserveEmptyTextSliceCaret' ): CaretRange; declare export function $rewindSiblingCaret< T: LexicalNode, D: CaretDirection, >(caret: SiblingCaret): NodeCaret; declare export function $setPointFromCaret( point: PointType, caret: PointCaret, ): void; declare export function $setSelectionFromCaretRange( caretRange: CaretRange, ): RangeSelection; declare export function $updateRangeSelectionFromCaretRange( selection: RangeSelection, caretRange: CaretRange, ): void; export type CommonAncestorResult< A: LexicalNode, B: LexicalNode, > = | CommonAncestorResultSame | CommonAncestorResultAncestor | CommonAncestorResultDescendant | CommonAncestorResultBranch; export interface CommonAncestorResultBranch< A: LexicalNode, B: LexicalNode, > { +type: 'branch'; +commonAncestor: ElementNode; +a: A | ElementNode; +b: B | ElementNode; } export interface CommonAncestorResultAncestor { +type: 'ancestor'; +commonAncestor: A; } export interface CommonAncestorResultDescendant { +type: 'descendant'; +commonAncestor: B; } export interface CommonAncestorResultSame { +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): -1 | 1 ; declare export function $getCommonAncestor< A: LexicalNode, B: LexicalNode, >(a: A, b: B): null | CommonAncestorResult; declare export function $extendCaretToRange( anchor: PointCaret, ): CaretRange; declare export function $getCollapsedCaretRange( anchor: PointCaret, ): CaretRange; declare export function $isExtendableTextPointCaret( caret: PointCaret ): implies caret is TextPointCaret; export interface SplitAtPointCaretNextOptions { $copyElementNode?: (node: ElementNode) => ElementNode; $splitTextPointCaretNext?: ( caret: TextPointCaret, ) => NodeCaret<'next'>; rootMode?: RootMode; $shouldSplit?: (node: ElementNode, edge: 'first' | 'last') => boolean; } declare export function $splitAtPointCaretNext( pointCaret: PointCaret<'next'>, options?: SplitAtPointCaretNextOptions, ): null | NodeCaret<'next'>; /** * LexicalUpdateTags */ declare export var COLLABORATION_TAG: 'collaboration'; declare export var HISTORIC_TAG: 'historic'; declare export var HISTORY_MERGE_TAG: 'history-merge'; declare export var HISTORY_PUSH_TAG: 'history-push'; declare export var PASTE_TAG: 'paste'; declare export var SKIP_COLLAB_TAG: 'skip-collab'; declare export var SKIP_DOM_SELECTION_TAG: 'skip-dom-selection'; declare export var SKIP_SCROLL_INTO_VIEW_TAG: 'skip-scroll-into-view'; export type UpdateTag = typeof COLLABORATION_TAG | typeof HISTORIC_TAG | typeof HISTORY_MERGE_TAG | typeof HISTORY_PUSH_TAG | typeof PASTE_TAG | typeof SKIP_COLLAB_TAG | typeof SKIP_DOM_SELECTION_TAG | typeof SKIP_SCROLL_INTO_VIEW_TAG | string; /** * LexicalNodeState */ export const NODE_STATE_KEY = '$'; export type ValueOrUpdater = V | ((prevValue: V) => V); export type StateConfigValue = S extends StateConfig< infer _K, infer V > ? V : empty; export type StateConfigKey = S extends StateConfig< infer K, infer _V > ? K : empty; export interface NodeStateConfig { stateConfig: S; flat?: boolean; } export type RequiredNodeStateConfig = | NodeStateConfig | AnyStateConfig; export type StateConfigJSON = S extends StateConfig ? {[Key in K]?: V} : Record; export type RequiredNodeStateConfigJSON< Config: RequiredNodeStateConfig, Flat: boolean, > = StateConfigJSON< Config extends NodeStateConfig ? {flat: false, ...Config} extends {flat: Flat} ? S : empty : false extends Flat ? Config : empty >; export type StateValueOrUpdater = ValueOrUpdater< StateConfigValue >; // $FlowFixMe[unclear-type] export type AnyStateConfig = StateConfig; export type NodeStateJSON = Partial<{ [typeof NODE_STATE_KEY]: CollectStateJSON, false>; }> & CollectStateJSON, true>; declare export class StateConfig { +key: K; +parse: (value?: mixed) => V; +unparse: (value: V) => mixed; +isEqual: (a: V, b: V) => boolean; +defaultValue: V; constructor(key: K, stateValueConfig: StateValueConfig): this; } export type StateValueConfig = { parse: (jsonValue: mixed) => V; unparse?: (parsed: V) => mixed; isEqual?: (a: V, b: V) => boolean; } export type UnionToIntersection = ( // $FlowFixMe[unclear-type] T extends mixed ? (x: T) => mixed : empty // $FlowFixMe[unclear-type] ) extends (x: infer R) => any ? R : empty; export type CollectStateJSON< Tuple: $ReadOnlyArray, Flat: boolean, > = UnionToIntersection< {[K in keyof Tuple]: RequiredNodeStateConfigJSON}[number] >; export const PROTOTYPE_CONFIG_METHOD = '$config'; export interface StaticNodeConfigValue< T: LexicalNode, Type: string, > { +type?: Type; +$transform?: (node: T) => void; +$importJSON?: (serializedNode: SerializedLexicalNode) => T; +importDOM?: DOMConversionMap; +stateConfigs?: $ReadOnlyArray; +extends?: Class; } /** * This is the type of LexicalNode.$config() that can be * overridden by subclasses. */ export type BaseStaticNodeConfig = { +[K in string]?: StaticNodeConfigValue; }; /** * Used to extract the node and type from a StaticNodeConfigRecord */ export type StaticNodeConfig< T: LexicalNode, Type: string, > = BaseStaticNodeConfig & { +[K in Type]?: StaticNodeConfigValue; }; // $FlowFixMe[unclear-type] export type AnyStaticNodeConfigValue = StaticNodeConfigValue; export type StaticNodeConfigRecord< Type: string, Config: AnyStaticNodeConfigValue, > = BaseStaticNodeConfig & { +[K in Type]?: Config; }; type GetStaticNodeConfig = ReturnType< T[typeof PROTOTYPE_CONFIG_METHOD] > extends infer Record ? Record extends StaticNodeConfigRecord ? Config & {+type: Type} : empty : empty; type GetStaticNodeConfigs = GetStaticNodeConfig extends infer OwnConfig ? OwnConfig extends empty ? [] : OwnConfig extends {extends: Class} ? GetStaticNodeConfig extends infer ParentNodeConfig ? ParentNodeConfig extends empty ? [OwnConfig] : [OwnConfig, ...GetStaticNodeConfigs] : OwnConfig : [OwnConfig] : []; type CollectStateConfigs = Configs extends [ infer OwnConfig, ...infer ParentConfigs, ] ? OwnConfig extends {stateConfigs: infer StateConfigs} ? StateConfigs extends $ReadOnlyArray ? [...StateConfigs, ...CollectStateConfigs] : CollectStateConfigs : CollectStateConfigs : []; export type GetNodeStateConfig = CollectStateConfigs< GetStaticNodeConfigs >; declare export function $getState( node: LexicalNode, stateConfig: StateConfig, version?: 'latest' | 'direct', ): V; declare export function $getStateChange( node: T, prevNode: T, stateConfig: StateConfig, ): null | [value: V, prevValue: V]; declare export function $getWritableNodeState( node: T, ): NodeState; type KnownStateMap = Map; type UnknownStateRecord = Record; type SharedConfigMap = Map; export type SharedNodeState = { sharedConfigMap: SharedConfigMap; flatKeys: Set; }; declare export class NodeState { +node: LexicalNode; +knownState: KnownStateMap; unknownState: void | UnknownStateRecord; +sharedNodeState: SharedNodeState; size: number; constructor( node: T, sharedNodeState: SharedNodeState, unknownState?: void | UnknownStateRecord, knownState?: KnownStateMap, size?: number | void, ): this; getValue(stateConfig: StateConfig): V; getInternalState(): [ {+[k in string]: mixed} | void, $ReadOnlyMap, ]; toJSON(): NodeStateJSON; getWritable(node: T): NodeState; updateFromKnown( stateConfig: StateConfig, value: V, ): void; updateFromUnknown(k: string, v: mixed): void; updateFromJSON(unknownState: void | UnknownStateRecord): void; } declare export function $setState( node: Node, stateConfig: StateConfig, valueOrUpdater: ValueOrUpdater, ): Node; export type LexicalNodeConfig = Class | LexicalNodeReplacement; declare export function createSharedNodeState( nodeConfig: LexicalNodeConfig, ): SharedNodeState; declare export function createState( key: K, valueConfig: StateValueConfig, ): StateConfig; declare export function $create(cls: Class): T; declare export function getStaticNodeConfig(cls: Class): { ownNodeType: void | string; ownNodeConfig: void | StaticNodeConfigValue; };