@lobehub/editor
Version:
A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.
225 lines (223 loc) • 8.5 kB
TypeScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalNode } from '../LexicalNode';
import { type PointType, type RangeSelection } from '../LexicalSelection';
import { type ElementNode } from '../nodes/LexicalElementNode';
import { type TextNode } from '../nodes/LexicalTextNode';
import type {
CaretDirection,
CaretRange,
NodeCaret,
PointCaret,
RootMode,
SiblingCaret,
TextPointCaret,
} from './LexicalCaret';
/**
* @param point
* @returns a PointCaret for the point
*/
export declare function $caretFromPoint<D extends CaretDirection>(
point: Pick<PointType, 'type' | 'key' | 'offset'>,
direction: D,
): PointCaret<D>;
/**
* Update the given point in-place from the PointCaret
*
* @param point the point to set
* @param caret the caret to set the point from
*/
export declare function $setPointFromCaret<D extends CaretDirection>(
point: PointType,
caret: PointCaret<D>,
): void;
/**
* Set a RangeSelection on the editor from the given CaretRange
*
* @returns The new RangeSelection
*/
export declare function $setSelectionFromCaretRange(caretRange: CaretRange): RangeSelection;
/**
* Update the points of a RangeSelection based on the given PointCaret.
*/
export declare function $updateRangeSelectionFromCaretRange(
selection: RangeSelection,
caretRange: CaretRange,
): void;
/**
* Get a pair of carets for a RangeSelection.
*
* If the focus is before the anchor, then the direction will be
* 'previous', otherwise the direction will be 'next'.
*/
export declare function $caretRangeFromSelection(selection: RangeSelection): CaretRange;
/**
* Given a SiblingCaret we can always compute a caret that points to the
* origin of that caret in the same direction. The adjacent caret of the
* returned caret will be equivalent to the given caret.
*
* @example
* ```ts
* siblingCaret.is($rewindSiblingCaret(siblingCaret).getAdjacentCaret())
* ```
*
* @param caret The caret to "rewind"
* @returns A new caret (ChildCaret or SiblingCaret) with the same direction
*/
export declare function $rewindSiblingCaret<T extends LexicalNode, D extends CaretDirection>(
caret: SiblingCaret<T, D>,
): NodeCaret<D>;
/**
* Remove all text and nodes in the given range. If the range spans multiple
* blocks then the remaining contents of the later block will be merged with
* the earlier block.
*
* @param initialRange The range to remove text and nodes from
* @param sliceMode If 'preserveEmptyTextPointCaret' it will leave an empty TextPointCaret at the anchor for insert if one exists, otherwise empty slices will be removed
* @returns The new collapsed range (biased towards the earlier node)
*/
export declare function $removeTextFromCaretRange<D extends CaretDirection>(
initialRange: CaretRange<D>,
sliceMode?: 'removeEmptySlices' | 'preserveEmptyTextSliceCaret',
): CaretRange<D>;
/**
* Normalize a caret to the deepest equivalent PointCaret.
* This will return a TextPointCaret with the offset set according
* to the direction if given a caret with a TextNode origin
* or a caret with an ElementNode origin with the deepest ChildCaret
* having an adjacent TextNode.
*
* If given a TextPointCaret, it will be returned, as no normalization
* is required when an offset is already present.
*
* @param initialCaret
* @returns The normalized PointCaret
*/
export declare function $normalizeCaret<D extends CaretDirection>(
initialCaret: PointCaret<D>,
): PointCaret<D>;
declare const PointCaretIsExtendableBrand: unique symbol;
/**
* Determine whether the TextPointCaret's offset can be extended further without leaving the TextNode.
* Returns false if the given caret is not a TextPointCaret or the offset can not be moved further in
* direction.
*
* @param caret A PointCaret
* @returns true if caret is a TextPointCaret with an offset that is not at the end of the text given the direction.
*/
export declare function $isExtendableTextPointCaret<D extends CaretDirection>(
caret: PointCaret<D>,
): caret is TextPointCaret<TextNode, D> & {
[PointCaretIsExtendableBrand]: never;
};
/**
* Return the caret if it's in the given direction, otherwise return
* caret.getFlipped().
*
* @param caret Any PointCaret
* @param direction The desired direction
* @returns A PointCaret in direction
*/
export declare function $getCaretInDirection<
Caret extends PointCaret<CaretDirection>,
D extends CaretDirection,
>(
caret: Caret,
direction: D,
):
| NodeCaret<D>
| (Caret extends TextPointCaret<TextNode, CaretDirection> ? TextPointCaret<TextNode, D> : never);
/**
* Return the range if it's in the given direction, otherwise
* construct a new range using a flipped focus as the anchor
* and a flipped anchor as the focus. This transformation
* preserves the section of the document that it's working
* with, but reverses the order of iteration.
*
* @param range Any CaretRange
* @param direction The desired direction
* @returns A CaretRange in direction
*/
export declare function $getCaretRangeInDirection<D extends CaretDirection>(
range: CaretRange<CaretDirection>,
direction: D,
): CaretRange<D>;
/**
* Get a caret pointing at the child at the given index, or the last
* caret in that node if out of bounds.
*
* @param parent An ElementNode
* @param index The index of the origin for the caret
* @returns A caret pointing towards the node at that index
*/
export declare function $getChildCaretAtIndex<D extends CaretDirection>(
parent: ElementNode,
index: number,
direction: D,
): NodeCaret<D>;
/**
* Returns the Node sibling when this exists, otherwise the closest parent sibling. For example
* R -> P -> T1, T2
* -> P2
* returns T2 for node T1, P2 for node T2, and null for node P2.
* @param startCaret The initial caret
* @param rootMode The root mode, 'root' (default) or 'shadowRoot'
* @returns An array (tuple) containing the found caret and the depth difference, or null, if this node doesn't exist.
*/
export declare function $getAdjacentSiblingOrParentSiblingCaret<D extends CaretDirection>(
startCaret: NodeCaret<D>,
rootMode?: RootMode,
): null | [NodeCaret<D>, number];
/**
* Get the adjacent nodes to initialCaret in the given direction.
*
* @example
* ```ts
* expect($getAdjacentNodes($getChildCaret(parent, 'next'))).toEqual(parent.getChildren());
* expect($getAdjacentNodes($getChildCaret(parent, 'previous'))).toEqual(parent.getChildren().reverse());
* expect($getAdjacentNodes($getSiblingCaret(node, 'next'))).toEqual(node.getNextSiblings());
* expect($getAdjacentNodes($getSiblingCaret(node, 'previous'))).toEqual(node.getPreviousSiblings().reverse());
* ```
*
* @param initialCaret The caret to start at (the origin will not be included)
* @returns An array of siblings.
*/
export declare function $getAdjacentNodes(initialCaret: NodeCaret<CaretDirection>): LexicalNode[];
export declare function $splitTextPointCaret<D extends CaretDirection>(
textPointCaret: TextPointCaret<TextNode, D>,
): NodeCaret<D>;
export interface SplitAtPointCaretNextOptions {
/** The function to create the right side of a split ElementNode (default {@link $copyNode}) */
$copyElementNode?: (node: ElementNode) => ElementNode;
/** The function to split a TextNode (default {@link $splitTextPointCaret}) */
$splitTextPointCaretNext?: (caret: TextPointCaret<TextNode, 'next'>) => NodeCaret<'next'>;
/** If the parent matches rootMode a split will not occur, default is 'shadowRoot' */
rootMode?: RootMode;
/**
* If element.canBeEmpty() and would create an empty split, this function will be
* called with the element and 'first' | 'last'. If it returns false, the empty
* split will not be created. Default is `() => true` to always split when possible.
*/
$shouldSplit?: (node: ElementNode, edge: 'first' | 'last') => boolean;
}
/**
* Split a node at a PointCaret and return a NodeCaret at that point, or null if the
* node can't be split. This is non-recursive and will only perform at most one split.
*
* @returns The NodeCaret pointing to the location of the split (or null if a split is not possible)
*/
export declare function $splitAtPointCaretNext(
pointCaret: PointCaret<'next'>,
{
$copyElementNode,
$splitTextPointCaretNext,
rootMode,
$shouldSplit,
}?: SplitAtPointCaretNextOptions,
): null | NodeCaret<'next'>;
export {};