From 992433b4193faf4de0d394d4806e172c4dfad4f2 Mon Sep 17 00:00:00 2001 From: Ajinkya Date: Thu, 17 Jul 2025 19:07:53 +0530 Subject: [PATCH 1/5] fix:handle the missing link on the draggable image --- .../src/plugins/ImagesPlugin/index.tsx | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx index 4097c58a47f..a825e9295f0 100644 --- a/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx @@ -8,11 +8,13 @@ import type {JSX} from 'react'; +import {$createLinkNode, LinkNode} from '@lexical/link'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$wrapNodeInElement, mergeRegister} from '@lexical/utils'; import { $createParagraphNode, $createRangeSelection, + $getNodeByKey, $getSelection, $insertNodes, $isNodeSelection, @@ -272,6 +274,7 @@ function $onDragStart(event: DragEvent): boolean { if (!dataTransfer) { return false; } + dataTransfer.setData('text/plain', '_'); dataTransfer.setDragImage(img, 0, 0); dataTransfer.setData( @@ -306,25 +309,67 @@ function $onDragover(event: DragEvent): boolean { } function $onDrop(event: DragEvent, editor: LexicalEditor): boolean { + // Get the currently selected image node const node = $getImageNodeInSelection(); if (!node) { - return false; + return false; // No image node selected, exit early + } + + // Get the parent node's key + const parent_key = String(node.__parent); + let link = ''; + if (node) { + // Check if the parent node is a link + const nodelink = $getNodeByKey(parent_key); + if (nodelink?.__type === 'link') { + // Cast to LinkNode to safely access the URL + const linkNode = nodelink as LinkNode; + link = linkNode.__url || ''; // Extract the URL or default to empty string + } } + + // Retrieve image data from the drag event const data = getDragImageData(event); if (!data) { - return false; + return false; // No valid image data, exit early } + + // Prevent default browser drop behavior event.preventDefault(); + + // Check if the image can be dropped at the current location if (canDropImage(event)) { + // Get the drop range from the event const range = getDragSelection(event); + + // Remove the original image node node.remove(); + + // Create a new range selection for the drop position const rangeSelection = $createRangeSelection(); if (range !== null && range !== undefined) { + // Apply the drop range to the selection rangeSelection.applyDOMRange(range); } + + // Set the editor's selection to the new range $setSelection(rangeSelection); - editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); + + if (link) { + // If a link exists, wrap the image in a link node + editor.update(() => { + const linkNode = $createLinkNode(link); // Create a new link node + const imageNode = $createImageNode(data); // Create a new image node + linkNode.append(imageNode); // Set image as child of link node + $insertNodes([linkNode]); // Insert the link node (with image) into the editor + }); + } else { + // If no link, insert the image directly + editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); + } } + + // Indicate that the drop event was handled return true; } From fcc767ff5c623f20dbc6fc9ff2a27ff9962c22aa Mon Sep 17 00:00:00 2001 From: Ajinkya Date: Thu, 17 Jul 2025 23:34:05 +0530 Subject: [PATCH 2/5] fix:Code Block formatting applies to unintended adjacent lines --- .../src/plugins/ToolbarPlugin/utils.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts b/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts index 6c1501a7c68..3407f085afd 100644 --- a/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts +++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts @@ -24,6 +24,7 @@ import {$isTableSelection} from '@lexical/table'; import {$getNearestBlockElementAncestorOrThrow} from '@lexical/utils'; import { $createParagraphNode, + $createTextNode, $getSelection, $isRangeSelection, $isTextNode, @@ -214,7 +215,7 @@ export const formatQuote = (editor: LexicalEditor, blockType: string) => { export const formatCode = (editor: LexicalEditor, blockType: string) => { if (blockType !== 'code') { editor.update(() => { - let selection = $getSelection(); + const selection = $getSelection(); if (!selection) { return; } @@ -223,11 +224,14 @@ export const formatCode = (editor: LexicalEditor, blockType: string) => { } else { const textContent = selection.getTextContent(); const codeNode = $createCodeNode(); - selection.insertNodes([codeNode]); - selection = $getSelection(); - if ($isRangeSelection(selection)) { - selection.insertRawText(textContent); - } + const anchorNode = selection.anchor.getNode(); + + // Insert code node just below the selected node (as its sibling) + anchorNode.insertAfter(codeNode); + // Insert the selected text into the code node + codeNode.append($createTextNode(textContent)); + // Remove the selected content + selection.removeText(); } }); } From d59b9254ed1eae8cc942dfadc6be0400f3b1caed Mon Sep 17 00:00:00 2001 From: Ajinkya Date: Thu, 17 Jul 2025 23:42:49 +0530 Subject: [PATCH 3/5] revert_changes --- .../src/plugins/ImagesPlugin/index.tsx | 51 ++----------------- 1 file changed, 3 insertions(+), 48 deletions(-) diff --git a/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx index a825e9295f0..4097c58a47f 100644 --- a/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx @@ -8,13 +8,11 @@ import type {JSX} from 'react'; -import {$createLinkNode, LinkNode} from '@lexical/link'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$wrapNodeInElement, mergeRegister} from '@lexical/utils'; import { $createParagraphNode, $createRangeSelection, - $getNodeByKey, $getSelection, $insertNodes, $isNodeSelection, @@ -274,7 +272,6 @@ function $onDragStart(event: DragEvent): boolean { if (!dataTransfer) { return false; } - dataTransfer.setData('text/plain', '_'); dataTransfer.setDragImage(img, 0, 0); dataTransfer.setData( @@ -309,67 +306,25 @@ function $onDragover(event: DragEvent): boolean { } function $onDrop(event: DragEvent, editor: LexicalEditor): boolean { - // Get the currently selected image node const node = $getImageNodeInSelection(); if (!node) { - return false; // No image node selected, exit early - } - - // Get the parent node's key - const parent_key = String(node.__parent); - let link = ''; - if (node) { - // Check if the parent node is a link - const nodelink = $getNodeByKey(parent_key); - if (nodelink?.__type === 'link') { - // Cast to LinkNode to safely access the URL - const linkNode = nodelink as LinkNode; - link = linkNode.__url || ''; // Extract the URL or default to empty string - } + return false; } - - // Retrieve image data from the drag event const data = getDragImageData(event); if (!data) { - return false; // No valid image data, exit early + return false; } - - // Prevent default browser drop behavior event.preventDefault(); - - // Check if the image can be dropped at the current location if (canDropImage(event)) { - // Get the drop range from the event const range = getDragSelection(event); - - // Remove the original image node node.remove(); - - // Create a new range selection for the drop position const rangeSelection = $createRangeSelection(); if (range !== null && range !== undefined) { - // Apply the drop range to the selection rangeSelection.applyDOMRange(range); } - - // Set the editor's selection to the new range $setSelection(rangeSelection); - - if (link) { - // If a link exists, wrap the image in a link node - editor.update(() => { - const linkNode = $createLinkNode(link); // Create a new link node - const imageNode = $createImageNode(data); // Create a new image node - linkNode.append(imageNode); // Set image as child of link node - $insertNodes([linkNode]); // Insert the link node (with image) into the editor - }); - } else { - // If no link, insert the image directly - editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); - } + editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); } - - // Indicate that the drop event was handled return true; } From 354ead86dd5a91dff456a013dad931c822fb531a Mon Sep 17 00:00:00 2001 From: Ajinkya Date: Fri, 18 Jul 2025 19:19:33 +0530 Subject: [PATCH 4/5] table break changes --- .../src/LexicalTableSelectionHelpers.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts index 6c591e1e88e..966c86afd67 100644 --- a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts +++ b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts @@ -691,10 +691,23 @@ export function applyTableHandlers( selection, tableNode, ); + const lastChild = tableCellNode.getLastChild(); + const isLastChildPageBreak = + lastChild && lastChild.getType() === 'page-break'; // Adjust 'page-break' to the actual node type for page breaks if (edgePosition) { $insertParagraphAtTableEdge(edgePosition, tableNode, [ $createTextNode(payload), ]); + return true; + } else if (isLastChildPageBreak && edgePosition === undefined) { + // Create a new paragraph node with the payload text + const newParagraph = $createParagraphNode(); + newParagraph.append($createTextNode(payload)); + // Insert the new paragraph after the last child (page-break) + lastChild.insertAfter(newParagraph); + // Optionally, move the selection to the new paragraph + newParagraph.selectEnd(); + return true; } } From baead425c09984d74ab09cab666c2f7996c31db2 Mon Sep 17 00:00:00 2001 From: Ajinkya Date: Fri, 18 Jul 2025 19:23:52 +0530 Subject: [PATCH 5/5] utils changed to the main one --- .../src/plugins/ToolbarPlugin/utils.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts b/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts index 3407f085afd..6c1501a7c68 100644 --- a/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts +++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/utils.ts @@ -24,7 +24,6 @@ import {$isTableSelection} from '@lexical/table'; import {$getNearestBlockElementAncestorOrThrow} from '@lexical/utils'; import { $createParagraphNode, - $createTextNode, $getSelection, $isRangeSelection, $isTextNode, @@ -215,7 +214,7 @@ export const formatQuote = (editor: LexicalEditor, blockType: string) => { export const formatCode = (editor: LexicalEditor, blockType: string) => { if (blockType !== 'code') { editor.update(() => { - const selection = $getSelection(); + let selection = $getSelection(); if (!selection) { return; } @@ -224,14 +223,11 @@ export const formatCode = (editor: LexicalEditor, blockType: string) => { } else { const textContent = selection.getTextContent(); const codeNode = $createCodeNode(); - const anchorNode = selection.anchor.getNode(); - - // Insert code node just below the selected node (as its sibling) - anchorNode.insertAfter(codeNode); - // Insert the selected text into the code node - codeNode.append($createTextNode(textContent)); - // Remove the selected content - selection.removeText(); + selection.insertNodes([codeNode]); + selection = $getSelection(); + if ($isRangeSelection(selection)) { + selection.insertRawText(textContent); + } } }); }