mirror of
https://github.com/facebook/lexical.git
synced 2025-05-17 15:18:47 +08:00
Create Flow definition file for Lexical core (#1350)
This commit is contained in:

committed by
acywatson

parent
198611d5bd
commit
993a2ea4ed
@ -2,6 +2,7 @@
|
||||
|
||||
packages/**/dist/*.js
|
||||
packages/**/config/*.js
|
||||
packages/**/*.js.flow
|
||||
packages/playwright
|
||||
packages/playwright-core
|
||||
packages/babel-plugin-transform-stylex
|
||||
|
@ -16,8 +16,6 @@ untyped-type-import=error
|
||||
server.max_workers=4
|
||||
exact_by_default=true
|
||||
|
||||
module.name_mapper='^lexical$' -> '<PROJECT_ROOT>/packages/lexical/src/index.js'
|
||||
|
||||
module.name_mapper='^lexical/HeadingNode' -> '<PROJECT_ROOT>/packages/lexical/src/nodes/extended/LexicalHeadingNode.js'
|
||||
module.name_mapper='^lexical/QuoteNode' -> '<PROJECT_ROOT>/packages/lexical/src/nodes/extended/LexicalQuoteNode.js'
|
||||
module.name_mapper='^lexical/CodeNode' -> '<PROJECT_ROOT>/packages/lexical/src/nodes/extended/LexicalCodeNode.js'
|
||||
@ -82,7 +80,6 @@ module.name_mapper='^@lexical/yjs$' -> '<PROJECT_ROOT>/packages/lexical-yjs/src/
|
||||
|
||||
module.name_mapper='^shared/invariant' -> '<PROJECT_ROOT>/packages/shared/src/invariant.js'
|
||||
module.name_mapper='^shared/environment' -> '<PROJECT_ROOT>/packages/shared/src/environment.js'
|
||||
module.name_mapper='^shared/getPossibleDecoratorNode' -> '<PROJECT_ROOT>/packages/shared/src/getPossibleDecoratorNode.js'
|
||||
module.name_mapper='^shared/useLayoutEffect' -> '<PROJECT_ROOT>/packages/shared/src/useLayoutEffect.js'
|
||||
module.name_mapper='^shared/canUseDOM' -> '<PROJECT_ROOT>/packages/shared/src/canUseDOM.js'
|
||||
|
||||
|
@ -86,8 +86,6 @@ module.exports = {
|
||||
'<rootDir>/packages/lexical/src/nodes/extended/LexicalQuoteNode.js',
|
||||
'^shared/canUseDOM$': '<rootDir>/packages/shared/src/canUseDOM.js',
|
||||
'^shared/environment$': '<rootDir>/packages/shared/src/environment.js',
|
||||
'^shared/getPossibleDecoratorNode$':
|
||||
'<rootDir>/packages/shared/src/getPossibleDecoratorNode.js',
|
||||
'^shared/invariant$': '<rootDir>/packages/shared/src/invariant.js',
|
||||
'^shared/useLayoutEffect$':
|
||||
'<rootDir>/packages/shared/src/useLayoutEffect.js',
|
||||
|
@ -22,14 +22,13 @@ import {$cloneContents} from '@lexical/helpers/selection';
|
||||
import {
|
||||
$createNodeFromParse,
|
||||
$createParagraphNode,
|
||||
$getDecoratorNode,
|
||||
$getSelection,
|
||||
$isDecoratorNode,
|
||||
$isElementNode,
|
||||
$isRangeSelection,
|
||||
} from 'lexical';
|
||||
|
||||
import getPossibleDecoratorNode from '../../shared/src/getPossibleDecoratorNode';
|
||||
|
||||
// TODO the Flow types here needs fixing
|
||||
export type EventHandler = (
|
||||
// $FlowFixMe: not sure how to handle this generic properly
|
||||
@ -216,7 +215,7 @@ export function $shouldOverrideDefaultCharacterSelection(
|
||||
selection: RangeSelection,
|
||||
isBackward: boolean,
|
||||
): boolean {
|
||||
const possibleNode = getPossibleDecoratorNode(selection.focus, isBackward);
|
||||
const possibleNode = $getDecoratorNode(selection.focus, isBackward);
|
||||
return $isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
|
||||
}
|
||||
|
||||
|
931
packages/lexical/Lexical.js.flow
Normal file
931
packages/lexical/Lexical.js.flow
Normal file
@ -0,0 +1,931 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
import type {Node as ReactNode} from 'react';
|
||||
|
||||
/**
|
||||
* LexicalEditor
|
||||
*/
|
||||
|
||||
type MutationListeners = Map<MutationListener, Class<LexicalNode>>;
|
||||
export type NodeMutation = 'created' | 'destroyed';
|
||||
export type ErrorListener = (error: Error) => void;
|
||||
type UpdateListener = ({
|
||||
tags: Set<string>,
|
||||
prevEditorState: EditorState,
|
||||
editorState: EditorState,
|
||||
dirtyLeaves: Set<NodeKey>,
|
||||
dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>,
|
||||
normalizedNodes: Set<NodeKey>,
|
||||
}) => void;
|
||||
type DecoratorListener = (decorator: {
|
||||
[NodeKey]: ReactNode,
|
||||
}) => void;
|
||||
type RootListener = (
|
||||
element: null | HTMLElement,
|
||||
element: null | HTMLElement,
|
||||
) => void;
|
||||
type TextContentListener = (text: string) => void;
|
||||
type MutationListener = (nodes: Map<NodeKey, NodeMutation>) => void;
|
||||
type CommandListener = (
|
||||
type: string,
|
||||
payload: CommandPayload,
|
||||
editor: LexicalEditor,
|
||||
) => boolean;
|
||||
|
||||
//$FlowFixMe
|
||||
type CommandPayload = any;
|
||||
type Listeners = {
|
||||
decorator: Set<DecoratorListener>,
|
||||
error: Set<ErrorListener>,
|
||||
mutation: MutationListeners,
|
||||
textcontent: Set<TextContentListener>,
|
||||
root: Set<RootListener>,
|
||||
update: Set<UpdateListener>,
|
||||
command: Array<Set<CommandListener>>,
|
||||
};
|
||||
type RegisteredNodes = Map<string, RegisteredNode>;
|
||||
type RegisteredNode = {
|
||||
klass: Class<LexicalNode>,
|
||||
transforms: Set<Transform<LexicalNode>>,
|
||||
};
|
||||
type Transform<T> = (node: T) => void;
|
||||
|
||||
type DOMConversionCache = Map<
|
||||
string,
|
||||
Array<(node: Node) => DOMConversion | null>,
|
||||
>;
|
||||
|
||||
declare export class LexicalEditor {
|
||||
_htmlConversions: DOMConversionCache;
|
||||
_parentEditor: null | LexicalEditor;
|
||||
_rootElement: null | HTMLElement;
|
||||
_editorState: EditorState;
|
||||
_pendingEditorState: null | EditorState;
|
||||
_compositionKey: null | NodeKey;
|
||||
_deferred: Array<() => void>;
|
||||
_updates: Array<[() => void, void | EditorUpdateOptions]>;
|
||||
_updating: boolean;
|
||||
_keyToDOMMap: Map<NodeKey, HTMLElement>;
|
||||
_listeners: Listeners;
|
||||
_nodes: RegisteredNodes;
|
||||
_decorators: {
|
||||
[NodeKey]: ReactNode,
|
||||
};
|
||||
_pendingDecorators: null | {
|
||||
[NodeKey]: ReactNode,
|
||||
};
|
||||
_config: EditorConfig<{...}>;
|
||||
_dirtyType: 0 | 1 | 2;
|
||||
_cloneNotNeeded: Set<NodeKey>;
|
||||
_dirtyLeaves: Set<NodeKey>;
|
||||
_dirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>;
|
||||
_normalizedNodes: Set<NodeKey>;
|
||||
_updateTags: Set<string>;
|
||||
_observer: null | MutationObserver;
|
||||
_key: string;
|
||||
isComposing(): boolean;
|
||||
addListener(type: 'error', listener: ErrorListener): () => void;
|
||||
addListener(type: 'update', listener: UpdateListener): () => void;
|
||||
addListener(type: 'root', listener: RootListener): () => void;
|
||||
addListener(type: 'decorator', listener: DecoratorListener): () => void;
|
||||
addListener(type: 'textcontent', listener: TextContentListener): () => void;
|
||||
addListener(
|
||||
type: 'command',
|
||||
listener: CommandListener,
|
||||
priority: CommandListenerPriority,
|
||||
): () => void;
|
||||
addListener(
|
||||
type: 'mutation',
|
||||
klass: Class<LexicalNode>,
|
||||
listener: MutationListener,
|
||||
): () => void;
|
||||
addTransform<T: LexicalNode>(
|
||||
klass: Class<T>,
|
||||
listener: Transform<T>,
|
||||
): () => void;
|
||||
execCommand(type: string, payload: CommandPayload): boolean;
|
||||
hasNodes(nodes: Array<Class<LexicalNode>>): boolean;
|
||||
getDecorators(): {
|
||||
[NodeKey]: ReactNode,
|
||||
};
|
||||
getRootElement(): null | HTMLElement;
|
||||
setRootElement(rootElement: null | HTMLElement): void;
|
||||
getElementByKey(key: NodeKey): null | HTMLElement;
|
||||
getEditorState(): EditorState;
|
||||
setEditorState(editorState: EditorState, options?: EditorSetOptions): void;
|
||||
parseEditorState(stringifiedEditorState: string): EditorState;
|
||||
update(updateFn: () => void, options?: EditorUpdateOptions): boolean;
|
||||
focus(callbackFn?: () => void): void;
|
||||
blur(): void;
|
||||
}
|
||||
type EditorUpdateOptions = {
|
||||
onUpdate?: () => void,
|
||||
tag?: string,
|
||||
skipTransforms?: true,
|
||||
};
|
||||
type EditorSetOptions = {
|
||||
tag?: string,
|
||||
};
|
||||
type EditorThemeClassName = string;
|
||||
type TextNodeThemeClasses = {
|
||||
base?: EditorThemeClassName,
|
||||
bold?: EditorThemeClassName,
|
||||
underline?: EditorThemeClassName,
|
||||
strikethrough?: EditorThemeClassName,
|
||||
underlineStrikethrough?: EditorThemeClassName,
|
||||
italic?: EditorThemeClassName,
|
||||
code?: EditorThemeClassName,
|
||||
};
|
||||
export type EditorThemeClasses = {
|
||||
ltr?: EditorThemeClassName,
|
||||
rtl?: EditorThemeClassName,
|
||||
root?: EditorThemeClassName,
|
||||
text?: TextNodeThemeClasses,
|
||||
paragraph?: EditorThemeClassName,
|
||||
image?: EditorThemeClassName,
|
||||
list?: {
|
||||
ul?: EditorThemeClassName,
|
||||
ul1?: EditorThemeClassName,
|
||||
ul2?: EditorThemeClassName,
|
||||
ul3?: EditorThemeClassName,
|
||||
ul4?: EditorThemeClassName,
|
||||
ul5?: EditorThemeClassName,
|
||||
ol?: EditorThemeClassName,
|
||||
ol1?: EditorThemeClassName,
|
||||
ol2?: EditorThemeClassName,
|
||||
ol3?: EditorThemeClassName,
|
||||
ol4?: EditorThemeClassName,
|
||||
ol5?: EditorThemeClassName,
|
||||
listitem?: EditorThemeClassName,
|
||||
nested?: {
|
||||
list?: EditorThemeClassName,
|
||||
listitem?: EditorThemeClassName,
|
||||
},
|
||||
},
|
||||
table?: EditorThemeClassName,
|
||||
tableRow?: EditorThemeClassName,
|
||||
tableCell?: EditorThemeClassName,
|
||||
tableCellHeader?: EditorThemeClassName,
|
||||
link?: EditorThemeClassName,
|
||||
quote?: EditorThemeClassName,
|
||||
code?: EditorThemeClassName,
|
||||
codeHighlight?: {[string]: EditorThemeClassName},
|
||||
hashtag?: EditorThemeClassName,
|
||||
heading?: {
|
||||
h1?: EditorThemeClassName,
|
||||
h2?: EditorThemeClassName,
|
||||
h3?: EditorThemeClassName,
|
||||
h4?: EditorThemeClassName,
|
||||
h5?: EditorThemeClassName,
|
||||
},
|
||||
// Handle other generic values
|
||||
[string]: EditorThemeClassName | {[string]: EditorThemeClassName},
|
||||
};
|
||||
export type EditorConfig<EditorContext> = {
|
||||
namespace: string,
|
||||
theme: EditorThemeClasses,
|
||||
context: EditorContext,
|
||||
disableEvents?: boolean,
|
||||
};
|
||||
export type CommandListenerEditorPriority = 0;
|
||||
export type CommandListenerLowPriority = 1;
|
||||
export type CommandListenerNormalPriority = 2;
|
||||
export type CommandListenerHighPriority = 3;
|
||||
export type CommandListenerCriticalPriority = 4;
|
||||
type CommandListenerPriority =
|
||||
| CommandListenerEditorPriority
|
||||
| CommandListenerLowPriority
|
||||
| CommandListenerNormalPriority
|
||||
| CommandListenerHighPriority
|
||||
| CommandListenerCriticalPriority;
|
||||
|
||||
export type IntentionallyMarkedAsDirtyElement = boolean;
|
||||
declare export function createEditor<EditorContext>(editorConfig?: {
|
||||
namespace?: string,
|
||||
editorState?: EditorState,
|
||||
theme?: EditorThemeClasses,
|
||||
context?: EditorContext,
|
||||
parentEditor?: LexicalEditor,
|
||||
nodes?: Array<Class<LexicalNode>>,
|
||||
onError?: (error: Error) => void,
|
||||
disableEvents?: boolean,
|
||||
}): LexicalEditor;
|
||||
|
||||
/**
|
||||
* LexicalEditorState
|
||||
*/
|
||||
export type ParsedEditorState = {
|
||||
_selection: null | {
|
||||
anchor: {
|
||||
key: string,
|
||||
offset: number,
|
||||
type: 'text' | 'element',
|
||||
},
|
||||
focus: {
|
||||
key: string,
|
||||
offset: number,
|
||||
type: 'text' | 'element',
|
||||
},
|
||||
},
|
||||
_nodeMap: Array<[NodeKey, ParsedNode]>,
|
||||
};
|
||||
type JSONEditorState = {
|
||||
_nodeMap: Array<[NodeKey, LexicalNode]>,
|
||||
_selection: null | ParsedSelection,
|
||||
};
|
||||
|
||||
declare export class EditorState {
|
||||
_nodeMap: NodeMap;
|
||||
_selection: null | RangeSelection | NodeSelection | GridSelection;
|
||||
_flushSync: boolean;
|
||||
_readOnly: boolean;
|
||||
constructor(
|
||||
nodeMap: NodeMap,
|
||||
selection?: RangeSelection | NodeSelection | GridSelection | null,
|
||||
): void;
|
||||
isEmpty(): boolean;
|
||||
read<V>(callbackFn: () => V): V;
|
||||
toJSON(space?: string | number): JSONEditorState;
|
||||
clone(
|
||||
selection?: RangeSelection | NodeSelection | GridSelection | null,
|
||||
): EditorState;
|
||||
}
|
||||
|
||||
/**
|
||||
* LexicalNode
|
||||
*/
|
||||
|
||||
export type NodeKey = string;
|
||||
declare export class LexicalNode {
|
||||
__type: string;
|
||||
__key: NodeKey;
|
||||
__parent: null | NodeKey;
|
||||
static getType(): string;
|
||||
static clone(data: $FlowFixMe): LexicalNode;
|
||||
constructor(key?: NodeKey): void;
|
||||
getType(): string;
|
||||
isAttached(): boolean;
|
||||
isSelected(): boolean;
|
||||
getKey(): NodeKey;
|
||||
getIndexWithinParent(): number;
|
||||
getParent(): ElementNode | null;
|
||||
getParentOrThrow(): ElementNode;
|
||||
getTopLevelElement(): null | ElementNode;
|
||||
getTopLevelElementOrThrow(): ElementNode;
|
||||
getParents(): Array<ElementNode>;
|
||||
getParentKeys(): Array<NodeKey>;
|
||||
getPreviousSibling(): LexicalNode | null;
|
||||
getPreviousSiblings(): Array<LexicalNode>;
|
||||
getNextSibling(): LexicalNode | null;
|
||||
getNextSiblings(): Array<LexicalNode>;
|
||||
getCommonAncestor(node: LexicalNode): ElementNode | null;
|
||||
is(object: ?LexicalNode): boolean;
|
||||
isBefore(targetNode: LexicalNode): boolean;
|
||||
isParentOf(targetNode: LexicalNode): boolean;
|
||||
getNodesBetween(targetNode: LexicalNode): Array<LexicalNode>;
|
||||
isDirty(): boolean;
|
||||
isComposing(): boolean;
|
||||
// $FlowFixMe
|
||||
getLatest<T: LexicalNode>(this: T): T;
|
||||
// $FlowFixMe
|
||||
getWritable<T: LexicalNode>(this: T): T;
|
||||
getTextContent(includeInert?: boolean, includeDirectionless?: false): string;
|
||||
getTextContentSize(
|
||||
includeInert?: boolean,
|
||||
includeDirectionless?: false,
|
||||
): number;
|
||||
// $FlowFixMe
|
||||
createDOM<EditorContext: Object>(
|
||||
config: EditorConfig<EditorContext>,
|
||||
editor: LexicalEditor,
|
||||
): HTMLElement;
|
||||
// $FlowFixMe
|
||||
updateDOM<EditorContext: Object>(
|
||||
// $FlowFixMe
|
||||
prevNode: any,
|
||||
dom: HTMLElement,
|
||||
config: EditorConfig<EditorContext>,
|
||||
): boolean;
|
||||
remove(): void;
|
||||
replace<N: LexicalNode>(replaceWith: N): N;
|
||||
insertAfter(nodeToInsert: LexicalNode): LexicalNode;
|
||||
insertBefore(nodeToInsert: LexicalNode): LexicalNode;
|
||||
selectPrevious(anchorOffset?: number, focusOffset?: number): Selection;
|
||||
selectNext(anchorOffset?: number, focusOffset?: number): Selection;
|
||||
markDirty(): void;
|
||||
}
|
||||
export type NodeMap = Map<NodeKey, LexicalNode>;
|
||||
|
||||
/**
|
||||
* LexicalParsing
|
||||
*/
|
||||
|
||||
export type ParsedNode = {
|
||||
__key: NodeKey,
|
||||
__type: string,
|
||||
__parent: null | NodeKey,
|
||||
...
|
||||
};
|
||||
export type ParsedNodeMap = Map<NodeKey, ParsedNode>;
|
||||
declare export function $createNodeFromParse(
|
||||
parsedNode: ParsedNode,
|
||||
parsedNodeMap: ParsedNodeMap,
|
||||
): LexicalNode;
|
||||
type ParsedSelection = {
|
||||
anchor: {
|
||||
key: NodeKey,
|
||||
offset: number,
|
||||
type: 'text' | 'element',
|
||||
},
|
||||
focus: {
|
||||
key: NodeKey,
|
||||
offset: number,
|
||||
type: 'text' | 'element',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* LexicalSelection
|
||||
*/
|
||||
|
||||
interface BaseSelection {
|
||||
clone(): BaseSelection;
|
||||
dirty: boolean;
|
||||
extract(): Array<LexicalNode>;
|
||||
getNodes(): Array<LexicalNode>;
|
||||
getTextContent(): string;
|
||||
insertRawText(text: string): void;
|
||||
is(selection: null | RangeSelection | NodeSelection | GridSelection): boolean;
|
||||
}
|
||||
|
||||
declare export class GridSelection implements BaseSelection {
|
||||
gridKey: NodeKey;
|
||||
anchorCellKey: NodeKey;
|
||||
focusCellKey: NodeKey;
|
||||
dirty: boolean;
|
||||
|
||||
constructor(
|
||||
gridKey: NodeKey,
|
||||
anchorCellKey: NodeKey,
|
||||
focusCellKey: NodeKey,
|
||||
): void;
|
||||
|
||||
is(selection: null | RangeSelection | NodeSelection | GridSelection): boolean;
|
||||
|
||||
set(gridKey: NodeKey, anchorCellKey: NodeKey, focusCellKey: NodeKey): void;
|
||||
|
||||
clone(): GridSelection;
|
||||
|
||||
extract(): Array<LexicalNode>;
|
||||
|
||||
insertRawText(): void;
|
||||
|
||||
insertText(): void;
|
||||
|
||||
getNodes(): Array<LexicalNode>;
|
||||
|
||||
getTextContent(): string;
|
||||
}
|
||||
|
||||
declare export function $isGridSelection(
|
||||
x: ?mixed,
|
||||
): boolean %checks(x instanceof GridSelection);
|
||||
|
||||
declare export class NodeSelection implements BaseSelection {
|
||||
_nodes: Set<NodeKey>;
|
||||
dirty: boolean;
|
||||
|
||||
constructor(objects: Set<NodeKey>): void;
|
||||
|
||||
is(selection: null | RangeSelection | NodeSelection | GridSelection): 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>;
|
||||
|
||||
getTextContent(): string;
|
||||
}
|
||||
|
||||
declare export function $isNodeSelection(
|
||||
x: ?mixed,
|
||||
): boolean %checks(x instanceof NodeSelection);
|
||||
|
||||
declare export class RangeSelection implements BaseSelection {
|
||||
anchor: PointType;
|
||||
focus: PointType;
|
||||
dirty: boolean;
|
||||
format: number;
|
||||
constructor(anchor: PointType, focus: PointType, format: number): void;
|
||||
is(selection: null | RangeSelection | GridSelection | NodeSelection): boolean;
|
||||
isBackward(): boolean;
|
||||
isCollapsed(): boolean;
|
||||
getNodes(): Array<LexicalNode>;
|
||||
setTextNodeRange(
|
||||
anchorNode: TextNode,
|
||||
anchorOffset: number,
|
||||
focusNode: TextNode,
|
||||
focusOffset: number,
|
||||
): void;
|
||||
getTextContent(): string;
|
||||
// $FlowFixMe DOM API
|
||||
applyDOMRange(range: StaticRange): void;
|
||||
clone(): RangeSelection;
|
||||
toggleFormat(format: TextFormatType): void;
|
||||
hasFormat(type: TextFormatType): boolean;
|
||||
insertText(text: string): void;
|
||||
insertRawText(text: string): void;
|
||||
removeText(): void;
|
||||
formatText(formatType: TextFormatType): void;
|
||||
insertNodes(nodes: Array<LexicalNode>, selectStart?: boolean): boolean;
|
||||
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;
|
||||
}
|
||||
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,
|
||||
isAtNodeEnd: () => boolean,
|
||||
};
|
||||
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,
|
||||
getCharacterOffset: () => number,
|
||||
isAtNodeEnd: () => boolean,
|
||||
};
|
||||
export type Point = PointType;
|
||||
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;
|
||||
getCharacterOffset(): number;
|
||||
getNode(): LexicalNode;
|
||||
set(key: NodeKey, offset: number, type: 'text' | 'element'): void;
|
||||
}
|
||||
|
||||
declare export function $createRangeSelection(): RangeSelection;
|
||||
declare export function $createNodeSelection(): NodeSelection;
|
||||
declare export function $createGridSelection(): GridSelection;
|
||||
declare export function $isRangeSelection(
|
||||
x: ?mixed,
|
||||
): boolean %checks(x instanceof RangeSelection);
|
||||
declare export function $getSelection(): null | RangeSelection;
|
||||
declare export function $getPreviousSelection(): null | RangeSelection;
|
||||
|
||||
/**
|
||||
* Decorator State
|
||||
*/
|
||||
|
||||
export type DecoratorStateValue =
|
||||
| DecoratorMap
|
||||
| DecoratorEditor
|
||||
| DecoratorArray
|
||||
| null
|
||||
| boolean
|
||||
| number
|
||||
| string;
|
||||
|
||||
declare export class DecoratorEditor {
|
||||
id: string;
|
||||
editorState: null | EditorState | string;
|
||||
editor: null | LexicalEditor;
|
||||
|
||||
constructor(id?: string, editorState?: string | EditorState): void;
|
||||
|
||||
init(editor: LexicalEditor): void;
|
||||
|
||||
set(editor: LexicalEditor): void;
|
||||
|
||||
toJSON(): $ReadOnly<{
|
||||
id: string,
|
||||
type: 'editor',
|
||||
editorState: null | string,
|
||||
}>;
|
||||
|
||||
isEmpty(): boolean;
|
||||
}
|
||||
|
||||
export type DecoratorMapObserver = (
|
||||
key: string,
|
||||
value: DecoratorStateValue,
|
||||
) => void;
|
||||
|
||||
export type DecoratorArrayObserver = (
|
||||
index: number,
|
||||
delCont: number,
|
||||
value: void | DecoratorStateValue,
|
||||
) => void;
|
||||
|
||||
declare export class DecoratorMap {
|
||||
_editor: LexicalEditor;
|
||||
_map: Map<string, DecoratorStateValue>;
|
||||
|
||||
constructor(
|
||||
editor: LexicalEditor,
|
||||
map?: Map<string, DecoratorStateValue>,
|
||||
): void;
|
||||
|
||||
get(key: string): void | DecoratorStateValue;
|
||||
|
||||
has(key: string): boolean;
|
||||
|
||||
set(key: string, value: DecoratorStateValue): void;
|
||||
|
||||
observe(observer: DecoratorMapObserver): () => void;
|
||||
|
||||
destroy(): void;
|
||||
|
||||
toJSON(): $ReadOnly<{
|
||||
type: 'map',
|
||||
map: Array<[string, DecoratorStateValue]>,
|
||||
}>;
|
||||
}
|
||||
|
||||
declare export function createDecoratorEditor(
|
||||
id?: string,
|
||||
editorState?: string | EditorState,
|
||||
): DecoratorEditor;
|
||||
|
||||
declare export function isDecoratorEditor(
|
||||
obj: ?mixed,
|
||||
): boolean %checks(obj instanceof DecoratorEditor);
|
||||
|
||||
declare export function createDecoratorMap(
|
||||
editor: LexicalEditor,
|
||||
map?: Map<string, DecoratorStateValue>,
|
||||
): DecoratorMap;
|
||||
|
||||
declare export function isDecoratorMap(
|
||||
obj: ?mixed,
|
||||
): boolean %checks(obj instanceof DecoratorMap);
|
||||
|
||||
declare export class DecoratorArray {
|
||||
_editor: LexicalEditor;
|
||||
_observers: Set<DecoratorArrayObserver>;
|
||||
_array: Array<DecoratorStateValue>;
|
||||
|
||||
constructor(editor: LexicalEditor, array?: Array<DecoratorStateValue>): void;
|
||||
|
||||
observe(observer: DecoratorArrayObserver): () => void;
|
||||
|
||||
map<V>(
|
||||
fn: (DecoratorStateValue, number, Array<DecoratorStateValue>) => V,
|
||||
): Array<V>;
|
||||
|
||||
reduce(
|
||||
fn: (DecoratorStateValue, DecoratorStateValue) => DecoratorStateValue,
|
||||
initial?: DecoratorStateValue,
|
||||
): DecoratorStateValue | void;
|
||||
|
||||
push(value: DecoratorStateValue): void;
|
||||
|
||||
getLength(): number;
|
||||
|
||||
splice(
|
||||
insertIndex: number,
|
||||
delCount: number,
|
||||
value?: DecoratorStateValue,
|
||||
): void;
|
||||
|
||||
indexOf(value: DecoratorStateValue): number;
|
||||
|
||||
destroy(): void;
|
||||
|
||||
toJSON(): $ReadOnly<{
|
||||
type: 'array',
|
||||
array: Array<DecoratorStateValue>,
|
||||
}>;
|
||||
}
|
||||
|
||||
declare export function createDecoratorArray(
|
||||
editor: LexicalEditor,
|
||||
list?: Array<DecoratorStateValue>,
|
||||
): DecoratorArray;
|
||||
|
||||
declare export function isDecoratorArray(
|
||||
x?: mixed,
|
||||
): boolean %checks(x instanceof DecoratorArray);
|
||||
|
||||
/**
|
||||
* LexicalTextNode
|
||||
*/
|
||||
|
||||
export type TextFormatType =
|
||||
| 'bold'
|
||||
| 'underline'
|
||||
| 'strikethrough'
|
||||
| 'italic'
|
||||
| 'code'
|
||||
| 'subscript'
|
||||
| 'superscript';
|
||||
type TextModeType = 'normal' | 'token' | 'segmented' | 'inert';
|
||||
|
||||
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;
|
||||
getFormat(): number;
|
||||
getStyle(): string;
|
||||
isToken(): boolean;
|
||||
isSegmented(): boolean;
|
||||
isInert(): boolean;
|
||||
isDirectionless(): boolean;
|
||||
isUnmergeable(): boolean;
|
||||
hasFormat(type: TextFormatType): boolean;
|
||||
isSimpleText(): boolean;
|
||||
getTextContent(includeInert?: boolean, includeDirectionless?: false): string;
|
||||
getFormatFlags(type: TextFormatType, alignWithFormat: null | number): number;
|
||||
// $FlowFixMe
|
||||
createDOM<EditorContext: Object>(
|
||||
config: EditorConfig<EditorContext>,
|
||||
): HTMLElement;
|
||||
// $FlowFixMe
|
||||
updateDOM<EditorContext: Object>(
|
||||
prevNode: TextNode,
|
||||
dom: HTMLElement,
|
||||
config: EditorConfig<EditorContext>,
|
||||
): boolean;
|
||||
selectionTransform(
|
||||
prevSelection: null | RangeSelection,
|
||||
nextSelection: RangeSelection,
|
||||
): void;
|
||||
setFormat(format: number): this;
|
||||
setStyle(style: string): this;
|
||||
toggleFormat(type: TextFormatType): TextNode;
|
||||
toggleDirectionless(): this;
|
||||
toggleUnmergeable(): this;
|
||||
setMode(type: TextModeType): this;
|
||||
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;
|
||||
}
|
||||
declare export function $createTextNode(text?: string): TextNode;
|
||||
declare export function $isTextNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof TextNode);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
declare export function $createLineBreakNode(): LineBreakNode;
|
||||
declare export function $isLineBreakNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof LineBreakNode);
|
||||
|
||||
/**
|
||||
* LexicalRootNode
|
||||
*/
|
||||
|
||||
declare export class RootNode extends ElementNode {
|
||||
__cachedText: null | string;
|
||||
static getType(): string;
|
||||
static clone(): RootNode;
|
||||
constructor(): void;
|
||||
getTextContent(includeInert?: boolean, includeDirectionless?: false): string;
|
||||
select(): RangeSelection;
|
||||
remove(): void;
|
||||
replace<N: LexicalNode>(node: N): N;
|
||||
insertBefore(): LexicalNode;
|
||||
insertAfter(node: LexicalNode): LexicalNode;
|
||||
updateDOM(prevNode: RootNode, dom: HTMLElement): false;
|
||||
append(...nodesToAppend: Array<LexicalNode>): ElementNode;
|
||||
canBeEmpty(): false;
|
||||
}
|
||||
declare export function $isRootNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof RootNode);
|
||||
|
||||
/**
|
||||
* LexicalElementNode
|
||||
*/
|
||||
export type ElementFormatType = 'left' | 'center' | 'right' | 'justify';
|
||||
declare export class ElementNode extends LexicalNode {
|
||||
__children: Array<NodeKey>;
|
||||
__format: number;
|
||||
__indent: number;
|
||||
__dir: 'ltr' | 'rtl' | null;
|
||||
constructor(key?: NodeKey): void;
|
||||
getFormat(): number;
|
||||
getIndent(): number;
|
||||
getChildren(): Array<LexicalNode>;
|
||||
getChildrenKeys(): Array<NodeKey>;
|
||||
getChildrenSize(): number;
|
||||
isEmpty(): boolean;
|
||||
isDirty(): boolean;
|
||||
getAllTextNodes(includeInert?: boolean): Array<TextNode>;
|
||||
getFirstDescendant(): null | LexicalNode;
|
||||
getLastDescendant(): null | LexicalNode;
|
||||
getDescendantByIndex(index: number): LexicalNode;
|
||||
getFirstChild<T: LexicalNode>(): null | T;
|
||||
getFirstChildOrThrow<T: LexicalNode>(): T;
|
||||
getLastChild(): null | LexicalNode;
|
||||
getChildAtIndex(index: number): null | LexicalNode;
|
||||
getTextContent(includeInert?: boolean, includeDirectionless?: false): string;
|
||||
getDirection(): 'ltr' | 'rtl' | null;
|
||||
hasFormat(type: ElementFormatType): boolean;
|
||||
select(_anchorOffset?: number, _focusOffset?: number): RangeSelection;
|
||||
selectStart(): RangeSelection;
|
||||
selectEnd(): RangeSelection;
|
||||
clear(): ElementNode;
|
||||
append(...nodesToAppend: Array<LexicalNode>): ElementNode;
|
||||
setDirection(direction: 'ltr' | 'rtl' | null): this;
|
||||
setFormat(type: ElementFormatType): this;
|
||||
setIndent(indentLevel: number): this;
|
||||
insertNewAfter(selection: RangeSelection): null | LexicalNode;
|
||||
canInsertTab(): boolean;
|
||||
collapseAtStart(selection: RangeSelection): boolean;
|
||||
excludeFromCopy(): boolean;
|
||||
canExtractContents(): boolean;
|
||||
canReplaceWith(replacement: LexicalNode): boolean;
|
||||
canInsertAfter(node: LexicalNode): boolean;
|
||||
canBeEmpty(): boolean;
|
||||
canInsertTextBefore(): boolean;
|
||||
canInsertTextAfter(): boolean;
|
||||
isInline(): boolean;
|
||||
canSelectionRemove(): boolean;
|
||||
splice(
|
||||
start: number,
|
||||
deleteCount: number,
|
||||
nodesToInsert: Array<LexicalNode>,
|
||||
): ElementNode;
|
||||
}
|
||||
declare export function $isElementNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof ElementNode);
|
||||
|
||||
/**
|
||||
* LexicalDecoratorNode
|
||||
*/
|
||||
|
||||
declare export class DecoratorNode extends LexicalNode {
|
||||
__state: DecoratorMap;
|
||||
constructor(state?: DecoratorMap, key?: NodeKey): void;
|
||||
decorate(editor: LexicalEditor): ReactNode;
|
||||
isIsolated(): boolean;
|
||||
}
|
||||
declare export function $isDecoratorNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof DecoratorNode);
|
||||
|
||||
/**
|
||||
* LexicalHorizontalRuleNode
|
||||
*/
|
||||
declare export class HorizontalRuleNode extends LexicalNode {
|
||||
static getType(): string;
|
||||
static clone(node: HorizontalRuleNode): HorizontalRuleNode;
|
||||
constructor(key?: NodeKey): void;
|
||||
createDOM(): HTMLElement;
|
||||
updateDOM(): false;
|
||||
}
|
||||
declare export function $createHorizontalRuleNode(): HorizontalRuleNode;
|
||||
declare export function $isHorizontalRuleNode(node: ?LexicalNode): boolean;
|
||||
|
||||
/**
|
||||
* LexicalParagraphNode
|
||||
*/
|
||||
declare export class ParagraphNode extends ElementNode {
|
||||
static getType(): string;
|
||||
static clone(node: ParagraphNode): ParagraphNode;
|
||||
constructor(key?: NodeKey): void;
|
||||
createDOM<EditorContext>(config: EditorConfig<EditorContext>): HTMLElement;
|
||||
updateDOM(prevNode: ParagraphNode, dom: HTMLElement): boolean;
|
||||
insertNewAfter(): ParagraphNode;
|
||||
collapseAtStart(): boolean;
|
||||
}
|
||||
declare export function $createParagraphNode(): ParagraphNode;
|
||||
declare export function $isParagraphNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof ParagraphNode);
|
||||
|
||||
declare export class GridNode extends ElementNode {}
|
||||
|
||||
declare export function $isGridNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof GridNode);
|
||||
|
||||
declare export class GridRowNode extends ElementNode {}
|
||||
|
||||
declare export function $isGridRowNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof GridRowNode);
|
||||
|
||||
declare export class GridCellNode extends ElementNode {
|
||||
__colSpan: number;
|
||||
|
||||
constructor(colSpan: number, key?: NodeKey): void;
|
||||
}
|
||||
|
||||
declare export function $isGridCellNode(
|
||||
node: ?LexicalNode,
|
||||
): boolean %checks(node instanceof GridCellNode);
|
||||
|
||||
/**
|
||||
* LexicalUtils
|
||||
*/
|
||||
|
||||
declare export function $getNearestNodeFromDOMNode(
|
||||
startingDOM: Node,
|
||||
): LexicalNode | null;
|
||||
declare export function $getNodeByKey<N: LexicalNode>(key: NodeKey): N | null;
|
||||
declare export function $getRoot(): RootNode;
|
||||
declare export function $isLeafNode(node: ?LexicalNode): boolean;
|
||||
declare export function $setCompositionKey(
|
||||
compositionKey: null | NodeKey,
|
||||
): void;
|
||||
declare export function $setSelection(
|
||||
selection: null | RangeSelection | NodeSelection | GridSelection,
|
||||
): void;
|
||||
|
||||
declare export var VERSION: string;
|
||||
|
||||
export type DOMConversion = {
|
||||
conversion: DOMConversionFn,
|
||||
priority: 0 | 1 | 2 | 3 | 4,
|
||||
};
|
||||
export type DOMConversionFn = (
|
||||
element: Node,
|
||||
parent?: Node,
|
||||
) => DOMConversionOutput;
|
||||
export type DOMChildConversion = (lexicalNode: LexicalNode) => void;
|
||||
export type DOMConversionMap = {
|
||||
[NodeName]: (node: Node) => DOMConversion | null,
|
||||
};
|
||||
type NodeName = string;
|
||||
export type DOMConversionOutput = {
|
||||
after?: (childLexicalNodes: Array<LexicalNode>) => Array<LexicalNode>,
|
||||
forChild?: DOMChildConversion,
|
||||
node: LexicalNode | null,
|
||||
};
|
||||
|
||||
declare export function $getDecoratorNode(
|
||||
focus: Point,
|
||||
isBackward: boolean,
|
||||
): null | LexicalNode;
|
@ -14,7 +14,6 @@ import type {ParsedSelection} from './LexicalParsing';
|
||||
import type {ElementNode} from './nodes/base/LexicalElementNode';
|
||||
import type {TextFormatType} from './nodes/base/LexicalTextNode';
|
||||
|
||||
import getPossibleDecoratorNode from 'shared/getPossibleDecoratorNode';
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
import {
|
||||
@ -38,6 +37,7 @@ import {
|
||||
} from './LexicalUpdates';
|
||||
import {
|
||||
$getCompositionKey,
|
||||
$getDecoratorNode,
|
||||
$getNodeByKey,
|
||||
$isTokenOrInert,
|
||||
$setCompositionKey,
|
||||
@ -378,6 +378,7 @@ export class GridSelection implements BaseSelection {
|
||||
return textContent;
|
||||
}
|
||||
}
|
||||
|
||||
export function $isGridSelection(x: ?mixed): boolean %checks {
|
||||
return x instanceof GridSelection;
|
||||
}
|
||||
@ -1355,7 +1356,7 @@ export class RangeSelection implements BaseSelection {
|
||||
const collapse = alter === 'move';
|
||||
|
||||
// Handle the selection movement around decorators.
|
||||
const possibleNode = getPossibleDecoratorNode(focus, isBackward);
|
||||
const possibleNode = $getDecoratorNode(focus, isBackward);
|
||||
if ($isDecoratorNode(possibleNode) && !possibleNode.isIsolated()) {
|
||||
const sibling = isBackward
|
||||
? possibleNode.getPreviousSibling()
|
||||
|
@ -20,6 +20,7 @@ import type {LexicalNode, NodeKey, NodeMap} from './LexicalNode';
|
||||
import type {
|
||||
GridSelection,
|
||||
NodeSelection,
|
||||
PointType,
|
||||
RangeSelection,
|
||||
} from './LexicalSelection';
|
||||
import type {RootNode} from './nodes/base/LexicalRootNode';
|
||||
@ -38,6 +39,7 @@ import {
|
||||
$isLineBreakNode,
|
||||
$isRangeSelection,
|
||||
$isTextNode,
|
||||
ElementNode,
|
||||
} from '.';
|
||||
import {
|
||||
DOM_TEXT_TYPE,
|
||||
@ -840,3 +842,53 @@ export function $nodesOfType<T: LexicalNode>(klass: Class<T>): Array<T> {
|
||||
}
|
||||
return nodesOfType;
|
||||
}
|
||||
|
||||
function resolveElement(
|
||||
element: ElementNode,
|
||||
isBackward: boolean,
|
||||
focusOffset: number,
|
||||
): LexicalNode | null {
|
||||
const parent = element.getParent();
|
||||
let offset = focusOffset;
|
||||
let block = element;
|
||||
if (parent !== null) {
|
||||
if (isBackward && focusOffset === 0) {
|
||||
offset = block.getIndexWithinParent();
|
||||
block = parent;
|
||||
} else if (!isBackward && focusOffset === block.getChildrenSize()) {
|
||||
offset = block.getIndexWithinParent() + 1;
|
||||
block = parent;
|
||||
}
|
||||
}
|
||||
return block.getChildAtIndex(isBackward ? offset - 1 : offset);
|
||||
}
|
||||
|
||||
export function $getDecoratorNode(
|
||||
focus: PointType,
|
||||
isBackward: boolean,
|
||||
): null | LexicalNode {
|
||||
const focusOffset = focus.offset;
|
||||
if (focus.type === 'element') {
|
||||
const block = focus.getNode();
|
||||
return resolveElement(block, isBackward, focusOffset);
|
||||
} else {
|
||||
const focusNode = focus.getNode();
|
||||
if (
|
||||
(isBackward && focusOffset === 0) ||
|
||||
(!isBackward && focusOffset === focusNode.getTextContentSize())
|
||||
) {
|
||||
const possibleNode = isBackward
|
||||
? focusNode.getPreviousSibling()
|
||||
: focusNode.getNextSibling();
|
||||
if (possibleNode === null) {
|
||||
return resolveElement(
|
||||
focusNode.getParentOrThrow(),
|
||||
isBackward,
|
||||
focusNode.getIndexWithinParent() + (isBackward ? 0 : 1),
|
||||
);
|
||||
}
|
||||
return possibleNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
$isRangeSelection,
|
||||
} from './LexicalSelection';
|
||||
import {
|
||||
$getDecoratorNode,
|
||||
$getNearestNodeFromDOMNode,
|
||||
$getNodeByKey,
|
||||
$getRoot,
|
||||
@ -59,50 +60,6 @@ import {
|
||||
TextNode,
|
||||
} from './nodes/base/LexicalTextNode';
|
||||
|
||||
export type {
|
||||
CommandListenerCriticalPriority,
|
||||
CommandListenerEditorPriority,
|
||||
CommandListenerHighPriority,
|
||||
CommandListenerLowPriority,
|
||||
CommandListenerNormalPriority,
|
||||
EditorConfig,
|
||||
EditorThemeClasses,
|
||||
IntentionallyMarkedAsDirtyElement,
|
||||
LexicalEditor,
|
||||
NodeMutation,
|
||||
RegisteredNodes,
|
||||
} from './LexicalEditor';
|
||||
export type {EditorState, ParsedEditorState} from './LexicalEditorState';
|
||||
export type {
|
||||
DOMChildConversion,
|
||||
DOMConversion,
|
||||
DOMConversionFn,
|
||||
DOMConversionMap,
|
||||
DOMConversionOutput,
|
||||
LexicalNode,
|
||||
NodeKey,
|
||||
NodeMap,
|
||||
} from './LexicalNode';
|
||||
export type {ParsedNode, ParsedNodeMap} from './LexicalParsing';
|
||||
export type {
|
||||
ElementPointType as ElementPoint,
|
||||
GridSelection,
|
||||
NodeSelection,
|
||||
PointType as Point,
|
||||
RangeSelection,
|
||||
TextPointType as TextPoint,
|
||||
} from './LexicalSelection';
|
||||
export type {
|
||||
DecoratorArray,
|
||||
DecoratorEditor,
|
||||
DecoratorMap,
|
||||
DecoratorStateValue,
|
||||
} from './nodes/base/LexicalDecoratorNode';
|
||||
export type {ElementFormatType} from './nodes/base/LexicalElementNode';
|
||||
export type {LineBreakNode} from './nodes/base/LexicalLineBreakNode';
|
||||
export type {RootNode} from './nodes/base/LexicalRootNode';
|
||||
export type {TextFormatType} from './nodes/base/LexicalTextNode';
|
||||
|
||||
export {
|
||||
$createGridSelection,
|
||||
$createLineBreakNode,
|
||||
@ -111,6 +68,7 @@ export {
|
||||
$createParagraphNode,
|
||||
$createRangeSelection,
|
||||
$createTextNode,
|
||||
$getDecoratorNode,
|
||||
$getNearestNodeFromDOMNode,
|
||||
$getNodeByKey,
|
||||
$getPreviousSelection,
|
||||
|
@ -7,9 +7,13 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {EditorThemeClasses} from '../../LexicalEditor';
|
||||
import type {DOMConversionMap, DOMConversionOutput} from '../../LexicalNode';
|
||||
import type {EditorConfig, LexicalNode, NodeKey} from 'lexical';
|
||||
import type {EditorConfig, EditorThemeClasses} from '../../LexicalEditor';
|
||||
import type {
|
||||
DOMConversionMap,
|
||||
DOMConversionOutput,
|
||||
LexicalNode,
|
||||
NodeKey,
|
||||
} from '../../LexicalNode';
|
||||
|
||||
import {getCachedClassNameArray} from '../../LexicalUtils';
|
||||
import {ElementNode} from './LexicalElementNode';
|
||||
|
@ -7,8 +7,9 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {DOMConversionMap, DOMConversionOutput} from '../../LexicalNode';
|
||||
import type {
|
||||
DOMConversionMap,
|
||||
DOMConversionOutput,
|
||||
EditorConfig,
|
||||
LexicalNode,
|
||||
NodeKey,
|
||||
|
@ -7,8 +7,14 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {DOMConversionMap, DOMConversionOutput} from '../../LexicalNode';
|
||||
import type {EditorConfig, LexicalNode, NodeKey, ParagraphNode} from 'lexical';
|
||||
import type {
|
||||
DOMConversionMap,
|
||||
DOMConversionOutput,
|
||||
EditorConfig,
|
||||
LexicalNode,
|
||||
NodeKey,
|
||||
ParagraphNode,
|
||||
} from 'lexical';
|
||||
|
||||
import {addClassNamesToElement} from '@lexical/helpers/elements';
|
||||
import {$createParagraphNode, ElementNode} from 'lexical';
|
||||
|
@ -7,8 +7,14 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {DOMConversionMap, DOMConversionOutput} from '../../LexicalNode';
|
||||
import type {EditorConfig, LexicalNode, NodeKey, RangeSelection} from 'lexical';
|
||||
import type {
|
||||
DOMConversionMap,
|
||||
DOMConversionOutput,
|
||||
EditorConfig,
|
||||
LexicalNode,
|
||||
NodeKey,
|
||||
RangeSelection,
|
||||
} from 'lexical';
|
||||
|
||||
import {addClassNamesToElement} from '@lexical/helpers/elements';
|
||||
import {$isElementNode, ElementNode} from 'lexical';
|
||||
|
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
import type {ElementNode, LexicalNode, Point} from 'lexical';
|
||||
|
||||
function resolveElement(
|
||||
element: ElementNode,
|
||||
isBackward: boolean,
|
||||
focusOffset: number,
|
||||
): LexicalNode | null {
|
||||
const parent = element.getParent();
|
||||
let offset = focusOffset;
|
||||
let block = element;
|
||||
if (parent !== null) {
|
||||
if (isBackward && focusOffset === 0) {
|
||||
offset = block.getIndexWithinParent();
|
||||
block = parent;
|
||||
} else if (!isBackward && focusOffset === block.getChildrenSize()) {
|
||||
offset = block.getIndexWithinParent() + 1;
|
||||
block = parent;
|
||||
}
|
||||
}
|
||||
return block.getChildAtIndex(isBackward ? offset - 1 : offset);
|
||||
}
|
||||
|
||||
export default function getPossibleDecoratorNode(
|
||||
focus: Point,
|
||||
isBackward: boolean,
|
||||
): null | LexicalNode {
|
||||
const focusOffset = focus.offset;
|
||||
if (focus.type === 'element') {
|
||||
const block = focus.getNode();
|
||||
return resolveElement(block, isBackward, focusOffset);
|
||||
} else {
|
||||
const focusNode = focus.getNode();
|
||||
if (
|
||||
(isBackward && focusOffset === 0) ||
|
||||
(!isBackward && focusOffset === focusNode.getTextContentSize())
|
||||
) {
|
||||
const possibleNode = isBackward
|
||||
? focusNode.getPreviousSibling()
|
||||
: focusNode.getNextSibling();
|
||||
if (possibleNode === null) {
|
||||
return resolveElement(
|
||||
focusNode.getParentOrThrow(),
|
||||
isBackward,
|
||||
focusNode.getIndexWithinParent() + (isBackward ? 0 : 1),
|
||||
);
|
||||
}
|
||||
return possibleNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
Reference in New Issue
Block a user