Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
546 lines
26 KiB
Plaintext
546 lines
26 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.
|
|
*
|
|
*/
|
|
import type { LexicalNode } from '../LexicalNode';
|
|
import { ElementNode } from '../nodes/LexicalElementNode';
|
|
import { TextNode } from '../nodes/LexicalTextNode';
|
|
/**
|
|
* The direction of a caret, 'next' points towards the end of the document
|
|
* and 'previous' points towards the beginning
|
|
*/
|
|
export type CaretDirection = 'next' | 'previous';
|
|
/**
|
|
* A type utility to flip next and previous
|
|
*/
|
|
export type FlipDirection<D extends CaretDirection> = (typeof FLIP_DIRECTION)[D];
|
|
/**
|
|
* A sibling caret type points from a LexicalNode origin to its next or previous sibling,
|
|
* and a child caret type points from an ElementNode origin to its first or last child.
|
|
*/
|
|
export type CaretType = 'sibling' | 'child';
|
|
/**
|
|
* The RootMode is specified in all caret traversals where the traversal can go up
|
|
* towards the root. 'root' means that it will stop at the document root,
|
|
* and 'shadowRoot' will stop at the document root or any shadow root
|
|
* (per {@link $isRootOrShadowRoot}).
|
|
*/
|
|
export type RootMode = 'root' | 'shadowRoot';
|
|
declare const FLIP_DIRECTION: {
|
|
readonly next: "previous";
|
|
readonly previous: "next";
|
|
};
|
|
/** @noInheritDoc */
|
|
export interface BaseCaret<T extends LexicalNode, D extends CaretDirection, Type> extends Iterable<SiblingCaret<LexicalNode, D>> {
|
|
/** The origin node of this caret, typically this is what you will use in traversals */
|
|
readonly origin: T;
|
|
/** sibling for a SiblingCaret (pointing at the next or previous sibling) or child for a ChildCaret (pointing at the first or last child) */
|
|
readonly type: Type;
|
|
/** next if pointing at the next sibling or first child, previous if pointing at the previous sibling or last child */
|
|
readonly direction: D;
|
|
/** Get the ElementNode that is the logical parent (`origin` for `ChildCaret`, `origin.getParent()` for `SiblingCaret`) */
|
|
getParentAtCaret: () => null | ElementNode;
|
|
/** Get the node connected to the origin in the caret's direction, or null if there is no node */
|
|
getNodeAtCaret: () => null | LexicalNode;
|
|
/** Get a new SiblingCaret from getNodeAtCaret() in the same direction. */
|
|
getAdjacentCaret: () => null | SiblingCaret<LexicalNode, D>;
|
|
/**
|
|
* Get a new SiblingCaret with this same node
|
|
*/
|
|
getSiblingCaret: () => SiblingCaret<T, D>;
|
|
/** Remove the getNodeAtCaret() node that this caret is pointing towards, if it exists */
|
|
remove: () => this;
|
|
/**
|
|
* Insert a node connected to origin in this direction (before the node that this caret is pointing towards, if any existed).
|
|
* For a `SiblingCaret` this is `origin.insertAfter(node)` for next, or `origin.insertBefore(node)` for previous.
|
|
* For a `ChildCaret` this is `origin.splice(0, 0, [node])` for next or `origin.append(node)` for previous.
|
|
*/
|
|
insert: (node: LexicalNode) => this;
|
|
/** If getNodeAtCaret() is not null then replace it with node, otherwise insert node */
|
|
replaceOrInsert: (node: LexicalNode, includeChildren?: boolean) => this;
|
|
/**
|
|
* Splice an iterable (typically an Array) of nodes into this location.
|
|
*
|
|
* @param deleteCount The number of existing nodes to replace or delete
|
|
* @param nodes An iterable of nodes that will be inserted in this location, using replace instead of insert for the first deleteCount nodes
|
|
* @param nodesDirection The direction of the nodes iterable, defaults to 'next'
|
|
*/
|
|
splice: (deleteCount: number, nodes: Iterable<LexicalNode>, nodesDirection?: CaretDirection) => this;
|
|
}
|
|
/**
|
|
* A RangeSelection expressed as a pair of Carets
|
|
*/
|
|
export interface CaretRange<D extends CaretDirection = CaretDirection> extends Iterable<NodeCaret<D>> {
|
|
readonly type: 'node-caret-range';
|
|
readonly direction: D;
|
|
anchor: PointCaret<D>;
|
|
focus: PointCaret<D>;
|
|
/** Return true if anchor and focus are the same caret */
|
|
isCollapsed: () => boolean;
|
|
/**
|
|
* Iterate the carets between anchor and focus in a pre-order fashion, note
|
|
* that this does not include any text slices represented by the anchor and/or
|
|
* focus. Those are accessed separately from getTextSlices.
|
|
*
|
|
* An ElementNode origin will be yielded as a ChildCaret on enter,
|
|
* and a SiblingCaret on leave.
|
|
*/
|
|
iterNodeCarets: (rootMode?: RootMode) => IterableIterator<NodeCaret<D>>;
|
|
/**
|
|
* There are between zero and two non-null TextSliceCarets for a CaretRange.
|
|
* Note that when anchor and focus share an origin node the second element
|
|
* will be null because the slice is entirely represented by the first element.
|
|
*
|
|
* `[slice, slice]`: anchor and focus are TextPointCaret with distinct origin nodes
|
|
* `[slice, null]`: anchor is a TextPointCaret
|
|
* `[null, slice]`: focus is a TextPointCaret
|
|
* `[null, null]`: Neither anchor nor focus are TextPointCarets
|
|
*/
|
|
getTextSlices: () => TextPointCaretSliceTuple<D>;
|
|
}
|
|
export interface StepwiseIteratorConfig<State, Stop, Value> {
|
|
readonly initial: State | Stop;
|
|
readonly hasNext: (value: State | Stop) => value is State;
|
|
readonly step: (value: State) => State | Stop;
|
|
readonly map: (value: State) => Value;
|
|
}
|
|
/**
|
|
* A NodeCaret is the combination of an origin node and a direction
|
|
* that points towards where a connected node will be fetched, inserted,
|
|
* or replaced. A SiblingCaret points from a node to its next or previous
|
|
* sibling, and a ChildCaret points to its first or last child
|
|
* (using next or previous as direction, for symmetry with SiblingCaret).
|
|
*
|
|
* The differences between NodeCaret and PointType are:
|
|
* - NodeCaret can only be used to refer to an entire node (PointCaret is used when a full analog is needed). A PointType of text type can be used to refer to a specific location inside of a TextNode.
|
|
* - NodeCaret stores an origin node, type (sibling or child), and direction (next or previous). A PointType stores a type (text or element), the key of a node, and a text or child offset within that node.
|
|
* - NodeCaret is directional and always refers to a very specific node, eliminating all ambiguity. PointType can refer to the location before or at a node depending on context.
|
|
* - NodeCaret is more robust to nearby mutations, as it relies only on a node's direct connections. An element Any change to the count of previous siblings in an element PointType will invalidate it.
|
|
* - NodeCaret is designed to work more directly with the internal representation of the document tree, making it suitable for use in traversals without performing any redundant work.
|
|
*
|
|
* The caret does *not* update in response to any mutations, you should
|
|
* not persist it across editor updates, and using a caret after its origin
|
|
* node has been removed or replaced may result in runtime errors.
|
|
*/
|
|
export type NodeCaret<D extends CaretDirection = CaretDirection> = SiblingCaret<LexicalNode, D> | ChildCaret<ElementNode, D>;
|
|
/**
|
|
* A PointCaret is a NodeCaret that also includes a
|
|
* TextPointCaret type which refers to a specific offset of a TextNode.
|
|
* This type is separate because it is not relevant to general node traversal
|
|
* so it doesn't make sense to have it show up except when defining
|
|
* a CaretRange and in those cases there will be at most two of them only
|
|
* at the boundaries.
|
|
*
|
|
* The addition of TextPointCaret allows this type to represent any location
|
|
* that is representable by PointType, as the TextPointCaret refers to a
|
|
* specific offset within a TextNode.
|
|
*/
|
|
export type PointCaret<D extends CaretDirection = CaretDirection> = TextPointCaret<TextNode, D> | SiblingCaret<LexicalNode, D> | ChildCaret<ElementNode, D>;
|
|
/**
|
|
* A SiblingCaret points from an origin LexicalNode towards its next or previous sibling.
|
|
*/
|
|
export interface SiblingCaret<T extends LexicalNode = LexicalNode, D extends CaretDirection = CaretDirection> extends BaseCaret<T, D, 'sibling'> {
|
|
/** Get a new caret with the latest origin pointer */
|
|
getLatest: () => SiblingCaret<T, D>;
|
|
/**
|
|
* If the origin of this node is an ElementNode, return the ChildCaret of this origin in the same direction.
|
|
* If the origin is not an ElementNode, this will return null.
|
|
*/
|
|
getChildCaret: () => null | ChildCaret<T & ElementNode, D>;
|
|
/**
|
|
* Get the caret in the same direction from the parent of this origin.
|
|
*
|
|
* @param mode 'root' to return null at the root, 'shadowRoot' to return null at the root or any shadow root
|
|
* @returns A SiblingCaret with the parent of this origin, or null if the parent is a root according to mode.
|
|
*/
|
|
getParentCaret: (mode?: RootMode) => null | SiblingCaret<ElementNode, D>;
|
|
/**
|
|
* Return true if other is a SiblingCaret or TextPointCaret with the same
|
|
* origin (by node key comparison) and direction.
|
|
*/
|
|
isSameNodeCaret: (other: null | undefined | PointCaret) => other is SiblingCaret<T, D> | T extends TextNode ? TextPointCaret<T & TextNode, D> : never;
|
|
/**
|
|
* Return true if other is a SiblingCaret with the same
|
|
* origin (by node key comparison) and direction.
|
|
*/
|
|
isSamePointCaret: (other: null | undefined | PointCaret) => other is SiblingCaret<T, D>;
|
|
/**
|
|
* Get a new NodeCaret with the head and tail of its directional arrow flipped, such that flipping twice is the identity.
|
|
* For example, given a non-empty parent with a firstChild and lastChild, and a second emptyParent node with no children:
|
|
*
|
|
* @example
|
|
* ```
|
|
* caret.getFlipped().getFlipped().is(caret) === true;
|
|
* $getChildCaret(parent, 'next').getFlipped().is($getSiblingCaret(firstChild, 'previous')) === true;
|
|
* $getSiblingCaret(lastChild, 'next').getFlipped().is($getChildCaret(parent, 'previous')) === true;
|
|
* $getSiblingCaret(firstChild, 'next).getFlipped().is($getSiblingCaret(lastChild, 'previous')) === true;
|
|
* $getChildCaret(emptyParent, 'next').getFlipped().is($getChildCaret(emptyParent, 'previous')) === true;
|
|
* ```
|
|
*/
|
|
getFlipped: () => NodeCaret<FlipDirection<D>>;
|
|
}
|
|
/**
|
|
* A ChildCaret points from an origin ElementNode towards its first or last child.
|
|
*/
|
|
export interface ChildCaret<T extends ElementNode = ElementNode, D extends CaretDirection = CaretDirection> extends BaseCaret<T, D, 'child'> {
|
|
/** Get a new caret with the latest origin pointer */
|
|
getLatest: () => ChildCaret<T, D>;
|
|
getParentCaret: (mode?: RootMode) => null | SiblingCaret<T, D>;
|
|
getParentAtCaret: () => T;
|
|
/** Return this, the ChildCaret is already a child caret of its origin */
|
|
getChildCaret: () => this;
|
|
/**
|
|
* Return true if other is a ChildCaret with the same
|
|
* origin (by node key comparison) and direction.
|
|
*/
|
|
isSameNodeCaret: (other: null | undefined | PointCaret) => other is ChildCaret<T, D>;
|
|
/**
|
|
* Return true if other is a ChildCaret with the same
|
|
* origin (by node key comparison) and direction.
|
|
*/
|
|
isSamePointCaret: (other: null | undefined | PointCaret) => other is ChildCaret<T, D>;
|
|
/**
|
|
* Get a new NodeCaret with the head and tail of its directional arrow flipped, such that flipping twice is the identity.
|
|
* For example, given a non-empty parent with a firstChild and lastChild, and a second emptyParent node with no children:
|
|
*
|
|
* @example
|
|
* ```
|
|
* caret.getFlipped().getFlipped().is(caret) === true;
|
|
* $getChildCaret(parent, 'next').getFlipped().is($getSiblingCaret(firstChild, 'previous')) === true;
|
|
* $getSiblingCaret(lastChild, 'next').getFlipped().is($getChildCaret(parent, 'previous')) === true;
|
|
* $getSiblingCaret(firstChild, 'next).getFlipped().is($getSiblingCaret(lastChild, 'previous')) === true;
|
|
* $getChildCaret(emptyParent, 'next').getFlipped().is($getChildCaret(emptyParent, 'previous')) === true;
|
|
* ```
|
|
*/
|
|
getFlipped: () => NodeCaret<FlipDirection<D>>;
|
|
}
|
|
/**
|
|
* A TextPointCaret is a special case of a SiblingCaret that also carries
|
|
* an offset used for representing partially selected TextNode at the edges
|
|
* of a CaretRange.
|
|
*
|
|
* The direction determines which part of the text is adjacent to the caret,
|
|
* if next it's all of the text after offset. If previous, it's all of the
|
|
* text before offset.
|
|
*
|
|
* While this can be used in place of any SiblingCaret of a TextNode,
|
|
* the offset into the text will be ignored except in contexts that
|
|
* specifically use the TextPointCaret or PointCaret types.
|
|
*/
|
|
export interface TextPointCaret<T extends TextNode = TextNode, D extends CaretDirection = CaretDirection> extends BaseCaret<T, D, 'text'> {
|
|
/** The offset into the string */
|
|
readonly offset: number;
|
|
/** Get a new caret with the latest origin pointer */
|
|
getLatest: () => TextPointCaret<T, D>;
|
|
/**
|
|
* A TextPointCaret can not have a ChildCaret.
|
|
*/
|
|
getChildCaret: () => null;
|
|
/**
|
|
* Get the caret in the same direction from the parent of this origin.
|
|
*
|
|
* @param mode 'root' to return null at the root, 'shadowRoot' to return null at the root or any shadow root
|
|
* @returns A SiblingCaret with the parent of this origin, or null if the parent is a root according to mode.
|
|
*/
|
|
getParentCaret: (mode?: RootMode) => null | SiblingCaret<ElementNode, D>;
|
|
/**
|
|
* Return true if other is a TextPointCaret or SiblingCaret with the same
|
|
* origin (by node key comparison) and direction.
|
|
*/
|
|
isSameNodeCaret: (other: null | undefined | PointCaret) => other is TextPointCaret<T, D> | SiblingCaret<T, D>;
|
|
/**
|
|
* Return true if other is a ChildCaret with the same
|
|
* origin (by node key comparison) and direction.
|
|
*/
|
|
isSamePointCaret: (other: null | undefined | PointCaret) => other is TextPointCaret<T, D>;
|
|
/**
|
|
* Get a new TextPointCaret with the head and tail of its directional arrow flipped, such that flipping twice is the identity.
|
|
* For a TextPointCaret this merely flips the direction because the arrow is internal to the node.
|
|
*
|
|
* @example
|
|
* ```
|
|
* caret.getFlipped().getFlipped().is(caret) === true;
|
|
* ```
|
|
*/
|
|
getFlipped: () => TextPointCaret<T, FlipDirection<D>>;
|
|
}
|
|
/**
|
|
* A TextPointCaretSlice is a wrapper for a TextPointCaret that carries a signed
|
|
* distance representing the direction and amount of text selected from the given
|
|
* caret. A negative distance means that text before offset is selected, a
|
|
* positive distance means that text after offset is selected. The offset+distance
|
|
* pair is not affected in any way by the direction of the caret.
|
|
*/
|
|
export interface TextPointCaretSlice<T extends TextNode = TextNode, D extends CaretDirection = CaretDirection> {
|
|
readonly type: 'slice';
|
|
readonly caret: TextPointCaret<T, D>;
|
|
readonly distance: number;
|
|
/**
|
|
* @returns absolute coordinates into the text (for use with `text.slice(...)`)
|
|
*/
|
|
getSliceIndices: () => [startIndex: number, endIndex: number];
|
|
/**
|
|
* @returns The text represented by the slice
|
|
*/
|
|
getTextContent: () => string;
|
|
/**
|
|
* @returns The size of the text represented by the slice
|
|
*/
|
|
getTextContentSize: () => number;
|
|
/**
|
|
* Remove the slice of text from the contained caret, returning a new
|
|
* TextPointCaret without the wrapper (since the size would be zero).
|
|
*
|
|
* Note that this is a lower-level utility that does not have any specific
|
|
* behavior for 'segmented' or 'token' modes and it will not remove
|
|
* an empty TextNode.
|
|
*
|
|
* @returns The inner TextPointCaret with the same offset and direction
|
|
* and the latest TextNode origin after mutation
|
|
*/
|
|
removeTextSlice(): TextPointCaret<T, D>;
|
|
}
|
|
/**
|
|
* A utility type to specify that a CaretRange may have zero,
|
|
* one, or two associated TextPointCaretSlice. If the anchor
|
|
* and focus are on the same node, the anchorSlice will contain
|
|
* the slice and focusSlie will be null.
|
|
*/
|
|
export type TextPointCaretSliceTuple<D extends CaretDirection> = readonly [
|
|
anchorSlice: null | TextPointCaretSlice<TextNode, D>,
|
|
focusSlice: null | TextPointCaretSlice<TextNode, D>
|
|
];
|
|
/**
|
|
* Flip a direction ('next' -> 'previous'; 'previous' -> 'next').
|
|
*
|
|
* Note that TypeScript can't prove that FlipDirection is its own
|
|
* inverse (but if you have a concrete 'next' or 'previous' it will
|
|
* simplify accordingly).
|
|
*
|
|
* @param direction A direction
|
|
* @returns The opposite direction
|
|
*/
|
|
export declare function flipDirection<D extends CaretDirection>(direction: D): FlipDirection<D>;
|
|
/**
|
|
* Guard to check if the given caret is specifically a TextPointCaret
|
|
*
|
|
* @param caret Any caret
|
|
* @returns true if it is a TextPointCaret
|
|
*/
|
|
export declare function $isTextPointCaret<D extends CaretDirection>(caret: null | undefined | PointCaret<D>): caret is TextPointCaret<TextNode, D>;
|
|
/**
|
|
* Guard to check if the given argument is any type of caret
|
|
*
|
|
* @param caret
|
|
* @returns true if caret is any type of caret
|
|
*/
|
|
export declare function $isNodeCaret<D extends CaretDirection>(caret: null | undefined | PointCaret<D>): caret is PointCaret<D>;
|
|
/**
|
|
* Guard to check if the given argument is specifically a SiblingCaret (or TextPointCaret)
|
|
*
|
|
* @param caret
|
|
* @returns true if caret is a SiblingCaret
|
|
*/
|
|
export declare function $isSiblingCaret<D extends CaretDirection>(caret: null | undefined | PointCaret<D>): caret is SiblingCaret<LexicalNode, D>;
|
|
/**
|
|
* Guard to check if the given argument is specifically a ChildCaret
|
|
|
|
* @param caret
|
|
* @returns true if caret is a ChildCaret
|
|
*/
|
|
export declare function $isChildCaret<D extends CaretDirection>(caret: null | undefined | PointCaret<D>): caret is ChildCaret<ElementNode, D>;
|
|
/**
|
|
* Get a caret that points at the next or previous sibling of the given origin node.
|
|
*
|
|
* @param origin The origin node
|
|
* @param direction 'next' or 'previous'
|
|
* @returns null if origin is null, otherwise a SiblingCaret for this origin and direction
|
|
*/
|
|
export declare function $getSiblingCaret<T extends LexicalNode, D extends CaretDirection>(origin: T, direction: D): SiblingCaret<T, D>;
|
|
export declare function $getSiblingCaret<T extends LexicalNode, D extends CaretDirection>(origin: null | T, direction: D): null | SiblingCaret<T, D>;
|
|
/**
|
|
* Construct a TextPointCaret
|
|
*
|
|
* @param origin The TextNode
|
|
* @param direction The direction (next points to the end of the text, previous points to the beginning)
|
|
* @param offset The offset into the text in absolute positive string coordinates (0 is the start)
|
|
* @returns a TextPointCaret
|
|
*/
|
|
export declare function $getTextPointCaret<T extends TextNode, D extends CaretDirection>(origin: T, direction: D, offset: number | CaretDirection): TextPointCaret<T, D>;
|
|
export declare function $getTextPointCaret<T extends TextNode, D extends CaretDirection>(origin: null | T, direction: D, offset: number | CaretDirection): null | TextPointCaret<T, D>;
|
|
/**
|
|
* Get a normalized offset into a TextNode given a numeric offset or a
|
|
* direction for which end of the string to use. Throws in dev if the offset
|
|
* is not in the bounds of the text content size.
|
|
*
|
|
* @param origin a TextNode
|
|
* @param offset An absolute offset into the TextNode string, or a direction for which end to use as the offset
|
|
* @param mode If 'error' (the default) out of bounds offsets will be an error in dev. Otherwise it will clamp to a valid offset.
|
|
* @returns An absolute offset into the TextNode string
|
|
*/
|
|
export declare function $getTextNodeOffset(origin: TextNode, offset: number | CaretDirection, mode?: 'error' | 'clamp'): number;
|
|
/**
|
|
* Construct a TextPointCaretSlice given a TextPointCaret and a signed distance. The
|
|
* distance should be negative to slice text before the caret's offset, and positive
|
|
* to slice text after the offset. The direction of the caret itself is not
|
|
* relevant to the string coordinates when working with a TextPointCaretSlice
|
|
* but mutation operations will preserve the direction.
|
|
*
|
|
* @param caret
|
|
* @param distance
|
|
* @returns TextPointCaretSlice
|
|
*/
|
|
export declare function $getTextPointCaretSlice<T extends TextNode, D extends CaretDirection>(caret: TextPointCaret<T, D>, distance: number): TextPointCaretSlice<T, D>;
|
|
/**
|
|
* Get a caret that points at the first or last child of the given origin node,
|
|
* which must be an ElementNode.
|
|
*
|
|
* @param origin The origin ElementNode
|
|
* @param direction 'next' for first child or 'previous' for last child
|
|
* @returns null if origin is null or not an ElementNode, otherwise a ChildCaret for this origin and direction
|
|
*/
|
|
export declare function $getChildCaret<T extends ElementNode, D extends CaretDirection>(origin: T, direction: D): ChildCaret<T, D>;
|
|
/**
|
|
* Gets the ChildCaret if one is possible at this caret origin, otherwise return the caret
|
|
*/
|
|
export declare function $getChildCaretOrSelf<Caret extends PointCaret | null>(caret: Caret): Caret | ChildCaret<ElementNode, NonNullable<Caret>['direction']>;
|
|
/**
|
|
* Gets the adjacent caret, if not-null and if the origin of the adjacent caret is an ElementNode, then return
|
|
* the ChildCaret. This can be used along with the getParentAdjacentCaret method to perform a full DFS
|
|
* style traversal of the tree.
|
|
*
|
|
* @param caret The caret to start at
|
|
*/
|
|
export declare function $getAdjacentChildCaret<D extends CaretDirection>(caret: null | NodeCaret<D>): null | NodeCaret<D>;
|
|
/**
|
|
* Guard to check for a TextPointCaretSlice
|
|
*
|
|
* @param caretOrSlice A caret or slice
|
|
* @returns true if caretOrSlice is a TextPointCaretSlice
|
|
*/
|
|
export declare function $isTextPointCaretSlice<D extends CaretDirection>(caretOrSlice: null | undefined | PointCaret<D> | TextPointCaretSlice<TextNode, D>): caretOrSlice is TextPointCaretSlice<TextNode, D>;
|
|
/**
|
|
* Construct a CaretRange that starts at anchor and goes to the end of the
|
|
* document in the anchor caret's direction.
|
|
*/
|
|
export declare function $extendCaretToRange<D extends CaretDirection>(anchor: PointCaret<D>): CaretRange<D>;
|
|
/**
|
|
* Construct a collapsed CaretRange that starts and ends at anchor.
|
|
*/
|
|
export declare function $getCollapsedCaretRange<D extends CaretDirection>(anchor: PointCaret<D>): CaretRange<D>;
|
|
/**
|
|
* Construct a CaretRange from anchor and focus carets pointing in the
|
|
* same direction. In order to get the expected behavior,
|
|
* the anchor must point towards the focus or be the same point.
|
|
*
|
|
* In the 'next' direction the anchor should be at or before the
|
|
* focus in the document. In the 'previous' direction the anchor
|
|
* should be at or after the focus in the document
|
|
* (similar to a backwards RangeSelection).
|
|
*
|
|
* @param anchor
|
|
* @param focus
|
|
* @returns a CaretRange
|
|
*/
|
|
export declare function $getCaretRange<D extends CaretDirection>(anchor: PointCaret<D>, focus: PointCaret<D>): CaretRange<D>;
|
|
/**
|
|
* A generalized utility for creating a stepwise iterator
|
|
* based on:
|
|
*
|
|
* - an initial state
|
|
* - a stop guard that returns true if the iteration is over, this
|
|
* is typically used to detect a sentinel value such as null or
|
|
* undefined from the state but may return true for other conditions
|
|
* as well
|
|
* - a step function that advances the state (this will be called
|
|
* after map each time next() is called to prepare the next state)
|
|
* - a map function that will be called that may transform the state
|
|
* before returning it. It will only be called once for each next()
|
|
* call when stop(state) === false
|
|
*
|
|
* @param config
|
|
* @returns An IterableIterator
|
|
*/
|
|
export declare function makeStepwiseIterator<State, Stop, Value>(config: StepwiseIteratorConfig<State, Stop, Value>): IterableIterator<Value>;
|
|
/**
|
|
* A total ordering for `PointCaret<'next'>`, based on
|
|
* the same order that a {@link CaretRange} would iterate
|
|
* them.
|
|
*
|
|
* For a given origin node:
|
|
* - ChildCaret comes before SiblingCaret
|
|
* - TextPointCaret comes before SiblingCaret
|
|
*
|
|
* An exception is thrown when a and b do not have any
|
|
* common ancestor.
|
|
*
|
|
* This ordering is a sort of mix of pre-order and post-order
|
|
* because each ElementNode will show up as a ChildCaret
|
|
* on 'enter' (pre-order) and a SiblingCaret on 'leave' (post-order).
|
|
*
|
|
* @param a
|
|
* @param b
|
|
* @returns -1 if a comes before b, 0 if a and b are the same, or 1 if a comes after b
|
|
*/
|
|
export declare function $comparePointCaretNext(a: PointCaret<'next'>, b: PointCaret<'next'>): -1 | 0 | 1;
|
|
/**
|
|
* Return the ordering of siblings in a CommonAncestorResultBranch
|
|
* @param branch Returns -1 if a precedes b, 1 otherwise
|
|
*/
|
|
export declare function $getCommonAncestorResultBranchOrder<A extends LexicalNode, B extends LexicalNode>(compare: CommonAncestorResultBranch<A, B>): -1 | 1;
|
|
/**
|
|
* The two compared nodes are the same
|
|
*/
|
|
export interface CommonAncestorResultSame<A extends LexicalNode> {
|
|
readonly type: 'same';
|
|
readonly commonAncestor: A;
|
|
}
|
|
/**
|
|
* Node a was a descendant of node b, and not the same node
|
|
*/
|
|
export interface CommonAncestorResultDescendant<B extends ElementNode> {
|
|
readonly type: 'descendant';
|
|
readonly commonAncestor: B;
|
|
}
|
|
/**
|
|
* Node a is an ancestor of node b, and not the same node
|
|
*/
|
|
export interface CommonAncestorResultAncestor<A extends ElementNode> {
|
|
readonly type: 'ancestor';
|
|
readonly commonAncestor: A;
|
|
}
|
|
/**
|
|
* Node a and node b have a common ancestor but are on different branches,
|
|
* the `a` and `b` properties of this result are the ancestors of a and b
|
|
* that are children of the commonAncestor. Since they are siblings, their
|
|
* positions are comparable to determine order in the document.
|
|
*/
|
|
export interface CommonAncestorResultBranch<A extends LexicalNode, B extends LexicalNode> {
|
|
readonly type: 'branch';
|
|
readonly commonAncestor: ElementNode;
|
|
/** The ancestor of `a` that is a child of `commonAncestor` */
|
|
readonly a: A | ElementNode;
|
|
/** The ancestor of `b` that is a child of `commonAncestor` */
|
|
readonly b: B | ElementNode;
|
|
}
|
|
/**
|
|
* The result of comparing two nodes that share some common ancestor
|
|
*/
|
|
export type CommonAncestorResult<A extends LexicalNode, B extends LexicalNode> = CommonAncestorResultSame<A> | CommonAncestorResultAncestor<A & ElementNode> | CommonAncestorResultDescendant<B & ElementNode> | CommonAncestorResultBranch<A, B>;
|
|
/**
|
|
* Find a common ancestor of a and b and return a detailed result object,
|
|
* or null if there is no common ancestor between the two nodes.
|
|
*
|
|
* The result object will have a commonAncestor property, and the other
|
|
* properties can be used to quickly compare these positions in the tree.
|
|
*
|
|
* @param a A LexicalNode
|
|
* @param b A LexicalNode
|
|
* @returns A comparison result between the two nodes or null if they have no common ancestor
|
|
*/
|
|
export declare function $getCommonAncestor<A extends LexicalNode, B extends LexicalNode>(a: A, b: B): null | CommonAncestorResult<A, B>;
|
|
export {};
|