From ee895ad44dedf5909a500b95bffbbf94c6b2295b Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Mon, 8 Jan 2024 19:56:15 +0530 Subject: [PATCH] refactor: select image/file node in super when clicking inside it --- .../Plugins/EncryptedFilePlugin/FilePlugin.ts | 5 +- .../Nodes/FileComponent.tsx | 26 ++++++++++- .../RemoteImageComponent.tsx | 31 +++++++++++-- .../RemoteImagePlugin/RemoteImagePlugin.tsx | 46 +++++++++++++------ 4 files changed, 86 insertions(+), 22 deletions(-) diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/FilePlugin.ts b/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/FilePlugin.ts index 000a83741..a299fd3c6 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/FilePlugin.ts +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/FilePlugin.ts @@ -77,9 +77,8 @@ export default function FilePlugin({ currentNote }: { currentNote: SNNote }): JS ), editor.registerNodeTransform(FileNode, (node) => { /** - * Before this was added, we used to wrap the file node in a paragraph node, - * which caused issues with selection. We no longer do that, but for existing - * notes that have this, we use this transform to remove the wrapper node. + * When adding the node we wrap it with a paragraph to avoid insertion errors, + * however that causes issues with selection. We unwrap the node to fix that. */ const parent = node.getParent() if (!parent) { diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/Nodes/FileComponent.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/Nodes/FileComponent.tsx index 06d60a4ca..f21272489 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/Nodes/FileComponent.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/EncryptedFilePlugin/Nodes/FileComponent.tsx @@ -1,10 +1,11 @@ import { BlockWithAlignableContents } from '@lexical/react/LexicalBlockWithAlignableContents' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { ElementFormatType, NodeKey } from 'lexical' +import { $getNodeByKey, CLICK_COMMAND, COMMAND_PRIORITY_LOW, ElementFormatType, NodeKey } from 'lexical' import { useApplication } from '@/Components/ApplicationProvider' import FilePreview from '@/Components/FilePreview/FilePreview' import { FileItem } from '@standardnotes/snjs' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' +import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection' export type FileComponentProps = Readonly<{ className: Readonly<{ @@ -66,6 +67,29 @@ export function FileComponent({ className, format, nodeKey, fileUuid, zoomLevel, [editor, setZoomLevel], ) + const [isSelected, setSelected] = useLexicalNodeSelection(nodeKey) + + useEffect(() => { + return editor.registerCommand( + CLICK_COMMAND, + (event) => { + if (blockWrapperRef.current?.contains(event.target as Node)) { + event.preventDefault() + + $getNodeByKey(nodeKey)?.selectEnd() + + setTimeout(() => { + setSelected(!isSelected) + }) + return true + } + + return false + }, + COMMAND_PRIORITY_LOW, + ) + }, [editor, isSelected, nodeKey, setSelected]) + if (!file) { return ( diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/RemoteImagePlugin/RemoteImageComponent.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/RemoteImagePlugin/RemoteImageComponent.tsx index cfd38a111..01ce99937 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/RemoteImagePlugin/RemoteImageComponent.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/RemoteImagePlugin/RemoteImageComponent.tsx @@ -5,11 +5,12 @@ import { isDesktopApplication } from '@/Utils' import { BlockWithAlignableContents } from '@lexical/react/LexicalBlockWithAlignableContents' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { classNames, Platform } from '@standardnotes/snjs' -import { ElementFormatType, NodeKey } from 'lexical' -import { useCallback, useState } from 'react' +import { $getNodeByKey, CLICK_COMMAND, COMMAND_PRIORITY_LOW, ElementFormatType, NodeKey } from 'lexical' +import { useCallback, useEffect, useRef, useState } from 'react' import { $createFileNode } from '../EncryptedFilePlugin/Nodes/FileUtils' import { RemoteImageNode } from './RemoteImageNode' import { isIOS } from '@standardnotes/ui-services' +import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection' type Props = { src: string @@ -66,9 +67,33 @@ const RemoteImageComponent = ({ className, src, alt, node, format, nodeKey }: Pr const isBase64OrDataUrl = src.startsWith('data:') const canShowSaveButton = application.isNativeMobileWeb() || isDesktopApplication() || isBase64OrDataUrl + const ref = useRef(null) + const [isSelected, setSelected] = useLexicalNodeSelection(nodeKey) + + useEffect(() => { + return editor.registerCommand( + CLICK_COMMAND, + (event) => { + if (ref.current?.contains(event.target as Node)) { + event.preventDefault() + + $getNodeByKey(nodeKey)?.selectEnd() + + setTimeout(() => { + setSelected(!isSelected) + }) + return true + } + + return false + }, + COMMAND_PRIORITY_LOW, + ) + }, [editor, isSelected, nodeKey, setSelected]) + return ( -
+
{alt} void }) { const [url, setURL] = useState('') @@ -35,20 +35,36 @@ export default function RemoteImagePlugin() { const [editor] = useLexicalComposerContext() useEffect(() => { - return editor.registerCommand( - INSERT_REMOTE_IMAGE_COMMAND, - (payload) => { - const imageNode = $createRemoteImageNode(payload) - $insertNodes([imageNode]) - if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) { - $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd() - } - const newLineNode = $createParagraphNode() - imageNode.getParentOrThrow().insertAfter(newLineNode) + return mergeRegister( + editor.registerCommand( + INSERT_REMOTE_IMAGE_COMMAND, + (payload) => { + const imageNode = $createRemoteImageNode(payload) + $insertNodes([imageNode]) + if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) { + $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd() + } + const newLineNode = $createParagraphNode() + imageNode.getParentOrThrow().insertAfter(newLineNode) - return true - }, - COMMAND_PRIORITY_NORMAL, + return true + }, + COMMAND_PRIORITY_NORMAL, + ), + editor.registerNodeTransform(RemoteImageNode, (node) => { + /** + * When adding the node we wrap it with a paragraph to avoid insertion errors, + * however that causes issues with selection. We unwrap the node to fix that. + */ + const parent = node.getParent() + if (!parent) { + return + } + if (parent.getChildrenSize() === 1) { + parent.insertBefore(node) + parent.remove() + } + }), ) }, [editor])