@lexical/clipboard
Advanced tools
Comparing version 0.7.8 to 0.7.9
@@ -23,3 +23,2 @@ /** | ||
const selection = lexical.$getSelection(); | ||
if (selection == null) { | ||
@@ -29,16 +28,15 @@ { | ||
} | ||
} // If we haven't selected anything | ||
} | ||
// If we haven't selected anything | ||
if (lexical.$isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) { | ||
return ''; | ||
} | ||
return html.$generateHtmlFromNodes(editor, selection); | ||
} | ||
return html.$generateHtmlFromNodes(editor, selection); | ||
} // TODO 0.6.0 Return a blank string instead | ||
// TODO 0.6.0 Return a blank string instead | ||
// TODO 0.6.0 Rename to $getJSON | ||
function $getLexicalContent(editor) { | ||
const selection = lexical.$getSelection(); | ||
if (selection == null) { | ||
@@ -48,9 +46,8 @@ { | ||
} | ||
} // If we haven't selected anything | ||
} | ||
// If we haven't selected anything | ||
if (lexical.$isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) { | ||
return null; | ||
} | ||
return JSON.stringify($generateJSONFromSelectedNodes(editor, selection)); | ||
@@ -60,3 +57,2 @@ } | ||
const text = dataTransfer.getData('text/plain'); | ||
if (text != null) { | ||
@@ -68,7 +64,5 @@ selection.insertRawText(text); | ||
const lexicalString = dataTransfer.getData('application/x-lexical-editor'); | ||
if (lexicalString) { | ||
try { | ||
const payload = JSON.parse(lexicalString); | ||
if (payload.namespace === editor._config.namespace && Array.isArray(payload.nodes)) { | ||
@@ -78,8 +72,7 @@ const nodes = $generateNodesFromSerializedNodes(payload.nodes); | ||
} | ||
} catch {// Fail silently. | ||
} catch { | ||
// Fail silently. | ||
} | ||
} | ||
const htmlString = dataTransfer.getData('text/html'); | ||
if (htmlString) { | ||
@@ -91,10 +84,10 @@ try { | ||
return $insertGeneratedNodes(editor, nodes, selection); | ||
} catch {// Fail silently. | ||
} catch { | ||
// Fail silently. | ||
} | ||
} // Multi-line plain text in rich text mode pasted as separate paragraphs | ||
} | ||
// Multi-line plain text in rich text mode pasted as separate paragraphs | ||
// instead of single paragraph with linebreaks. | ||
const text = dataTransfer.getData('text/plain'); | ||
if (text != null) { | ||
@@ -104,6 +97,4 @@ if (lexical.$isRangeSelection(selection)) { | ||
const linesLength = lines.length; | ||
for (let i = 0; i < linesLength; i++) { | ||
selection.insertText(lines[i]); | ||
if (i < linesLength - 1) { | ||
@@ -120,3 +111,2 @@ selection.insertParagraph(); | ||
const isSelectionInsideOfGrid = lexical.DEPRECATED_$isGridSelection(selection) || utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n)) !== null && utils.$findMatchingParent(selection.focus.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n)) !== null; | ||
if (isSelectionInsideOfGrid && nodes.length === 1 && lexical.DEPRECATED_$isGridNode(nodes[0])) { | ||
@@ -126,7 +116,5 @@ $mergeGridNodesStrategy(nodes, selection, false, editor); | ||
} | ||
$basicInsertStrategy(nodes, selection); | ||
return; | ||
} | ||
function $basicInsertStrategy(nodes, selection) { | ||
@@ -136,13 +124,11 @@ // Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level | ||
let currentBlock = null; | ||
for (let i = 0; i < nodes.length; i++) { | ||
const node = nodes[i]; | ||
const isLineBreakNode = lexical.$isLineBreakNode(node); | ||
if (isLineBreakNode || lexical.$isDecoratorNode(node) && node.isInline() || lexical.$isElementNode(node) && node.isInline() || lexical.$isTextNode(node) || node.isParentRequired()) { | ||
if (currentBlock === null) { | ||
currentBlock = node.createParentElementNode(); | ||
topLevelBlocks.push(currentBlock); // In the case of LineBreakNode, we just need to | ||
topLevelBlocks.push(currentBlock); | ||
// In the case of LineBreakNode, we just need to | ||
// add an empty ParagraphNode to the topLevelBlocks. | ||
if (isLineBreakNode) { | ||
@@ -152,3 +138,2 @@ continue; | ||
} | ||
if (currentBlock !== null) { | ||
@@ -162,3 +147,2 @@ currentBlock.append(node); | ||
} | ||
if (lexical.$isRangeSelection(selection)) { | ||
@@ -169,3 +153,2 @@ selection.insertNodes(topLevelBlocks); | ||
const anchorCell = selection.anchor.getNode(); | ||
if (!lexical.DEPRECATED_$isGridCellNode(anchorCell)) { | ||
@@ -176,7 +159,5 @@ { | ||
} | ||
anchorCell.append(...topLevelBlocks); | ||
} | ||
} | ||
function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) { | ||
@@ -188,3 +169,2 @@ if (nodes.length !== 1 || !lexical.DEPRECATED_$isGridNode(nodes[0])) { | ||
} | ||
const newGrid = nodes[0]; | ||
@@ -197,3 +177,2 @@ const newGridRows = newGrid.getChildren(); | ||
const gridNode = gridRowNode && utils.$findMatchingParent(gridRowNode, n => lexical.DEPRECATED_$isGridNode(n)); | ||
if (!lexical.DEPRECATED_$isGridCellNode(gridCellNode) || !lexical.DEPRECATED_$isGridRowNode(gridRowNode) || !lexical.DEPRECATED_$isGridNode(gridNode)) { | ||
@@ -204,3 +183,2 @@ { | ||
} | ||
const startY = gridRowNode.getIndexWithinParent(); | ||
@@ -218,6 +196,4 @@ const stopY = Math.min(gridNode.getChildrenSize() - 1, startY + newRowCount - 1); | ||
let newFocusCellKey; | ||
for (let r = fromY; r <= toY; r++) { | ||
const currentGridRowNode = gridRowNodes[r]; | ||
if (!lexical.DEPRECATED_$isGridRowNode(currentGridRowNode)) { | ||
@@ -228,5 +204,3 @@ { | ||
} | ||
const newGridRowNode = newGridRows[newRowIdx]; | ||
if (!lexical.DEPRECATED_$isGridRowNode(newGridRowNode)) { | ||
@@ -237,10 +211,7 @@ { | ||
} | ||
const gridCellNodes = currentGridRowNode.getChildren(); | ||
const newGridCellNodes = newGridRowNode.getChildren(); | ||
let newColumnIdx = 0; | ||
for (let c = fromX; c <= toX; c++) { | ||
const currentGridCellNode = gridCellNodes[c]; | ||
if (!lexical.DEPRECATED_$isGridCellNode(currentGridCellNode)) { | ||
@@ -251,5 +222,3 @@ { | ||
} | ||
const newGridCellNode = newGridCellNodes[newColumnIdx]; | ||
if (!lexical.DEPRECATED_$isGridCellNode(newGridCellNode)) { | ||
@@ -260,3 +229,2 @@ { | ||
} | ||
if (r === fromY && c === fromX) { | ||
@@ -267,3 +235,2 @@ newAnchorCellKey = currentGridCellNode.getKey(); | ||
} | ||
const originalChildren = currentGridCellNode.getChildren(); | ||
@@ -282,6 +249,4 @@ newGridCellNode.getChildren().forEach(child => { | ||
} | ||
newRowIdx++; | ||
} | ||
if (newAnchorCellKey && newFocusCellKey) { | ||
@@ -294,7 +259,7 @@ const newGridSelection = lexical.DEPRECATED_$createGridSelection(); | ||
} | ||
function exportNodeToJSON(node) { | ||
const serializedNode = node.exportJSON(); | ||
const nodeClass = node.constructor; // @ts-expect-error TODO Replace Class utility type with InstanceType | ||
const nodeClass = node.constructor; | ||
// @ts-expect-error TODO Replace Class utility type with InstanceType | ||
if (serializedNode.type !== nodeClass.getType()) { | ||
@@ -304,7 +269,6 @@ { | ||
} | ||
} // @ts-expect-error TODO Replace Class utility type with InstanceType | ||
} | ||
// @ts-expect-error TODO Replace Class utility type with InstanceType | ||
const serializedChildren = serializedNode.children; | ||
if (lexical.$isElementNode(node)) { | ||
@@ -317,6 +281,4 @@ if (!Array.isArray(serializedChildren)) { | ||
} | ||
return serializedNode; | ||
} | ||
function $appendNodesToJSON(editor, selection$1, currentNode, targetArray = []) { | ||
@@ -326,3 +288,2 @@ let shouldInclude = selection$1 != null ? currentNode.isSelected(selection$1) : true; | ||
let target = currentNode; | ||
if (selection$1 !== null) { | ||
@@ -333,5 +294,6 @@ let clone = selection.$cloneWithProperties(currentNode); | ||
} | ||
const children = lexical.$isElementNode(target) ? target.getChildren() : []; | ||
const serializedNode = exportNodeToJSON(target); | ||
const children = lexical.$isElementNode(target) ? target.getChildren() : []; | ||
const serializedNode = exportNodeToJSON(target); // TODO: TextNode calls getTextContent() (NOT node.__text) within it's exportJSON method | ||
// TODO: TextNode calls getTextContent() (NOT node.__text) within it's exportJSON method | ||
// which uses getLatest() to get the text from the original node with the same key. | ||
@@ -342,8 +304,7 @@ // This is a deeper issue with the word "clone" here, it's still a reference to the | ||
// until then this hack will work for the selected text extract use case. | ||
if (lexical.$isTextNode(target)) { | ||
const text = target.__text; // If an uncollapsed selection ends or starts at the end of a line of specialized, | ||
const text = target.__text; | ||
// If an uncollapsed selection ends or starts at the end of a line of specialized, | ||
// TextNodes, such as code tokens, we will get a 'blank' TextNode here, i.e., one | ||
// with text of length 0. We don't want this, it makes a confusing mess. Reset! | ||
if (text.length > 0) { | ||
@@ -355,7 +316,5 @@ serializedNode.text = text; | ||
} | ||
for (let i = 0; i < children.length; i++) { | ||
const childNode = children[i]; | ||
const shouldIncludeChild = $appendNodesToJSON(editor, selection$1, childNode, serializedNode.children); | ||
if (!shouldInclude && lexical.$isElementNode(currentNode) && shouldIncludeChild && currentNode.extractWithChild(childNode, selection$1, 'clone')) { | ||
@@ -365,3 +324,2 @@ shouldInclude = true; | ||
} | ||
if (shouldInclude && !shouldExclude) { | ||
@@ -375,7 +333,6 @@ targetArray.push(serializedNode); | ||
} | ||
return shouldInclude; | ||
} // TODO why $ function with Editor instance? | ||
} | ||
// TODO why $ function with Editor instance? | ||
function $generateJSONFromSelectedNodes(editor, selection) { | ||
@@ -385,3 +342,2 @@ const nodes = []; | ||
const topLevelChildren = root.getChildren(); | ||
for (let i = 0; i < topLevelChildren.length; i++) { | ||
@@ -391,3 +347,2 @@ const topLevelNode = topLevelChildren[i]; | ||
} | ||
return { | ||
@@ -400,20 +355,17 @@ namespace: editor._config.namespace, | ||
const nodes = []; | ||
for (let i = 0; i < serializedNodes.length; i++) { | ||
const serializedNode = serializedNodes[i]; | ||
const node = lexical.$parseSerializedNode(serializedNode); | ||
if (lexical.$isTextNode(node)) { | ||
selection.$addNodeStyle(node); | ||
} | ||
nodes.push(node); | ||
} | ||
return nodes; | ||
} | ||
const EVENT_LATENCY = 50; | ||
let clipboardEventTimeout = null; // TODO custom selection | ||
let clipboardEventTimeout = null; | ||
// TODO custom selection | ||
// TODO potentially have a node customizable version for plain text | ||
async function copyToClipboard__EXPERIMENTAL(editor, event) { | ||
@@ -425,3 +377,2 @@ if (clipboardEventTimeout !== null) { | ||
} | ||
if (event !== null) { | ||
@@ -434,10 +385,7 @@ return new Promise((resolve, reject) => { | ||
} | ||
const rootElement = editor.getRootElement(); | ||
const domSelection = document.getSelection(); | ||
if (rootElement === null || domSelection === null) { | ||
return false; | ||
} | ||
const element = document.createElement('span'); | ||
@@ -456,3 +404,2 @@ element.style.cssText = 'position: fixed; top: -1000px;'; | ||
removeListener(); | ||
if (clipboardEventTimeout !== null) { | ||
@@ -462,11 +409,9 @@ window.clearTimeout(clipboardEventTimeout); | ||
} | ||
resolve($copyToClipboardEvent(editor, secondEvent)); | ||
} // Block the entire copy flow while we wait for the next ClipboardEvent | ||
} | ||
// Block the entire copy flow while we wait for the next ClipboardEvent | ||
return true; | ||
}, lexical.COMMAND_PRIORITY_CRITICAL); // If the above hack execCommand hack works, this timeout code should never fire. Otherwise, | ||
}, lexical.COMMAND_PRIORITY_CRITICAL); | ||
// If the above hack execCommand hack works, this timeout code should never fire. Otherwise, | ||
// the listener will be quickly freed so that the user can reuse it again | ||
clipboardEventTimeout = window.setTimeout(() => { | ||
@@ -480,42 +425,33 @@ removeListener(); | ||
}); | ||
} // TODO shouldn't pass editor (pass namespace directly) | ||
} | ||
// TODO shouldn't pass editor (pass namespace directly) | ||
function $copyToClipboardEvent(editor, event) { | ||
const domSelection = window.getSelection(); | ||
if (!domSelection) { | ||
return false; | ||
} | ||
const anchorDOM = domSelection.anchorNode; | ||
const focusDOM = domSelection.focusNode; | ||
if (anchorDOM !== null && focusDOM !== null && !lexical.isSelectionWithinEditor(editor, anchorDOM, focusDOM)) { | ||
return false; | ||
} | ||
event.preventDefault(); | ||
const clipboardData = event.clipboardData; | ||
const selection = lexical.$getSelection(); | ||
if (clipboardData === null || selection === null) { | ||
return false; | ||
} | ||
const htmlString = $getHtmlContent(editor); | ||
const lexicalString = $getLexicalContent(editor); | ||
let plainString = ''; | ||
if (selection !== null) { | ||
plainString = selection.getTextContent(); | ||
} | ||
if (htmlString !== null) { | ||
clipboardData.setData('text/html', htmlString); | ||
} | ||
if (lexicalString !== null) { | ||
clipboardData.setData('application/x-lexical-editor', lexicalString); | ||
} | ||
clipboardData.setData('text/plain', plainString); | ||
@@ -522,0 +458,0 @@ return true; |
@@ -12,12 +12,12 @@ { | ||
"license": "MIT", | ||
"version": "0.7.8", | ||
"version": "0.7.9", | ||
"main": "LexicalClipboard.js", | ||
"peerDependencies": { | ||
"lexical": "0.7.8" | ||
"lexical": "0.7.9" | ||
}, | ||
"dependencies": { | ||
"@lexical/utils": "0.7.8", | ||
"@lexical/list": "0.7.8", | ||
"@lexical/selection": "0.7.8", | ||
"@lexical/html": "0.7.8" | ||
"@lexical/utils": "0.7.9", | ||
"@lexical/list": "0.7.9", | ||
"@lexical/selection": "0.7.9", | ||
"@lexical/html": "0.7.9" | ||
}, | ||
@@ -24,0 +24,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
488
28301
+ Added@lexical/html@0.7.9(transitive)
+ Added@lexical/list@0.7.9(transitive)
+ Added@lexical/selection@0.7.9(transitive)
+ Added@lexical/table@0.7.9(transitive)
+ Added@lexical/utils@0.7.9(transitive)
+ Addedlexical@0.7.9(transitive)
- Removed@lexical/html@0.7.8(transitive)
- Removed@lexical/list@0.7.8(transitive)
- Removed@lexical/selection@0.7.8(transitive)
- Removed@lexical/table@0.7.8(transitive)
- Removed@lexical/utils@0.7.8(transitive)
- Removedlexical@0.7.8(transitive)
Updated@lexical/html@0.7.9
Updated@lexical/list@0.7.9
Updated@lexical/selection@0.7.9
Updated@lexical/utils@0.7.9