From 5ccde0de589464c44cdb57855b689ee0ffa25cb9 Mon Sep 17 00:00:00 2001 From: Ben Carleton Date: Fri, 13 Oct 2023 23:25:46 +0100 Subject: [PATCH] Fix: right click select images (#5056) Co-authored-by: bcarleton3 --- .../src/nodes/ImageComponent.tsx | 79 ++++++++++++++----- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/packages/lexical-playground/src/nodes/ImageComponent.tsx b/packages/lexical-playground/src/nodes/ImageComponent.tsx index d516e944835..d00748ca063 100644 --- a/packages/lexical-playground/src/nodes/ImageComponent.tsx +++ b/packages/lexical-playground/src/nodes/ImageComponent.tsx @@ -8,6 +8,7 @@ import type { GridSelection, + LexicalCommand, LexicalEditor, NodeKey, NodeSelection, @@ -31,9 +32,11 @@ import { $getNodeByKey, $getSelection, $isNodeSelection, + $isRangeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, + createCommand, DRAGSTART_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, @@ -59,6 +62,9 @@ import {$isImageNode} from './ImageNode'; const imageCache = new Set(); +export const RIGHT_CLICK_IMAGE_COMMAND: LexicalCommand = + createCommand('RIGHT_CLICK_IMAGE_COMMAND'); + function useSuspenseImage(src: string) { if (!imageCache.has(src)) { throw new Promise((resolve) => { @@ -206,8 +212,51 @@ export default function ImageComponent({ [caption, editor, setSelected], ); + const onClick = useCallback( + (payload: MouseEvent) => { + const event = payload; + + if (isResizing) { + return true; + } + if (event.target === imageRef.current) { + if (event.shiftKey) { + setSelected(!isSelected); + } else { + clearSelection(); + setSelected(true); + } + return true; + } + + return false; + }, + [isResizing, isSelected, setSelected, clearSelection], + ); + + const onRightClick = useCallback( + (event: MouseEvent): void => { + editor.getEditorState().read(() => { + const latestSelection = $getSelection(); + const domElement = event.target as HTMLElement; + if ( + domElement.tagName === 'IMG' && + $isRangeSelection(latestSelection) && + latestSelection.getNodes().length === 1 + ) { + editor.dispatchCommand( + RIGHT_CLICK_IMAGE_COMMAND, + event as MouseEvent, + ); + } + }); + }, + [editor], + ); + useEffect(() => { let isMounted = true; + const rootElement = editor.getRootElement(); const unregister = mergeRegister( editor.registerUpdateListener(({editorState}) => { if (isMounted) { @@ -224,24 +273,12 @@ export default function ImageComponent({ ), editor.registerCommand( CLICK_COMMAND, - (payload) => { - const event = payload; - - if (isResizing) { - return true; - } - if (event.target === imageRef.current) { - if (event.shiftKey) { - setSelected(!isSelected); - } else { - clearSelection(); - setSelected(true); - } - return true; - } - - return false; - }, + onClick, + COMMAND_PRIORITY_LOW, + ), + editor.registerCommand( + RIGHT_CLICK_IMAGE_COMMAND, + onClick, COMMAND_PRIORITY_LOW, ), editor.registerCommand( @@ -274,9 +311,13 @@ export default function ImageComponent({ COMMAND_PRIORITY_LOW, ), ); + + rootElement?.addEventListener('contextmenu', onRightClick); + return () => { isMounted = false; unregister(); + rootElement?.removeEventListener('contextmenu', onRightClick); }; }, [ clearSelection, @@ -287,6 +328,8 @@ export default function ImageComponent({ onDelete, onEnter, onEscape, + onClick, + onRightClick, setSelected, ]);