@lexical/utils
Advanced tools
Comparing version 0.12.2 to 0.12.3
@@ -9,4 +9,7 @@ /** @module @lexical/utils */ | ||
*/ | ||
import { $splitNode, EditorState, ElementNode, isHTMLAnchorElement, isHTMLElement, Klass, LexicalEditor, LexicalNode } from 'lexical'; | ||
export { $splitNode, isHTMLAnchorElement, isHTMLElement }; | ||
import { DecoratorNode, EditorState, ElementNode, Klass, LexicalEditor, LexicalNode } from 'lexical'; | ||
export { default as markSelection } from './markSelection'; | ||
export { default as mergeRegister } from './mergeRegister'; | ||
export { default as positionNodeOnRange } from './positionNodeOnRange'; | ||
export { $splitNode, isHTMLAnchorElement, isHTMLElement } from 'lexical'; | ||
export type DFSNode = Readonly<{ | ||
@@ -94,27 +97,3 @@ depth: number; | ||
export declare function $findMatchingParent(startingNode: LexicalNode, findFn: (node: LexicalNode) => boolean): LexicalNode | null; | ||
type Func = () => void; | ||
/** | ||
* Returns a function that will execute all functions passed when called. It is generally used | ||
* to register multiple lexical listeners and then tear them down with a single function call, such | ||
* as React's useEffect hook. | ||
* @example | ||
* ```ts | ||
* useEffect(() => { | ||
* return mergeRegister( | ||
* editor.registerCommand(...registerCommand1 logic), | ||
* editor.registerCommand(...registerCommand2 logic), | ||
* editor.registerCommand(...registerCommand3 logic) | ||
* ) | ||
* }, [editor]) | ||
* ``` | ||
* In this case, useEffect is returning the function returned by mergeRegister as a cleanup | ||
* function to be executed after either the useEffect runs again (due to one of its dependencies | ||
* updating) or the compenent it resides in unmounts. | ||
* Note the functions don't neccesarily need to be in an array as all arguements | ||
* are considered to be the func argument and spread from there. | ||
* @param func - An array of functions meant to be executed by the returned function. | ||
* @returns the function which executes all the passed register command functions. | ||
*/ | ||
export declare function mergeRegister(...func: Array<Func>): () => void; | ||
/** | ||
* Attempts to resolve nested element nodes of the same type into a single node of that type. | ||
@@ -148,4 +127,4 @@ * It is generally used for marks/commenting | ||
* @param node - Node to be wrapped. | ||
* @param createElementNode - Creates a new lexcial element to wrap the to-be-wrapped node and returns it. | ||
* @returns A new lexcial element with the previous node appended within (as a child, including its children). | ||
* @param createElementNode - Creates a new lexical element to wrap the to-be-wrapped node and returns it. | ||
* @returns A new lexical element with the previous node appended within (as a child, including its children). | ||
*/ | ||
@@ -173,1 +152,7 @@ export declare function $wrapNodeInElement(node: LexicalNode, createElementNode: () => ElementNode): ElementNode; | ||
export declare function $insertFirst(parent: ElementNode, node: LexicalNode): void; | ||
/** | ||
* This function is for internal use of the library. | ||
* Please do not use it as it may change in the future. | ||
*/ | ||
export declare function INTERNAL_$isBlock(node: LexicalNode): node is ElementNode | DecoratorNode<unknown>; | ||
export declare function $getAncestor<NodeType extends LexicalNode = LexicalNode>(node: LexicalNode, predicate: (ancestor: LexicalNode) => ancestor is NodeType): NodeType | null; |
@@ -12,5 +12,296 @@ /** | ||
/** @module @lexical/utils */ | ||
/** | ||
* 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. | ||
* | ||
*/ | ||
/** | ||
* Returns a function that will execute all functions passed when called. It is generally used | ||
* to register multiple lexical listeners and then tear them down with a single function call, such | ||
* as React's useEffect hook. | ||
* @example | ||
* ```ts | ||
* useEffect(() => { | ||
* return mergeRegister( | ||
* editor.registerCommand(...registerCommand1 logic), | ||
* editor.registerCommand(...registerCommand2 logic), | ||
* editor.registerCommand(...registerCommand3 logic) | ||
* ) | ||
* }, [editor]) | ||
* ``` | ||
* In this case, useEffect is returning the function returned by mergeRegister as a cleanup | ||
* function to be executed after either the useEffect runs again (due to one of its dependencies | ||
* updating) or the component it resides in unmounts. | ||
* Note the functions don't neccesarily need to be in an array as all arguements | ||
* are considered to be the func argument and spread from there. | ||
* @param func - An array of functions meant to be executed by the returned function. | ||
* @returns the function which executes all the passed register command functions. | ||
*/ | ||
function mergeRegister(...func) { | ||
return () => { | ||
func.forEach(f => f()); | ||
}; | ||
} | ||
/** | ||
* 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. | ||
* | ||
*/ | ||
function px(value) { | ||
return `${value}px`; | ||
} | ||
/** | ||
* 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. | ||
* | ||
*/ | ||
const mutationObserverConfig = { | ||
attributes: true, | ||
characterData: true, | ||
childList: true, | ||
subtree: true | ||
}; | ||
function positionNodeOnRange(editor, range, onReposition) { | ||
let rootDOMNode = null; | ||
let parentDOMNode = null; | ||
let observer = null; | ||
let lastNodes = []; | ||
const wrapperNode = document.createElement('div'); | ||
function position() { | ||
if (!(rootDOMNode !== null)) { | ||
throw Error(`Unexpected null rootDOMNode`); | ||
} | ||
if (!(parentDOMNode !== null)) { | ||
throw Error(`Unexpected null parentDOMNode`); | ||
} | ||
const { | ||
left: rootLeft, | ||
top: rootTop | ||
} = rootDOMNode.getBoundingClientRect(); | ||
const parentDOMNode_ = parentDOMNode; | ||
const rects = selection.createRectsFromDOMRange(editor, range); | ||
if (!wrapperNode.isConnected) { | ||
parentDOMNode_.append(wrapperNode); | ||
} | ||
let hasRepositioned = false; | ||
for (let i = 0; i < rects.length; i++) { | ||
const rect = rects[i]; | ||
// Try to reuse the previously created Node when possible, no need to | ||
// remove/create on the most common case reposition case | ||
const rectNode = lastNodes[i] || document.createElement('div'); | ||
const rectNodeStyle = rectNode.style; | ||
if (rectNodeStyle.position !== 'absolute') { | ||
rectNodeStyle.position = 'absolute'; | ||
hasRepositioned = true; | ||
} | ||
const left = px(rect.left - rootLeft); | ||
if (rectNodeStyle.left !== left) { | ||
rectNodeStyle.left = left; | ||
hasRepositioned = true; | ||
} | ||
const top = px(rect.top - rootTop); | ||
if (rectNodeStyle.top !== top) { | ||
rectNode.style.top = top; | ||
hasRepositioned = true; | ||
} | ||
const width = px(rect.width); | ||
if (rectNodeStyle.width !== width) { | ||
rectNode.style.width = width; | ||
hasRepositioned = true; | ||
} | ||
const height = px(rect.height); | ||
if (rectNodeStyle.height !== height) { | ||
rectNode.style.height = height; | ||
hasRepositioned = true; | ||
} | ||
if (rectNode.parentNode !== wrapperNode) { | ||
wrapperNode.append(rectNode); | ||
hasRepositioned = true; | ||
} | ||
lastNodes[i] = rectNode; | ||
} | ||
while (lastNodes.length > rects.length) { | ||
lastNodes.pop(); | ||
} | ||
if (hasRepositioned) { | ||
onReposition(lastNodes); | ||
} | ||
} | ||
function stop() { | ||
parentDOMNode = null; | ||
rootDOMNode = null; | ||
if (observer !== null) { | ||
observer.disconnect(); | ||
} | ||
observer = null; | ||
wrapperNode.remove(); | ||
for (const node of lastNodes) { | ||
node.remove(); | ||
} | ||
lastNodes = []; | ||
} | ||
function restart() { | ||
const currentRootDOMNode = editor.getRootElement(); | ||
if (currentRootDOMNode === null) { | ||
return stop(); | ||
} | ||
const currentParentDOMNode = currentRootDOMNode.parentElement; | ||
if (!(currentParentDOMNode instanceof HTMLElement)) { | ||
return stop(); | ||
} | ||
stop(); | ||
rootDOMNode = currentRootDOMNode; | ||
parentDOMNode = currentParentDOMNode; | ||
observer = new MutationObserver(mutations => { | ||
const nextRootDOMNode = editor.getRootElement(); | ||
const nextParentDOMNode = nextRootDOMNode && nextRootDOMNode.parentElement; | ||
if (nextRootDOMNode !== rootDOMNode || nextParentDOMNode !== parentDOMNode) { | ||
return restart(); | ||
} | ||
for (const mutation of mutations) { | ||
if (!wrapperNode.contains(mutation.target)) { | ||
// TODO throttle | ||
return position(); | ||
} | ||
} | ||
}); | ||
observer.observe(currentParentDOMNode, mutationObserverConfig); | ||
position(); | ||
} | ||
const removeRootListener = editor.registerRootListener(restart); | ||
return () => { | ||
removeRootListener(); | ||
stop(); | ||
}; | ||
} | ||
/** | ||
* 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. | ||
* | ||
*/ | ||
function markSelection(editor, onReposition) { | ||
let previousAnchorNode = null; | ||
let previousAnchorOffset = null; | ||
let previousFocusNode = null; | ||
let previousFocusOffset = null; | ||
let removeRangeListener = () => {}; | ||
function compute(editorState) { | ||
editorState.read(() => { | ||
const selection = lexical.$getSelection(); | ||
if (!lexical.$isRangeSelection(selection)) { | ||
// TODO | ||
previousAnchorNode = null; | ||
previousAnchorOffset = null; | ||
previousFocusNode = null; | ||
previousFocusOffset = null; | ||
removeRangeListener(); | ||
removeRangeListener = () => {}; | ||
return; | ||
} | ||
const { | ||
anchor, | ||
focus | ||
} = selection; | ||
const currentAnchorNode = anchor.getNode(); | ||
const currentAnchorNodeKey = currentAnchorNode.getKey(); | ||
const currentAnchorOffset = anchor.offset; | ||
const currentFocusNode = focus.getNode(); | ||
const currentFocusNodeKey = currentFocusNode.getKey(); | ||
const currentFocusOffset = focus.offset; | ||
const currentAnchorNodeDOM = editor.getElementByKey(currentAnchorNodeKey); | ||
const currentFocusNodeDOM = editor.getElementByKey(currentFocusNodeKey); | ||
const differentAnchorDOM = previousAnchorNode === null || currentAnchorNodeDOM === null || currentAnchorOffset !== previousAnchorOffset || currentAnchorNodeKey !== previousAnchorNode.getKey() || currentAnchorNode !== previousAnchorNode && (!(previousAnchorNode instanceof lexical.TextNode) || currentAnchorNode.updateDOM(previousAnchorNode, currentAnchorNodeDOM, editor._config)); | ||
const differentFocusDOM = previousFocusNode === null || currentFocusNodeDOM === null || currentFocusOffset !== previousFocusOffset || currentFocusNodeKey !== previousFocusNode.getKey() || currentFocusNode !== previousFocusNode && (!(previousFocusNode instanceof lexical.TextNode) || currentFocusNode.updateDOM(previousFocusNode, currentFocusNodeDOM, editor._config)); | ||
if (differentAnchorDOM || differentFocusDOM) { | ||
const anchorHTMLElement = editor.getElementByKey(anchor.getNode().getKey()); | ||
const focusHTMLElement = editor.getElementByKey(focus.getNode().getKey()); | ||
// TODO handle selection beyond the common TextNode | ||
if (anchorHTMLElement !== null && focusHTMLElement !== null && anchorHTMLElement.tagName === 'SPAN' && focusHTMLElement.tagName === 'SPAN') { | ||
const range = document.createRange(); | ||
let firstHTMLElement; | ||
let firstOffset; | ||
let lastHTMLElement; | ||
let lastOffset; | ||
if (focus.isBefore(anchor)) { | ||
firstHTMLElement = focusHTMLElement; | ||
firstOffset = focus.offset; | ||
lastHTMLElement = anchorHTMLElement; | ||
lastOffset = anchor.offset; | ||
} else { | ||
firstHTMLElement = anchorHTMLElement; | ||
firstOffset = anchor.offset; | ||
lastHTMLElement = focusHTMLElement; | ||
lastOffset = focus.offset; | ||
} | ||
const firstTextNode = firstHTMLElement.firstChild; | ||
if (!(firstTextNode !== null)) { | ||
throw Error(`Expected text node to be first child of span`); | ||
} | ||
const lastTextNode = lastHTMLElement.firstChild; | ||
if (!(lastTextNode !== null)) { | ||
throw Error(`Expected text node to be first child of span`); | ||
} | ||
range.setStart(firstTextNode, firstOffset); | ||
range.setEnd(lastTextNode, lastOffset); | ||
removeRangeListener(); | ||
removeRangeListener = positionNodeOnRange(editor, range, domNodes => { | ||
for (const domNode of domNodes) { | ||
const domNodeStyle = domNode.style; | ||
if (domNodeStyle.background !== 'Highlight') { | ||
domNodeStyle.background = 'Highlight'; | ||
} | ||
if (domNodeStyle.color !== 'HighlightText') { | ||
domNodeStyle.color = 'HighlightText'; | ||
} | ||
if (domNodeStyle.zIndex !== '-1') { | ||
domNodeStyle.zIndex = '-1'; | ||
} | ||
if (domNodeStyle.pointerEvents !== 'none') { | ||
domNodeStyle.pointerEvents = 'none'; | ||
} | ||
if (domNodeStyle.marginTop !== px(-1.5)) { | ||
domNodeStyle.marginTop = px(-1.5); | ||
} | ||
if (domNodeStyle.paddingTop !== px(4)) { | ||
domNodeStyle.paddingTop = px(4); | ||
} | ||
if (domNodeStyle.paddingBottom !== px(0)) { | ||
domNodeStyle.paddingBottom = px(0); | ||
} | ||
} | ||
if (onReposition !== undefined) { | ||
onReposition(domNodes); | ||
} | ||
}); | ||
} | ||
} | ||
previousAnchorNode = currentAnchorNode; | ||
previousAnchorOffset = currentAnchorOffset; | ||
previousFocusNode = currentFocusNode; | ||
previousFocusOffset = currentFocusOffset; | ||
}); | ||
} | ||
compute(editor.getEditorState()); | ||
return mergeRegister(editor.registerUpdateListener(({ | ||
editorState | ||
}) => compute(editorState)), removeRangeListener, () => { | ||
removeRangeListener(); | ||
}); | ||
} | ||
/** @module @lexical/utils */ | ||
/** | ||
* Takes an HTML element and adds the classNames passed within an array, | ||
@@ -31,2 +322,3 @@ * ignoring any non-string types. A space can be used to add multiple classes | ||
} | ||
/** | ||
@@ -40,3 +332,2 @@ * Takes an HTML element and removes the classNames passed within an array, | ||
*/ | ||
function removeClassNamesFromElement(element, ...classNames) { | ||
@@ -49,2 +340,3 @@ classNames.forEach(className => { | ||
} | ||
/** | ||
@@ -58,3 +350,2 @@ * Returns true if the file type matches the types passed within the acceptableMimeTypes array, false otherwise. | ||
*/ | ||
function isMimeType(file, acceptableMimeTypes) { | ||
@@ -66,5 +357,5 @@ for (const acceptableType of acceptableMimeTypes) { | ||
} | ||
return false; | ||
} | ||
/** | ||
@@ -81,3 +372,2 @@ * Lexical File Reader with: | ||
*/ | ||
function mediaFileReader(files, acceptableMimeTypes) { | ||
@@ -87,3 +377,2 @@ const filesIterator = files[Symbol.iterator](); | ||
const processed = []; | ||
const handleNextFile = () => { | ||
@@ -94,7 +383,5 @@ const { | ||
} = filesIterator.next(); | ||
if (done) { | ||
return resolve(processed); | ||
} | ||
const fileReader = new FileReader(); | ||
@@ -104,3 +391,2 @@ fileReader.addEventListener('error', reject); | ||
const result = fileReader.result; | ||
if (typeof result === 'string') { | ||
@@ -112,6 +398,4 @@ processed.push({ | ||
} | ||
handleNextFile(); | ||
}); | ||
if (isMimeType(file, acceptableMimeTypes)) { | ||
@@ -123,6 +407,6 @@ fileReader.readAsDataURL(file); | ||
}; | ||
handleNextFile(); | ||
}); | ||
} | ||
/** | ||
@@ -138,3 +422,2 @@ * "Depth-First Search" starts at the root/top node of a tree and goes as far as it can down a branch end | ||
*/ | ||
function $dfs(startingNode, endingNode) { | ||
@@ -146,3 +429,2 @@ const nodes = []; | ||
let depth = $getDepth(node); | ||
while (node !== null && !node.is(end)) { | ||
@@ -153,3 +435,2 @@ nodes.push({ | ||
}); | ||
if (lexical.$isElementNode(node) && node.getChildrenSize() > 0) { | ||
@@ -161,6 +442,4 @@ node = node.getFirstChild(); | ||
let sibling = null; | ||
while (sibling === null && node !== null) { | ||
sibling = node.getNextSibling(); | ||
if (sibling === null) { | ||
@@ -175,3 +454,2 @@ node = node.getParent(); | ||
} | ||
if (node !== null && node.is(end)) { | ||
@@ -183,16 +461,13 @@ nodes.push({ | ||
} | ||
return nodes; | ||
} | ||
function $getDepth(node) { | ||
let innerNode = node; | ||
let depth = 0; | ||
while ((innerNode = innerNode.getParent()) !== null) { | ||
depth++; | ||
} | ||
return depth; | ||
} | ||
/** | ||
@@ -205,7 +480,4 @@ * Takes a node and traverses up its ancestors (toward the root node) | ||
*/ | ||
function $getNearestNodeOfType(node, klass) { | ||
let parent = node; | ||
while (parent != null) { | ||
@@ -215,8 +487,7 @@ if (parent instanceof klass) { | ||
} | ||
parent = parent.getParent(); | ||
} | ||
return null; | ||
} | ||
/** | ||
@@ -227,6 +498,4 @@ * Returns the element node of the nearest ancestor, otherwise throws an error. | ||
*/ | ||
function $getNearestBlockElementAncestorOrThrow(startNode) { | ||
const blockNode = $findMatchingParent(startNode, node => lexical.$isElementNode(node) && !node.isInline()); | ||
if (!lexical.$isElementNode(blockNode)) { | ||
@@ -237,6 +506,4 @@ { | ||
} | ||
return blockNode; | ||
} | ||
/** | ||
@@ -252,3 +519,2 @@ * Starts with a node and moves up the tree (toward the root node) to find a matching node based on | ||
let curr = startingNode; | ||
while (curr !== lexical.$getRoot() && curr != null) { | ||
@@ -258,6 +524,4 @@ if (findFn(curr)) { | ||
} | ||
curr = curr.getParent(); | ||
} | ||
return null; | ||
@@ -267,29 +531,2 @@ } | ||
/** | ||
* Returns a function that will execute all functions passed when called. It is generally used | ||
* to register multiple lexical listeners and then tear them down with a single function call, such | ||
* as React's useEffect hook. | ||
* @example | ||
* ```ts | ||
* useEffect(() => { | ||
* return mergeRegister( | ||
* editor.registerCommand(...registerCommand1 logic), | ||
* editor.registerCommand(...registerCommand2 logic), | ||
* editor.registerCommand(...registerCommand3 logic) | ||
* ) | ||
* }, [editor]) | ||
* ``` | ||
* In this case, useEffect is returning the function returned by mergeRegister as a cleanup | ||
* function to be executed after either the useEffect runs again (due to one of its dependencies | ||
* updating) or the compenent it resides in unmounts. | ||
* Note the functions don't neccesarily need to be in an array as all arguements | ||
* are considered to be the func argument and spread from there. | ||
* @param func - An array of functions meant to be executed by the returned function. | ||
* @returns the function which executes all the passed register command functions. | ||
*/ | ||
function mergeRegister(...func) { | ||
return () => { | ||
func.forEach(f => f()); | ||
}; | ||
} | ||
/** | ||
* Attempts to resolve nested element nodes of the same type into a single node of that type. | ||
@@ -303,3 +540,2 @@ * It is generally used for marks/commenting | ||
*/ | ||
function registerNestedElementResolver(editor, targetNode, cloneNode, handleOverlap) { | ||
@@ -309,3 +545,2 @@ const $isTargetNode = node => { | ||
}; | ||
const $findMatch = node => { | ||
@@ -315,6 +550,4 @@ // First validate we don't have any children that are of the target, | ||
const children = node.getChildren(); | ||
for (let i = 0; i < children.length; i++) { | ||
const child = children[i]; | ||
if ($isTargetNode(child)) { | ||
@@ -324,10 +557,7 @@ return null; | ||
} | ||
let parentNode = node; | ||
let childNode = node; | ||
while (parentNode !== null) { | ||
childNode = parentNode; | ||
parentNode = parentNode.getParent(); | ||
if ($isTargetNode(parentNode)) { | ||
@@ -340,9 +570,6 @@ return { | ||
} | ||
return null; | ||
}; | ||
const elementNodeTransform = node => { | ||
const match = $findMatch(node); | ||
if (match !== null) { | ||
@@ -352,4 +579,6 @@ const { | ||
parent | ||
} = match; // Simple path, we can move child out and siblings into a new parent. | ||
} = match; | ||
// Simple path, we can move child out and siblings into a new parent. | ||
if (child.is(node)) { | ||
@@ -360,7 +589,5 @@ handleOverlap(parent, node); | ||
parent.insertAfter(child); | ||
if (nextSiblingsLength !== 0) { | ||
const newParent = cloneNode(parent); | ||
child.insertAfter(newParent); | ||
for (let i = 0; i < nextSiblingsLength; i++) { | ||
@@ -370,3 +597,2 @@ newParent.append(nextSiblings[i]); | ||
} | ||
if (!parent.canBeEmpty() && parent.getChildrenSize() === 0) { | ||
@@ -378,5 +604,5 @@ parent.remove(); | ||
}; | ||
return editor.registerNodeTransform(targetNode, elementNodeTransform); | ||
} | ||
/** | ||
@@ -388,3 +614,2 @@ * Clones the editor and marks it as dirty to be reconciled. If there was a selection, | ||
*/ | ||
function $restoreEditorState(editor, editorState) { | ||
@@ -394,17 +619,12 @@ const FULL_RECONCILE = 2; | ||
const activeEditorState = editor._pendingEditorState; | ||
for (const [key, node] of editorState._nodeMap) { | ||
const clone = selection.$cloneWithProperties(node); | ||
if (lexical.$isTextNode(clone)) { | ||
clone.__text = node.__text; | ||
} | ||
nodeMap.set(key, clone); | ||
} | ||
if (activeEditorState) { | ||
activeEditorState._nodeMap = nodeMap; | ||
} | ||
editor._dirtyType = FULL_RECONCILE; | ||
@@ -414,2 +634,3 @@ const selection$1 = editorState._selection; | ||
} | ||
/** | ||
@@ -423,6 +644,4 @@ * If the selected insertion area is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}), | ||
*/ | ||
function $insertNodeToNearestRoot(node) { | ||
const selection = lexical.$getSelection() || lexical.$getPreviousSelection(); | ||
if (lexical.$isRangeSelection(selection)) { | ||
@@ -434,6 +653,4 @@ const { | ||
const focusOffset = focus.offset; | ||
if (lexical.$isRootOrShadowRoot(focusNode)) { | ||
const focusChild = focusNode.getChildAtIndex(focusOffset); | ||
if (focusChild == null) { | ||
@@ -444,3 +661,2 @@ focusNode.append(node); | ||
} | ||
node.selectNext(); | ||
@@ -450,7 +666,5 @@ } else { | ||
let splitOffset; | ||
if (lexical.$isTextNode(focusNode)) { | ||
splitNode = focusNode.getParentOrThrow(); | ||
splitOffset = focusNode.getIndexWithinParent(); | ||
if (focusOffset > 0) { | ||
@@ -464,3 +678,2 @@ splitOffset += 1; | ||
} | ||
const [, rightTree] = lexical.$splitNode(splitNode, splitOffset); | ||
@@ -478,3 +691,2 @@ rightTree.insertBefore(node); | ||
} | ||
const paragraphNode = lexical.$createParagraphNode(); | ||
@@ -484,12 +696,11 @@ node.insertAfter(paragraphNode); | ||
} | ||
return node.getLatest(); | ||
} | ||
/** | ||
* Wraps the node into another node created from a createElementNode function, eg. $createParagraphNode | ||
* @param node - Node to be wrapped. | ||
* @param createElementNode - Creates a new lexcial element to wrap the to-be-wrapped node and returns it. | ||
* @returns A new lexcial element with the previous node appended within (as a child, including its children). | ||
* @param createElementNode - Creates a new lexical element to wrap the to-be-wrapped node and returns it. | ||
* @returns A new lexical element with the previous node appended within (as a child, including its children). | ||
*/ | ||
function $wrapNodeInElement(node, createElementNode) { | ||
@@ -500,4 +711,6 @@ const elementNode = createElementNode(); | ||
return elementNode; | ||
} // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
/** | ||
@@ -511,2 +724,3 @@ * @param object = The instance of the type | ||
} | ||
/** | ||
@@ -521,6 +735,4 @@ * Filter the nodes | ||
const result = []; | ||
for (let i = 0; i < nodes.length; i++) { | ||
const node = filterFn(nodes[i]); | ||
if (node !== null) { | ||
@@ -530,3 +742,2 @@ result.push(node); | ||
} | ||
return result; | ||
@@ -539,6 +750,4 @@ } | ||
*/ | ||
function $insertFirst(parent, node) { | ||
const firstChild = parent.getFirstChild(); | ||
if (firstChild !== null) { | ||
@@ -551,2 +760,25 @@ firstChild.insertBefore(node); | ||
/** | ||
* This function is for internal use of the library. | ||
* Please do not use it as it may change in the future. | ||
*/ | ||
function INTERNAL_$isBlock(node) { | ||
if (lexical.$isDecoratorNode(node) && !node.isInline()) { | ||
return true; | ||
} | ||
if (!lexical.$isElementNode(node) || lexical.$isRootOrShadowRoot(node)) { | ||
return false; | ||
} | ||
const firstChild = node.getFirstChild(); | ||
const isLeafElement = firstChild === null || lexical.$isLineBreakNode(firstChild) || lexical.$isTextNode(firstChild) || firstChild.isInline(); | ||
return !node.isInline() && node.canBeEmpty() !== false && isLeafElement; | ||
} | ||
function $getAncestor(node, predicate) { | ||
let parent = node; | ||
while (parent !== null && parent.getParent() !== null && !predicate(parent)) { | ||
parent = parent.getParentOrThrow(); | ||
} | ||
return predicate(parent) ? parent : null; | ||
} | ||
exports.$splitNode = lexical.$splitNode; | ||
@@ -558,2 +790,3 @@ exports.isHTMLAnchorElement = lexical.isHTMLAnchorElement; | ||
exports.$findMatchingParent = $findMatchingParent; | ||
exports.$getAncestor = $getAncestor; | ||
exports.$getNearestBlockElementAncestorOrThrow = $getNearestBlockElementAncestorOrThrow; | ||
@@ -565,8 +798,11 @@ exports.$getNearestNodeOfType = $getNearestNodeOfType; | ||
exports.$wrapNodeInElement = $wrapNodeInElement; | ||
exports.INTERNAL_$isBlock = INTERNAL_$isBlock; | ||
exports.addClassNamesToElement = addClassNamesToElement; | ||
exports.isMimeType = isMimeType; | ||
exports.markSelection = markSelection; | ||
exports.mediaFileReader = mediaFileReader; | ||
exports.mergeRegister = mergeRegister; | ||
exports.objectKlassEquals = objectKlassEquals; | ||
exports.positionNodeOnRange = positionNodeOnRange; | ||
exports.registerNestedElementResolver = registerNestedElementResolver; | ||
exports.removeClassNamesFromElement = removeClassNamesFromElement; |
@@ -7,12 +7,19 @@ /** | ||
*/ | ||
'use strict';var g=require("@lexical/selection"),n=require("lexical");function p(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function r(a,b){for(let c of b)if(a.type.startsWith(c))return!0;return!1} | ||
function t(a,b){for(;a!==n.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}exports.$splitNode=n.$splitNode;exports.isHTMLAnchorElement=n.isHTMLAnchorElement;exports.isHTMLElement=n.isHTMLElement; | ||
exports.$dfs=function(a,b){let c=[];a=(a||n.$getRoot()).getLatest();b=b||(n.$isElementNode(a)?a.getLastDescendant():a);for(var e=a,d=0;null!==(e=e.getParent());)d++;for(e=d;null!==a&&!a.is(b);)if(c.push({depth:e,node:a}),n.$isElementNode(a)&&0<a.getChildrenSize())a=a.getFirstChild(),e++;else for(d=null;null===d&&null!==a;)d=a.getNextSibling(),null===d?(a=a.getParent(),e--):a=d;null!==a&&a.is(b)&&c.push({depth:e,node:a});return c}; | ||
exports.$filter=function(a,b){let c=[];for(let e=0;e<a.length;e++){let d=b(a[e]);null!==d&&c.push(d)}return c};exports.$findMatchingParent=t;exports.$getNearestBlockElementAncestorOrThrow=function(a){let b=t(a,c=>n.$isElementNode(c)&&!c.isInline());n.$isElementNode(b)||p(4,a.__key);return b};exports.$getNearestNodeOfType=function(a,b){for(;null!=a;){if(a instanceof b)return a;a=a.getParent()}return null};exports.$insertFirst=function(a,b){let c=a.getFirstChild();null!==c?c.insertBefore(b):a.append(b)}; | ||
exports.$insertNodeToNearestRoot=function(a){var b=n.$getSelection()||n.$getPreviousSelection();if(n.$isRangeSelection(b)){var {focus:c}=b;b=c.getNode();c=c.offset;if(n.$isRootOrShadowRoot(b))c=b.getChildAtIndex(c),null==c?b.append(a):c.insertBefore(a),a.selectNext();else{let e,d;n.$isTextNode(b)?(e=b.getParentOrThrow(),d=b.getIndexWithinParent(),0<c&&(d+=1,b.splitText(c))):(e=b,d=c);[,b]=n.$splitNode(e,d);b.insertBefore(a);b.selectStart()}}else n.$isNodeSelection(b)||n.DEPRECATED_$isGridSelection(b)? | ||
(b=b.getNodes(),b[b.length-1].getTopLevelElementOrThrow().insertAfter(a)):n.$getRoot().append(a),b=n.$createParagraphNode(),a.insertAfter(b),b.select();return a.getLatest()};exports.$restoreEditorState=function(a,b){let c=new Map,e=a._pendingEditorState;for(let [d,f]of b._nodeMap){let h=g.$cloneWithProperties(f);n.$isTextNode(h)&&(h.__text=f.__text);c.set(d,h)}e&&(e._nodeMap=c);a._dirtyType=2;a=b._selection;n.$setSelection(null===a?null:a.clone())}; | ||
exports.$wrapNodeInElement=function(a,b){b=b();a.replace(b);b.append(a);return b};exports.addClassNamesToElement=function(a,...b){b.forEach(c=>{"string"===typeof c&&(c=c.split(" ").filter(e=>""!==e),a.classList.add(...c))})};exports.isMimeType=r; | ||
exports.mediaFileReader=function(a,b){let c=a[Symbol.iterator]();return new Promise((e,d)=>{let f=[],h=()=>{const {done:m,value:k}=c.next();if(m)return e(f);const l=new FileReader;l.addEventListener("error",d);l.addEventListener("load",()=>{const q=l.result;"string"===typeof q&&f.push({file:k,result:q});h()});r(k,b)?l.readAsDataURL(k):h()};h()})};exports.mergeRegister=function(...a){return()=>{a.forEach(b=>b())}}; | ||
exports.objectKlassEquals=function(a,b){return null!==a?Object.getPrototypeOf(a).constructor.name===b.name:!1}; | ||
exports.registerNestedElementResolver=function(a,b,c,e){return a.registerNodeTransform(b,d=>{a:{var f=d.getChildren();for(var h=0;h<f.length;h++)if(f[h]instanceof b){f=null;break a}for(f=d;null!==f;)if(h=f,f=f.getParent(),f instanceof b){f={child:h,parent:f};break a}f=null}if(null!==f){const {child:m,parent:k}=f;if(m.is(d)){e(k,d);d=m.getNextSiblings();f=d.length;k.insertAfter(m);if(0!==f){h=c(k);m.insertAfter(h);for(let l=0;l<f;l++)h.append(d[l])}k.canBeEmpty()||0!==k.getChildrenSize()||k.remove()}}})}; | ||
'use strict';var g=require("@lexical/selection"),B=require("lexical");function C(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function D(...a){return()=>{a.forEach(b=>b())}}let E={attributes:!0,characterData:!0,childList:!0,subtree:!0}; | ||
function F(a,b,c){function e(){if(null===h)throw Error("Unexpected null rootDOMNode");if(null===n)throw Error("Unexpected null parentDOMNode");let {left:p,top:z}=h.getBoundingClientRect();var q=n;let r=g.createRectsFromDOMRange(a,b);t.isConnected||q.append(t);q=!1;for(let x=0;x<r.length;x++){var w=r[x];let u=k[x]||document.createElement("div"),y=u.style;"absolute"!==y.position&&(y.position="absolute",q=!0);var l=`${w.left-p}px`;y.left!==l&&(y.left=l,q=!0);l=`${w.top-z}px`;y.top!==l&&(u.style.top= | ||
l,q=!0);l=`${w.width}px`;y.width!==l&&(u.style.width=l,q=!0);w=`${w.height}px`;y.height!==w&&(u.style.height=w,q=!0);u.parentNode!==t&&(t.append(u),q=!0);k[x]=u}for(;k.length>r.length;)k.pop();q&&c(k)}function d(){h=n=null;null!==m&&m.disconnect();m=null;t.remove();for(let p of k)p.remove();k=[]}function f(){let p=a.getRootElement();if(null===p)return d();let z=p.parentElement;if(!(z instanceof HTMLElement))return d();d();h=p;n=z;m=new MutationObserver(q=>{let r=a.getRootElement(),w=r&&r.parentElement; | ||
if(r!==h||w!==n)return f();for(let l of q)if(!t.contains(l.target))return e()});m.observe(z,E);e()}let h=null,n=null,m=null,k=[],t=document.createElement("div"),A=a.registerRootListener(f);return()=>{A();d()}}function G(a,b){for(let c of b)if(a.type.startsWith(c))return!0;return!1}function H(a,b){for(;a!==B.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}exports.$splitNode=B.$splitNode;exports.isHTMLAnchorElement=B.isHTMLAnchorElement;exports.isHTMLElement=B.isHTMLElement; | ||
exports.$dfs=function(a,b){let c=[];a=(a||B.$getRoot()).getLatest();b=b||(B.$isElementNode(a)?a.getLastDescendant():a);for(var e=a,d=0;null!==(e=e.getParent());)d++;for(e=d;null!==a&&!a.is(b);)if(c.push({depth:e,node:a}),B.$isElementNode(a)&&0<a.getChildrenSize())a=a.getFirstChild(),e++;else for(d=null;null===d&&null!==a;)d=a.getNextSibling(),null===d?(a=a.getParent(),e--):a=d;null!==a&&a.is(b)&&c.push({depth:e,node:a});return c}; | ||
exports.$filter=function(a,b){let c=[];for(let e=0;e<a.length;e++){let d=b(a[e]);null!==d&&c.push(d)}return c};exports.$findMatchingParent=H;exports.$getAncestor=function(a,b){for(;null!==a&&null!==a.getParent()&&!b(a);)a=a.getParentOrThrow();return b(a)?a:null};exports.$getNearestBlockElementAncestorOrThrow=function(a){let b=H(a,c=>B.$isElementNode(c)&&!c.isInline());B.$isElementNode(b)||C(4,a.__key);return b}; | ||
exports.$getNearestNodeOfType=function(a,b){for(;null!=a;){if(a instanceof b)return a;a=a.getParent()}return null};exports.$insertFirst=function(a,b){let c=a.getFirstChild();null!==c?c.insertBefore(b):a.append(b)}; | ||
exports.$insertNodeToNearestRoot=function(a){var b=B.$getSelection()||B.$getPreviousSelection();if(B.$isRangeSelection(b)){var {focus:c}=b;b=c.getNode();c=c.offset;if(B.$isRootOrShadowRoot(b))c=b.getChildAtIndex(c),null==c?b.append(a):c.insertBefore(a),a.selectNext();else{let e,d;B.$isTextNode(b)?(e=b.getParentOrThrow(),d=b.getIndexWithinParent(),0<c&&(d+=1,b.splitText(c))):(e=b,d=c);[,b]=B.$splitNode(e,d);b.insertBefore(a);b.selectStart()}}else B.$isNodeSelection(b)||B.DEPRECATED_$isGridSelection(b)? | ||
(b=b.getNodes(),b[b.length-1].getTopLevelElementOrThrow().insertAfter(a)):B.$getRoot().append(a),b=B.$createParagraphNode(),a.insertAfter(b),b.select();return a.getLatest()};exports.$restoreEditorState=function(a,b){let c=new Map,e=a._pendingEditorState;for(let [d,f]of b._nodeMap){let h=g.$cloneWithProperties(f);B.$isTextNode(h)&&(h.__text=f.__text);c.set(d,h)}e&&(e._nodeMap=c);a._dirtyType=2;a=b._selection;B.$setSelection(null===a?null:a.clone())}; | ||
exports.$wrapNodeInElement=function(a,b){b=b();a.replace(b);b.append(a);return b};exports.INTERNAL_$isBlock=function(a){if(B.$isDecoratorNode(a)&&!a.isInline())return!0;if(!B.$isElementNode(a)||B.$isRootOrShadowRoot(a))return!1;var b=a.getFirstChild();b=null===b||B.$isLineBreakNode(b)||B.$isTextNode(b)||b.isInline();return!a.isInline()&&!1!==a.canBeEmpty()&&b};exports.addClassNamesToElement=function(a,...b){b.forEach(c=>{"string"===typeof c&&(c=c.split(" ").filter(e=>""!==e),a.classList.add(...c))})}; | ||
exports.isMimeType=G; | ||
exports.markSelection=function(a,b){function c(m){m.read(()=>{var k=B.$getSelection();if(B.$isRangeSelection(k)){var {anchor:t,focus:A}=k;k=t.getNode();var p=k.getKey(),z=t.offset,q=A.getNode(),r=q.getKey(),w=A.offset,l=a.getElementByKey(p),x=a.getElementByKey(r);p=null===e||null===l||z!==d||p!==e.getKey()||k!==e&&(!(e instanceof B.TextNode)||k.updateDOM(e,l,a._config));r=null===f||null===x||w!==h||r!==f.getKey()||q!==f&&(!(f instanceof B.TextNode)||q.updateDOM(f,x,a._config));if(p||r){l=a.getElementByKey(t.getNode().getKey()); | ||
var u=a.getElementByKey(A.getNode().getKey());if(null!==l&&null!==u&&"SPAN"===l.tagName&&"SPAN"===u.tagName){r=document.createRange();A.isBefore(t)?(p=u,x=A.offset,u=l,l=t.offset):(p=l,x=t.offset,l=A.offset);p=p.firstChild;if(null===p)throw Error("Expected text node to be first child of span");u=u.firstChild;if(null===u)throw Error("Expected text node to be first child of span");r.setStart(p,x);r.setEnd(u,l);n();n=F(a,r,y=>{for(let I of y){let v=I.style;"Highlight"!==v.background&&(v.background="Highlight"); | ||
"HighlightText"!==v.color&&(v.color="HighlightText");"-1"!==v.zIndex&&(v.zIndex="-1");"none"!==v.pointerEvents&&(v.pointerEvents="none");"-1.5px"!==v.marginTop&&(v.marginTop="-1.5px");"4px"!==v.paddingTop&&(v.paddingTop="4px");"0px"!==v.paddingBottom&&(v.paddingBottom="0px")}void 0!==b&&b(y)})}}e=k;d=z;f=q;h=w}else h=f=d=e=null,n(),n=()=>{}})}let e=null,d=null,f=null,h=null,n=()=>{};c(a.getEditorState());return D(a.registerUpdateListener(({editorState:m})=>c(m)),n,()=>{n()})}; | ||
exports.mediaFileReader=function(a,b){let c=a[Symbol.iterator]();return new Promise((e,d)=>{let f=[],h=()=>{const {done:n,value:m}=c.next();if(n)return e(f);const k=new FileReader;k.addEventListener("error",d);k.addEventListener("load",()=>{const t=k.result;"string"===typeof t&&f.push({file:m,result:t});h()});G(m,b)?k.readAsDataURL(m):h()};h()})};exports.mergeRegister=D;exports.objectKlassEquals=function(a,b){return null!==a?Object.getPrototypeOf(a).constructor.name===b.name:!1}; | ||
exports.positionNodeOnRange=F; | ||
exports.registerNestedElementResolver=function(a,b,c,e){return a.registerNodeTransform(b,d=>{a:{var f=d.getChildren();for(var h=0;h<f.length;h++)if(f[h]instanceof b){f=null;break a}for(f=d;null!==f;)if(h=f,f=f.getParent(),f instanceof b){f={child:h,parent:f};break a}f=null}if(null!==f){const {child:n,parent:m}=f;if(n.is(d)){e(m,d);d=n.getNextSiblings();f=d.length;m.insertAfter(n);if(0!==f){h=c(m);n.insertAfter(h);for(let k=0;k<f;k++)h.append(d[k])}m.canBeEmpty()||0!==m.getChildrenSize()||m.remove()}}})}; | ||
exports.removeClassNamesFromElement=function(a,...b){b.forEach(c=>{"string"===typeof c&&a.classList.remove(...c.split(" "))})} |
@@ -11,11 +11,11 @@ { | ||
"license": "MIT", | ||
"version": "0.12.2", | ||
"version": "0.12.3", | ||
"main": "LexicalUtils.js", | ||
"peerDependencies": { | ||
"lexical": "0.12.2" | ||
"lexical": "0.12.3" | ||
}, | ||
"dependencies": { | ||
"@lexical/list": "0.12.2", | ||
"@lexical/table": "0.12.2", | ||
"@lexical/selection": "0.12.2" | ||
"@lexical/list": "0.12.3", | ||
"@lexical/table": "0.12.3", | ||
"@lexical/selection": "0.12.3" | ||
}, | ||
@@ -22,0 +22,0 @@ "repository": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
50324
12
991
+ Added@lexical/list@0.12.3(transitive)
+ Added@lexical/selection@0.12.3(transitive)
+ Added@lexical/table@0.12.3(transitive)
+ Addedlexical@0.12.3(transitive)
- Removed@lexical/list@0.12.2(transitive)
- Removed@lexical/selection@0.12.2(transitive)
- Removed@lexical/table@0.12.2(transitive)
- Removedlexical@0.12.2(transitive)
Updated@lexical/list@0.12.3
Updated@lexical/selection@0.12.3
Updated@lexical/table@0.12.3