From 276fa217efb5161cd100c6cb684e4c1faea69320 Mon Sep 17 00:00:00 2001 From: Kohei Yoshino Date: Wed, 12 Jun 2024 22:45:13 -0400 Subject: [PATCH] Fix some text editor issues https://github.com/sveltia/sveltia-cms/issues/164 --- src/lib/components/text-editor/core.js | 49 +++++++++++++++++++ .../text-editor/lexical-root.svelte | 4 ++ .../components/text-editor/text-editor.svelte | 4 +- .../toolbar/toggle-block-menu-item.svelte | 5 ++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/lib/components/text-editor/core.js b/src/lib/components/text-editor/core.js index 7161e76..e8530b4 100644 --- a/src/lib/components/text-editor/core.js +++ b/src/lib/components/text-editor/core.js @@ -11,6 +11,7 @@ import { INSERT_UNORDERED_LIST_COMMAND, ListItemNode, ListNode, + $handleListInsertParagraph as handleListInsertParagraph, insertList, $isListItemNode as isListItemNode, $isListNode as isListNode, @@ -32,6 +33,9 @@ import { $getNearestNodeOfType as getNearestNodeOfType } from '@lexical/utils'; import { COMMAND_PRIORITY_NORMAL, ElementNode, + INDENT_CONTENT_COMMAND, + INSERT_PARAGRAPH_COMMAND, + OUTDENT_CONTENT_COMMAND, createEditor, $getSelection as getSelection, $isRangeSelection as isRangeSelection, @@ -64,6 +68,11 @@ const editorConfig = { */ italic: 'italic', }, + list: { + nested: { + listitem: 'nested', + }, + }, }, }; @@ -176,6 +185,13 @@ export const initEditor = () => { COMMAND_PRIORITY_NORMAL, ); + // https://github.com/facebook/lexical/blob/main/packages/lexical-react/src/shared/useList.ts + editor.registerCommand( + INSERT_PARAGRAPH_COMMAND, + () => handleListInsertParagraph(), + COMMAND_PRIORITY_NORMAL, + ); + editor.registerUpdateListener(({ editorState }) => { if (editor?.isComposing()) { return; @@ -186,6 +202,39 @@ export const initEditor = () => { }); }); + // `editor.registerCommand(KEY_TAB_COMMAND, listener, priority)` doesn’t work for some reason, so + // use another method + editor.registerRootListener((root) => { + if (root) { + root.addEventListener('keydown', (event) => { + editor.update(() => { + if (event.key === 'Tab') { + const selection = getSelection(); + + if (!isRangeSelection(selection)) { + return; + } + + const anchor = selection.anchor.getNode(); + + const parent = + anchor instanceof ElementNode ? anchor : getNearestNodeOfType(anchor, ElementNode); + + if (isListItemNode(parent) && parent.canIndent()) { + if (!event.shiftKey) { + event.preventDefault(); + editor.dispatchCommand(INDENT_CONTENT_COMMAND, undefined); + } else if (parent.getIndent() > 0) { + event.preventDefault(); + editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, undefined); + } + } + } + }); + }); + } + }); + return editor; }; diff --git a/src/lib/components/text-editor/lexical-root.svelte b/src/lib/components/text-editor/lexical-root.svelte index 101387c..17c0009 100644 --- a/src/lib/components/text-editor/lexical-root.svelte +++ b/src/lib/components/text-editor/lexical-root.svelte @@ -139,6 +139,10 @@ font-style: italic; } + :global(li.nested) { + list-style-type: none; + } + :global([data-lexical-text='true']) { cursor: text; } diff --git a/src/lib/components/text-editor/text-editor.svelte b/src/lib/components/text-editor/text-editor.svelte index fa03b3f..dfd1b2e 100644 --- a/src/lib/components/text-editor/text-editor.svelte +++ b/src/lib/components/text-editor/text-editor.svelte @@ -95,11 +95,11 @@ * Update {@link inputValue} based on {@link value}. */ const setInputValue = () => { - const newValue = value ?? ''; + const newValue = value; // Avoid a cycle dependency & infinite loop if (inputValue !== newValue) { - inputValue = newValue; + inputValue = newValue ?? ''; if ($useRichText) { convertMarkdown(); diff --git a/src/lib/components/text-editor/toolbar/toggle-block-menu-item.svelte b/src/lib/components/text-editor/toolbar/toggle-block-menu-item.svelte index 915b58d..44a4a9d 100644 --- a/src/lib/components/text-editor/toolbar/toggle-block-menu-item.svelte +++ b/src/lib/components/text-editor/toolbar/toggle-block-menu-item.svelte @@ -66,6 +66,11 @@ setBlocksType(getSelection(), () => createQuoteNode()); }); } + + // Move focus back to the editor + window.setTimeout(() => { + $editor.focus(); + }, 500); };