From 154ad9d13229f5fa2866762e5c35bbab60cf4956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Sun, 22 Dec 2024 12:18:23 -0300 Subject: [PATCH] fix(richtext-lexical): restore selection (#10129) Fix #9964 Now we make sure that the node for the previous selection exists before restoring it to avoid a runtime error. I also optimized the performance of a function in the client feature. In the future, we should centralize the insertion of all decorator blocks in one place. There are several things to improve. For example, currently an additional paragraph is inserted (in addition to the one for the selection we delete). --- .../features/upload/client/plugin/index.tsx | 10 +++------- .../fieldsDrawer/useLexicalListDrawer.tsx | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx b/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx index c3c6d08407..a01f20c0d9 100644 --- a/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx +++ b/packages/richtext-lexical/src/features/upload/client/plugin/index.tsx @@ -59,15 +59,11 @@ export const UploadPlugin: PluginComponent = ({ client const { focus } = selection const focusNode = focus.getNode() - // First, delete currently selected node if it's an empty paragraph and if there are sufficient - // paragraph nodes (more than 1) left in the parent node, so that we don't "trap" the user + // Delete the node it it's an empty paragraph and it has at least one sibling, so that we don't "trap" the user if ( $isParagraphNode(focusNode) && - focusNode.getTextContentSize() === 0 && - focusNode - .getParentOrThrow() - .getChildren() - .filter((node) => $isParagraphNode(node)).length > 1 + !focusNode.__first && + (focusNode.__prev || focusNode.__next) ) { focusNode.remove() } diff --git a/packages/richtext-lexical/src/utilities/fieldsDrawer/useLexicalListDrawer.tsx b/packages/richtext-lexical/src/utilities/fieldsDrawer/useLexicalListDrawer.tsx index 157274b78e..ed5cc1e707 100644 --- a/packages/richtext-lexical/src/utilities/fieldsDrawer/useLexicalListDrawer.tsx +++ b/packages/richtext-lexical/src/utilities/fieldsDrawer/useLexicalListDrawer.tsx @@ -4,7 +4,14 @@ import type { BaseSelection } from 'lexical' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { useListDrawer, useModal } from '@payloadcms/ui' -import { $getPreviousSelection, $getSelection, $setSelection } from 'lexical' +import { + $getNodeByKey, + $getPreviousSelection, + $getRoot, + $getSelection, + $isRangeSelection, + $setSelection, +} from 'lexical' import { useCallback, useEffect, useState } from 'react' /** @@ -49,7 +56,16 @@ export const useLexicalListDrawer = ( if (selectionState) { editor.update( () => { - $setSelection(selectionState.clone()) + if ($isRangeSelection(selectionState)) { + const { anchor, focus } = selectionState + if ($getNodeByKey(anchor.key) && $getNodeByKey(focus.key)) { + $setSelection(selectionState.clone()) + } + } else { + // not ideal, but better than losing the selection. Try to set the selection + // in a valid place if you remove selected nodes! + $getRoot().selectEnd() + } }, { discrete: true, skipTransforms: true }, )