1509 lines
50 KiB
Plaintext
1509 lines
50 KiB
Plaintext
/**
|
|
* 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';
|
|
export type UpdateListenerPayload = {
|
|
tags: Set<string>,
|
|
prevEditorState: EditorState,
|
|
editorState: EditorState,
|
|
dirtyLeaves: Set<NodeKey>,
|
|
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
|
normalizedNodes: Set<NodeKey>,
|
|
};
|
|
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<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<UpdateTag>;
|
|
_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: 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<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'>;
|
|
|
|
/**
|
|
* 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> = V | ((prevValue: V) => V);
|
|
export type StateConfigValue<S: AnyStateConfig> = S extends StateConfig<
|
|
infer _K,
|
|
infer V
|
|
>
|
|
? V
|
|
: empty;
|
|
export type StateConfigKey<S: AnyStateConfig> = S extends StateConfig<
|
|
infer K,
|
|
infer _V
|
|
>
|
|
? K
|
|
: empty;
|
|
export interface NodeStateConfig<S: AnyStateConfig> {
|
|
stateConfig: S;
|
|
flat?: boolean;
|
|
}
|
|
|
|
export type RequiredNodeStateConfig =
|
|
| NodeStateConfig<AnyStateConfig>
|
|
| AnyStateConfig;
|
|
|
|
export type StateConfigJSON<S> = S extends StateConfig<infer K, infer V>
|
|
? {[Key in K]?: V}
|
|
: Record<empty, empty>;
|
|
|
|
export type RequiredNodeStateConfigJSON<
|
|
Config: RequiredNodeStateConfig,
|
|
Flat: boolean,
|
|
> = StateConfigJSON<
|
|
Config extends NodeStateConfig<infer S>
|
|
? {flat: false, ...Config} extends {flat: Flat}
|
|
? S
|
|
: empty
|
|
: false extends Flat
|
|
? Config
|
|
: empty
|
|
>;
|
|
export type StateValueOrUpdater<Cfg: AnyStateConfig> = ValueOrUpdater<
|
|
StateConfigValue<Cfg>
|
|
>;
|
|
// $FlowFixMe[unclear-type]
|
|
export type AnyStateConfig = StateConfig<any, any>;
|
|
export type NodeStateJSON<T: LexicalNode> = Partial<{
|
|
[typeof NODE_STATE_KEY]: CollectStateJSON<GetNodeStateConfig<T>, false>;
|
|
}> & CollectStateJSON<GetNodeStateConfig<T>, true>;
|
|
|
|
declare export class StateConfig<K: string, V> {
|
|
+key: K;
|
|
+parse: (value?: mixed) => V;
|
|
+unparse: (value: V) => mixed;
|
|
+isEqual: (a: V, b: V) => boolean;
|
|
+defaultValue: V;
|
|
constructor(key: K, stateValueConfig: StateValueConfig<V>): this;
|
|
}
|
|
|
|
export type StateValueConfig<V> = {
|
|
parse: (jsonValue: mixed) => V;
|
|
unparse?: (parsed: V) => mixed;
|
|
isEqual?: (a: V, b: V) => boolean;
|
|
}
|
|
|
|
export type UnionToIntersection<T> = (
|
|
// $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<RequiredNodeStateConfig>,
|
|
Flat: boolean,
|
|
> = UnionToIntersection<
|
|
{[K in keyof Tuple]: RequiredNodeStateConfigJSON<Tuple[K], Flat>}[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<RequiredNodeStateConfig>;
|
|
+extends?: Class<LexicalNode>;
|
|
}
|
|
|
|
/**
|
|
* This is the type of LexicalNode.$config() that can be
|
|
* overridden by subclasses.
|
|
*/
|
|
export type BaseStaticNodeConfig = {
|
|
+[K in string]?: StaticNodeConfigValue<LexicalNode, string>;
|
|
};
|
|
|
|
/**
|
|
* Used to extract the node and type from a StaticNodeConfigRecord
|
|
*/
|
|
export type StaticNodeConfig<
|
|
T: LexicalNode,
|
|
Type: string,
|
|
> = BaseStaticNodeConfig & {
|
|
+[K in Type]?: StaticNodeConfigValue<T, Type>;
|
|
};
|
|
|
|
// $FlowFixMe[unclear-type]
|
|
export type AnyStaticNodeConfigValue = StaticNodeConfigValue<any, any>;
|
|
|
|
export type StaticNodeConfigRecord<
|
|
Type: string,
|
|
Config: AnyStaticNodeConfigValue,
|
|
> = BaseStaticNodeConfig & {
|
|
+[K in Type]?: Config;
|
|
};
|
|
|
|
type GetStaticNodeConfig<T: LexicalNode> = ReturnType<
|
|
T[typeof PROTOTYPE_CONFIG_METHOD]
|
|
> extends infer Record
|
|
? Record extends StaticNodeConfigRecord<infer Type, infer Config>
|
|
? Config & {+type: Type}
|
|
: empty
|
|
: empty;
|
|
type GetStaticNodeConfigs<T: LexicalNode> =
|
|
GetStaticNodeConfig<T> extends infer OwnConfig
|
|
? OwnConfig extends empty
|
|
? []
|
|
: OwnConfig extends {extends: Class<infer Parent>}
|
|
? GetStaticNodeConfig<Parent> extends infer ParentNodeConfig
|
|
? ParentNodeConfig extends empty
|
|
? [OwnConfig]
|
|
: [OwnConfig, ...GetStaticNodeConfigs<Parent>]
|
|
: OwnConfig
|
|
: [OwnConfig]
|
|
: [];
|
|
|
|
type CollectStateConfigs<Configs> = Configs extends [
|
|
infer OwnConfig,
|
|
...infer ParentConfigs,
|
|
]
|
|
? OwnConfig extends {stateConfigs: infer StateConfigs}
|
|
? StateConfigs extends $ReadOnlyArray<RequiredNodeStateConfig>
|
|
? [...StateConfigs, ...CollectStateConfigs<ParentConfigs>]
|
|
: CollectStateConfigs<ParentConfigs>
|
|
: CollectStateConfigs<ParentConfigs>
|
|
: [];
|
|
|
|
export type GetNodeStateConfig<T: LexicalNode> = CollectStateConfigs<
|
|
GetStaticNodeConfigs<T>
|
|
>;
|
|
|
|
declare export function $getState<K: string, V>(
|
|
node: LexicalNode,
|
|
stateConfig: StateConfig<K, V>,
|
|
version?: 'latest' | 'direct',
|
|
): V;
|
|
declare export function $getStateChange<T: LexicalNode, K: string, V>(
|
|
node: T,
|
|
prevNode: T,
|
|
stateConfig: StateConfig<K, V>,
|
|
): null | [value: V, prevValue: V];
|
|
declare export function $getWritableNodeState<T: LexicalNode>(
|
|
node: T,
|
|
): NodeState<T>;
|
|
type KnownStateMap = Map<AnyStateConfig, mixed>;
|
|
type UnknownStateRecord = Record<string, mixed>;
|
|
type SharedConfigMap = Map<string, AnyStateConfig>;
|
|
export type SharedNodeState = {
|
|
sharedConfigMap: SharedConfigMap;
|
|
flatKeys: Set<string>;
|
|
};
|
|
declare export class NodeState<T: LexicalNode> {
|
|
+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<K: string, V>(stateConfig: StateConfig<K, V>): V;
|
|
getInternalState(): [
|
|
{+[k in string]: mixed} | void,
|
|
$ReadOnlyMap<AnyStateConfig, mixed>,
|
|
];
|
|
toJSON(): NodeStateJSON<T>;
|
|
getWritable(node: T): NodeState<T>;
|
|
updateFromKnown<K: string, V>(
|
|
stateConfig: StateConfig<K, V>,
|
|
value: V,
|
|
): void;
|
|
updateFromUnknown(k: string, v: mixed): void;
|
|
updateFromJSON(unknownState: void | UnknownStateRecord): void;
|
|
}
|
|
declare export function $setState<Node: LexicalNode, K: string, V>(
|
|
node: Node,
|
|
stateConfig: StateConfig<K, V>,
|
|
valueOrUpdater: ValueOrUpdater<V>,
|
|
): Node;
|
|
export type LexicalNodeConfig = Class<LexicalNode> | LexicalNodeReplacement;
|
|
declare export function createSharedNodeState(
|
|
nodeConfig: LexicalNodeConfig,
|
|
): SharedNodeState;
|
|
declare export function createState<K: string, V>(
|
|
key: K,
|
|
valueConfig: StateValueConfig<V>,
|
|
): StateConfig<K, V>;
|
|
declare export function $create<T>(cls: Class<T>): T;
|
|
declare export function getStaticNodeConfig(cls: Class<LexicalNode>): {
|
|
ownNodeType: void | string;
|
|
ownNodeConfig: void | StaticNodeConfigValue<LexicalNode, string>;
|
|
};
|