@ekz/lexical-utils 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts ADDED
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import { type CaretDirection, type EditorState, ElementNode, type Klass, type LexicalEditor, type LexicalNode, type NodeCaret, PointCaret, type SiblingCaret, SplitAtPointCaretNextOptions, StateConfig, ValueOrUpdater } from '@ekz/lexical';
9
+ export { default as markSelection } from './markSelection';
10
+ export { default as positionNodeOnRange } from './positionNodeOnRange';
11
+ export { default as selectionAlwaysOnDisplay } from './selectionAlwaysOnDisplay';
12
+ export { $findMatchingParent, $getAdjacentSiblingOrParentSiblingCaret, $splitNode, addClassNamesToElement, isBlockDomNode, isHTMLAnchorElement, isHTMLElement, isInlineDomNode, mergeRegister, removeClassNamesFromElement, } from '@ekz/lexical';
13
+ export declare const CAN_USE_BEFORE_INPUT: boolean;
14
+ export declare const CAN_USE_DOM: boolean;
15
+ export declare const IS_ANDROID: boolean;
16
+ export declare const IS_ANDROID_CHROME: boolean;
17
+ export declare const IS_APPLE: boolean;
18
+ export declare const IS_APPLE_WEBKIT: boolean;
19
+ export declare const IS_CHROME: boolean;
20
+ export declare const IS_FIREFOX: boolean;
21
+ export declare const IS_IOS: boolean;
22
+ export declare const IS_SAFARI: boolean;
23
+ /**
24
+ * Returns true if the file type matches the types passed within the acceptableMimeTypes array, false otherwise.
25
+ * The types passed must be strings and are CASE-SENSITIVE.
26
+ * eg. if file is of type 'text' and acceptableMimeTypes = ['TEXT', 'IMAGE'] the function will return false.
27
+ * @param file - The file you want to type check.
28
+ * @param acceptableMimeTypes - An array of strings of types which the file is checked against.
29
+ * @returns true if the file is an acceptable mime type, false otherwise.
30
+ */
31
+ export declare function isMimeType(file: File, acceptableMimeTypes: Array<string>): boolean;
32
+ /**
33
+ * Lexical File Reader with:
34
+ * 1. MIME type support
35
+ * 2. batched results (HistoryPlugin compatibility)
36
+ * 3. Order aware (respects the order when multiple Files are passed)
37
+ *
38
+ * const filesResult = await mediaFileReader(files, ['image/']);
39
+ * filesResult.forEach(file => editor.dispatchCommand('INSERT_IMAGE', \\{
40
+ * src: file.result,
41
+ * \\}));
42
+ */
43
+ export declare function mediaFileReader(files: Array<File>, acceptableMimeTypes: Array<string>): Promise<Array<{
44
+ file: File;
45
+ result: string;
46
+ }>>;
47
+ export interface DFSNode {
48
+ readonly depth: number;
49
+ readonly node: LexicalNode;
50
+ }
51
+ /**
52
+ * "Depth-First Search" starts at the root/top node of a tree and goes as far as it can down a branch end
53
+ * before backtracking and finding a new path. Consider solving a maze by hugging either wall, moving down a
54
+ * branch until you hit a dead-end (leaf) and backtracking to find the nearest branching path and repeat.
55
+ * It will then return all the nodes found in the search in an array of objects.
56
+ * Preorder traversal is used, meaning that nodes are listed in the order of when they are FIRST encountered.
57
+ * @param startNode - The node to start the search (inclusive), if omitted, it will start at the root node.
58
+ * @param endNode - The node to end the search (inclusive), if omitted, it will find all descendants of the startingNode. If endNode
59
+ * is an ElementNode, it will stop before visiting any of its children.
60
+ * @returns An array of objects of all the nodes found by the search, including their depth into the tree.
61
+ * \\{depth: number, node: LexicalNode\\} It will always return at least 1 node (the start node).
62
+ */
63
+ export declare function $dfs(startNode?: LexicalNode, endNode?: LexicalNode): Array<DFSNode>;
64
+ /**
65
+ * Get the adjacent caret in the same direction
66
+ *
67
+ * @param caret A caret or null
68
+ * @returns `caret.getAdjacentCaret()` or `null`
69
+ */
70
+ export declare function $getAdjacentCaret<D extends CaretDirection>(caret: null | NodeCaret<D>): null | SiblingCaret<LexicalNode, D>;
71
+ /**
72
+ * $dfs iterator (right to left). Tree traversal is done on the fly as new values are requested with O(1) memory.
73
+ * @param startNode - The node to start the search, if omitted, it will start at the root node.
74
+ * @param endNode - The node to end the search, if omitted, it will find all descendants of the startingNode.
75
+ * @returns An iterator, each yielded value is a DFSNode. It will always return at least 1 node (the start node).
76
+ */
77
+ export declare function $reverseDfs(startNode?: LexicalNode, endNode?: LexicalNode): Array<DFSNode>;
78
+ /**
79
+ * $dfs iterator (left to right). Tree traversal is done on the fly as new values are requested with O(1) memory.
80
+ * Preorder traversal is used, meaning that nodes are iterated over in the order of when they are FIRST encountered.
81
+ * @param startNode - The node to start the search (inclusive), if omitted, it will start at the root node.
82
+ * @param endNode - The node to end the search (inclusive), if omitted, it will find all descendants of the startingNode.
83
+ * If endNode is an ElementNode, the iterator will end as soon as it reaches the endNode (no children will be visited).
84
+ * @returns An iterator, each yielded value is a DFSNode. It will always return at least 1 node (the start node).
85
+ */
86
+ export declare function $dfsIterator(startNode?: LexicalNode, endNode?: LexicalNode): IterableIterator<DFSNode>;
87
+ /**
88
+ * Returns the Node sibling when this exists, otherwise the closest parent sibling. For example
89
+ * R -> P -> T1, T2
90
+ * -> P2
91
+ * returns T2 for node T1, P2 for node T2, and null for node P2.
92
+ * @param node LexicalNode.
93
+ * @returns An array (tuple) containing the found Lexical node and the depth difference, or null, if this node doesn't exist.
94
+ */
95
+ export declare function $getNextSiblingOrParentSibling(node: LexicalNode): null | [LexicalNode, number];
96
+ export declare function $getDepth(node: null | LexicalNode): number;
97
+ /**
98
+ * Performs a right-to-left preorder tree traversal.
99
+ * From the starting node it goes to the rightmost child, than backtracks to parent and finds new rightmost path.
100
+ * It will return the next node in traversal sequence after the startingNode.
101
+ * The traversal is similar to $dfs functions above, but the nodes are visited right-to-left, not left-to-right.
102
+ * @param startingNode - The node to start the search.
103
+ * @returns The next node in pre-order right to left traversal sequence or `null`, if the node does not exist
104
+ */
105
+ export declare function $getNextRightPreorderNode(startingNode: LexicalNode): LexicalNode | null;
106
+ /**
107
+ * $dfs iterator (right to left). Tree traversal is done on the fly as new values are requested with O(1) memory.
108
+ * @param startNode - The node to start the search, if omitted, it will start at the root node.
109
+ * @param endNode - The node to end the search, if omitted, it will find all descendants of the startingNode.
110
+ * @returns An iterator, each yielded value is a DFSNode. It will always return at least 1 node (the start node).
111
+ */
112
+ export declare function $reverseDfsIterator(startNode?: LexicalNode, endNode?: LexicalNode): IterableIterator<DFSNode>;
113
+ /**
114
+ * Takes a node and traverses up its ancestors (toward the root node)
115
+ * in order to find a specific type of node.
116
+ * @param node - the node to begin searching.
117
+ * @param klass - an instance of the type of node to look for.
118
+ * @returns the node of type klass that was passed, or null if none exist.
119
+ */
120
+ export declare function $getNearestNodeOfType<T extends ElementNode>(node: LexicalNode, klass: Klass<T>): T | null;
121
+ /**
122
+ * Returns the element node of the nearest ancestor, otherwise throws an error.
123
+ * @param startNode - The starting node of the search
124
+ * @returns The ancestor node found
125
+ */
126
+ export declare function $getNearestBlockElementAncestorOrThrow(startNode: LexicalNode): ElementNode;
127
+ export type DOMNodeToLexicalConversion = (element: Node) => LexicalNode;
128
+ export type DOMNodeToLexicalConversionMap = Record<string, DOMNodeToLexicalConversion>;
129
+ /**
130
+ * Attempts to resolve nested element nodes of the same type into a single node of that type.
131
+ * It is generally used for marks/commenting
132
+ * @param editor - The lexical editor
133
+ * @param targetNode - The target for the nested element to be extracted from.
134
+ * @param cloneNode - See {@link $createMarkNode}
135
+ * @param handleOverlap - Handles any overlap between the node to extract and the targetNode
136
+ * @returns The lexical editor
137
+ */
138
+ export declare function registerNestedElementResolver<N extends ElementNode>(editor: LexicalEditor, targetNode: Klass<N>, cloneNode: (from: N) => N, handleOverlap: (from: N, to: N) => void): () => void;
139
+ /**
140
+ * Clones the editor and marks it as dirty to be reconciled. If there was a selection,
141
+ * it would be set back to its previous state, or null otherwise.
142
+ * @param editor - The lexical editor
143
+ * @param editorState - The editor's state
144
+ */
145
+ export declare function $restoreEditorState(editor: LexicalEditor, editorState: EditorState): void;
146
+ /**
147
+ * If the selected insertion area is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}),
148
+ * the node will be appended there, otherwise, it will be inserted before the insertion area.
149
+ * If there is no selection where the node is to be inserted, it will be appended after any current nodes
150
+ * within the tree, as a child of the root node. A paragraph will then be added after the inserted node and selected.
151
+ * @param node - The node to be inserted
152
+ * @returns The node after its insertion
153
+ */
154
+ export declare function $insertNodeToNearestRoot<T extends LexicalNode>(node: T): T;
155
+ /**
156
+ * If the insertion caret is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}),
157
+ * the node will be inserted there, otherwise the parent nodes will be split according to the
158
+ * given options.
159
+ * @param node - The node to be inserted
160
+ * @param caret - The location to insert or split from
161
+ * @returns The node after its insertion
162
+ */
163
+ export declare function $insertNodeToNearestRootAtCaret<T extends LexicalNode, D extends CaretDirection>(node: T, caret: PointCaret<D>, options?: SplitAtPointCaretNextOptions): NodeCaret<D>;
164
+ /**
165
+ * Wraps the node into another node created from a createElementNode function, eg. $createParagraphNode
166
+ * @param node - Node to be wrapped.
167
+ * @param createElementNode - Creates a new lexical element to wrap the to-be-wrapped node and returns it.
168
+ * @returns A new lexical element with the previous node appended within (as a child, including its children).
169
+ */
170
+ export declare function $wrapNodeInElement(node: LexicalNode, createElementNode: () => ElementNode): ElementNode;
171
+ export type ObjectKlass<T> = new (...args: any[]) => T;
172
+ /**
173
+ * @param object = The instance of the type
174
+ * @param objectClass = The class of the type
175
+ * @returns Whether the object is has the same Klass of the objectClass, ignoring the difference across window (e.g. different iframes)
176
+ */
177
+ export declare function objectKlassEquals<T>(object: unknown, objectClass: ObjectKlass<T>): object is T;
178
+ /**
179
+ * @deprecated Use Array filter or flatMap
180
+ *
181
+ * Filter the nodes
182
+ * @param nodes Array of nodes that needs to be filtered
183
+ * @param filterFn A filter function that returns node if the current node satisfies the condition otherwise null
184
+ * @returns Array of filtered nodes
185
+ */
186
+ export declare function $filter<T>(nodes: Array<LexicalNode>, filterFn: (node: LexicalNode) => null | T): Array<T>;
187
+ /**
188
+ * Appends the node before the first child of the parent node
189
+ * @param parent A parent node
190
+ * @param node Node that needs to be appended
191
+ */
192
+ export declare function $insertFirst(parent: ElementNode, node: LexicalNode): void;
193
+ /**
194
+ * Calculates the zoom level of an element as a result of using
195
+ * css zoom property. For browsers that implement standardized CSS
196
+ * zoom (Firefox, Chrome >= 128), this will always return 1.
197
+ * @param element
198
+ * @param useManualZoom - If true, always use zoom level will be calculated manually, otherwise it will be calculated on as needed basis.
199
+ */
200
+ export declare function calculateZoomLevel(element: Element | null, useManualZoom?: boolean): number;
201
+ /**
202
+ * Checks if the editor is a nested editor created by LexicalNestedComposer
203
+ */
204
+ export declare function $isEditorIsNestedEditor(editor: LexicalEditor): boolean;
205
+ /**
206
+ * A depth first last-to-first traversal of root that stops at each node that matches
207
+ * $predicate and ensures that its parent is root. This is typically used to discard
208
+ * invalid or unsupported wrapping nodes. For example, a TableNode must only have
209
+ * TableRowNode as children, but an importer might add invalid nodes based on
210
+ * caption, tbody, thead, etc. and this will unwrap and discard those.
211
+ *
212
+ * @param root The root to start the traversal
213
+ * @param $predicate Should return true for nodes that are permitted to be children of root
214
+ * @returns true if this unwrapped or removed any nodes
215
+ */
216
+ export declare function $unwrapAndFilterDescendants(root: ElementNode, $predicate: (node: LexicalNode) => boolean): boolean;
217
+ /**
218
+ * A depth first traversal of the children array that stops at and collects
219
+ * each node that `$predicate` matches. This is typically used to discard
220
+ * invalid or unsupported wrapping nodes on a children array in the `after`
221
+ * of an {@link lexical!DOMConversionOutput}. For example, a TableNode must only have
222
+ * TableRowNode as children, but an importer might add invalid nodes based on
223
+ * caption, tbody, thead, etc. and this will unwrap and discard those.
224
+ *
225
+ * This function is read-only and performs no mutation operations, which makes
226
+ * it suitable for import and export purposes but likely not for any in-place
227
+ * mutation. You should use {@link $unwrapAndFilterDescendants} for in-place
228
+ * mutations such as node transforms.
229
+ *
230
+ * @param children The children to traverse
231
+ * @param $predicate Should return true for nodes that are permitted to be children of root
232
+ * @returns The children or their descendants that match $predicate
233
+ */
234
+ export declare function $descendantsMatching<T extends LexicalNode>(children: LexicalNode[], $predicate: (node: LexicalNode) => node is T): T[];
235
+ /**
236
+ * Return an iterator that yields each child of node from first to last, taking
237
+ * care to preserve the next sibling before yielding the value in case the caller
238
+ * removes the yielded node.
239
+ *
240
+ * @param node The node whose children to iterate
241
+ * @returns An iterator of the node's children
242
+ */
243
+ export declare function $firstToLastIterator(node: ElementNode): Iterable<LexicalNode>;
244
+ /**
245
+ * Return an iterator that yields each child of node from last to first, taking
246
+ * care to preserve the previous sibling before yielding the value in case the caller
247
+ * removes the yielded node.
248
+ *
249
+ * @param node The node whose children to iterate
250
+ * @returns An iterator of the node's children
251
+ */
252
+ export declare function $lastToFirstIterator(node: ElementNode): Iterable<LexicalNode>;
253
+ /**
254
+ * Replace this node with its children
255
+ *
256
+ * @param node The ElementNode to unwrap and remove
257
+ */
258
+ export declare function $unwrapNode(node: ElementNode): void;
259
+ /**
260
+ * A wrapper that creates bound functions and methods for the
261
+ * StateConfig to save some boilerplate when defining methods
262
+ * or exporting only the accessors from your modules rather
263
+ * than exposing the StateConfig directly.
264
+ */
265
+ export interface StateConfigWrapper<K extends string, V> {
266
+ /** A reference to the stateConfig */
267
+ readonly stateConfig: StateConfig<K, V>;
268
+ /** `(node) => $getState(node, stateConfig)` */
269
+ readonly $get: <T extends LexicalNode>(node: T) => V;
270
+ /** `(node, valueOrUpdater) => $setState(node, stateConfig, valueOrUpdater)` */
271
+ readonly $set: <T extends LexicalNode>(node: T, valueOrUpdater: ValueOrUpdater<V>) => T;
272
+ /** `[$get, $set]` */
273
+ readonly accessors: readonly [$get: this['$get'], $set: this['$set']];
274
+ /**
275
+ * `() => function () { return $get(this) }`
276
+ *
277
+ * Should be called with an explicit `this` type parameter.
278
+ *
279
+ * @example
280
+ * ```ts
281
+ * class MyNode {
282
+ * // …
283
+ * myGetter = myWrapper.makeGetterMethod<this>();
284
+ * }
285
+ * ```
286
+ */
287
+ makeGetterMethod<T extends LexicalNode>(): (this: T) => V;
288
+ /**
289
+ * `() => function (valueOrUpdater) { return $set(this, valueOrUpdater) }`
290
+ *
291
+ * Must be called with an explicit `this` type parameter.
292
+ *
293
+ * @example
294
+ * ```ts
295
+ * class MyNode {
296
+ * // …
297
+ * mySetter = myWrapper.makeSetterMethod<this>();
298
+ * }
299
+ * ```
300
+ */
301
+ makeSetterMethod<T extends LexicalNode>(): (this: T, valueOrUpdater: ValueOrUpdater<V>) => T;
302
+ }
303
+ /**
304
+ * EXPERIMENTAL
305
+ *
306
+ * A convenience interface for working with {@link $getState} and
307
+ * {@link $setState}.
308
+ *
309
+ * @param stateConfig The stateConfig to wrap with convenience functionality
310
+ * @returns a StateWrapper
311
+ */
312
+ export declare function makeStateWrapper<K extends string, V>(stateConfig: StateConfig<K, V>): StateConfigWrapper<K, V>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import { type LexicalEditor } from '@ekz/lexical';
9
+ /**
10
+ * Place one or multiple newly created Nodes at the current selection. Multiple
11
+ * nodes will only be created when the selection spans multiple lines (aka
12
+ * client rects).
13
+ *
14
+ * This function can come useful when you want to show the selection but the
15
+ * editor has been focused away.
16
+ */
17
+ export default function markSelection(editor: LexicalEditor, onReposition?: (node: Array<HTMLElement>) => void): () => void;
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@ekz/lexical-utils",
3
+ "description": "This package contains misc utilities for Lexical.",
4
+ "keywords": [
5
+ "lexical",
6
+ "editor",
7
+ "rich-text",
8
+ "utils"
9
+ ],
10
+ "license": "MIT",
11
+ "version": "0.40.0",
12
+ "main": "LexicalUtils.js",
13
+ "types": "index.d.ts",
14
+ "dependencies": {
15
+ "@ekz/lexical-selection": "0.40.0",
16
+ "@ekz/lexical": "0.40.0"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/facebook/lexical.git",
21
+ "directory": "packages/lexical-utils"
22
+ },
23
+ "module": "LexicalUtils.mjs",
24
+ "sideEffects": false,
25
+ "exports": {
26
+ ".": {
27
+ "import": {
28
+ "types": "./index.d.ts",
29
+ "development": "./LexicalUtils.dev.mjs",
30
+ "production": "./LexicalUtils.prod.mjs",
31
+ "node": "./LexicalUtils.node.mjs",
32
+ "default": "./LexicalUtils.mjs"
33
+ },
34
+ "require": {
35
+ "types": "./index.d.ts",
36
+ "development": "./LexicalUtils.dev.js",
37
+ "production": "./LexicalUtils.prod.js",
38
+ "default": "./LexicalUtils.js"
39
+ }
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import { type LexicalEditor } from '@ekz/lexical';
9
+ /**
10
+ * Place one or multiple newly created Nodes at the passed Range's position.
11
+ * Multiple nodes will only be created when the Range spans multiple lines (aka
12
+ * client rects).
13
+ *
14
+ * This function can come particularly useful to highlight particular parts of
15
+ * the text without interfering with the EditorState, that will often replicate
16
+ * the state across collab and clipboard.
17
+ *
18
+ * This function accounts for DOM updates which can modify the passed Range.
19
+ * Hence, the function return to remove the listener.
20
+ */
21
+ export default function mlcPositionNodeOnRange(editor: LexicalEditor, range: Range, onReposition: (node: Array<HTMLElement>) => void): () => void;
package/px.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ export default function px(value: number): string;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import { type LexicalEditor } from '@ekz/lexical';
9
+ export default function selectionAlwaysOnDisplay(editor: LexicalEditor, onReposition?: (node: Array<HTMLElement>) => void): () => void;