UNPKG

lexical-beautiful-mentions

Version:
80 lines (79 loc) 4.01 kB
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; import { mergeRegister } from "@lexical/utils"; import { $getSelection, $isDecoratorNode, $isRangeSelection, $nodesOfType, COMMAND_PRIORITY_HIGH, KEY_DOWN_COMMAND, ParagraphNode, SELECTION_CHANGE_COMMAND, } from "lexical"; import { useEffect } from "react"; import { $createPlaceholderNode, $isPlaceholderNode, PlaceholderNode, } from "./PlaceholderNode"; /** * This plugin serves as a patch to fix an incorrect cursor position in Safari. * {@link https://github.com/facebook/lexical/issues/4487}. * @deprecated This plugin is no longer needed and will be removed in a future release. */ export function PlaceholderPlugin() { const [editor] = useLexicalComposerContext(); useEffect(() => { if (!editor.hasNodes([PlaceholderNode])) { throw new Error("BeautifulMentionsPlugin: PlaceholderNode not registered on editor"); } return mergeRegister(editor.registerUpdateListener(() => { editor.update(() => { // insert a placeholder node at the end of each paragraph if the // last node is a decorator node. // eslint-disable-next-line @typescript-eslint/no-deprecated const placeholderNodes = $nodesOfType(PlaceholderNode); // eslint-disable-next-line @typescript-eslint/no-deprecated $nodesOfType(ParagraphNode).forEach((paragraph) => { const paragraphPlaceholders = placeholderNodes.filter((p) => paragraph.isParentOf(p)); const lastNode = paragraph.getLastDescendant(); if ($isDecoratorNode(lastNode)) { paragraphPlaceholders.forEach((p) => { p.remove(); }); lastNode.insertAfter($createPlaceholderNode()); } else if ($isPlaceholderNode(lastNode) && !$isDecoratorNode(lastNode.getPreviousSibling())) { paragraphPlaceholders.forEach((p) => { p.remove(); }); } }); }, // merge with previous history entry to allow undoing { tag: "history-merge" }); }), editor.registerCommand(KEY_DOWN_COMMAND, (event) => { // prevent unnecessary removal of the placeholder nodes, since this // would lead to insertion of another placeholder node and thus break // undo with Ctrl+z if (event.ctrlKey || event.metaKey || event.altKey || event.key === "Shift") { return false; } // if the user starts typing at the placeholder's position, remove // the placeholder node. this makes the PlaceholderNode almost // "invisible" and prevents issues when, for example, when checking // for previous nodes in the code. const selection = $getSelection(); if ($isRangeSelection(selection)) { const [node] = selection.getNodes(); if ($isPlaceholderNode(node)) { node.remove(); } } return false; }, COMMAND_PRIORITY_HIGH), editor.registerCommand(SELECTION_CHANGE_COMMAND, () => { // select the previous node to avoid an error that occurs when the // user tries to insert a node directly after the PlaceholderNode const selection = $getSelection(); if ($isRangeSelection(selection) && selection.isCollapsed()) { const [node] = selection.getNodes(); if ($isPlaceholderNode(node)) { node.selectPrevious(); } } return false; }, COMMAND_PRIORITY_HIGH)); }, [editor]); return null; }