From b3f9edd41e00c3b356db5d838b28e05934252c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 22 Jul 2023 17:20:47 +0200 Subject: [PATCH] Lexical: Fix autofocus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/features/compose/editor/index.tsx | 29 ++++++++-------- .../compose/editor/nodes/image-component.tsx | 18 +++++----- .../compose/editor/plugins/focus-plugin.tsx | 33 +++++++++++++++++++ .../ui/components/modals/compose-modal.tsx | 1 + 4 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 app/soapbox/features/compose/editor/plugins/focus-plugin.tsx diff --git a/app/soapbox/features/compose/editor/index.tsx b/app/soapbox/features/compose/editor/index.tsx index 45d715584..611225728 100644 --- a/app/soapbox/features/compose/editor/index.tsx +++ b/app/soapbox/features/compose/editor/index.tsx @@ -6,7 +6,6 @@ Copyright (c) Meta Platforms, Inc. and affiliates. This source code is licensed under the MIT license found in the LICENSE file in the /app/soapbox/features/compose/editor directory. */ -import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin'; import { AutoLinkPlugin, createLinkMatcherWithRegExp } from '@lexical/react/LexicalAutoLinkPlugin'; import { LexicalComposer, InitialConfigType } from '@lexical/react/LexicalComposer'; import { ContentEditable } from '@lexical/react/LexicalContentEditable'; @@ -25,6 +24,15 @@ import { FormattedMessage } from 'react-intl'; import { useAppDispatch, useFeatures } from 'soapbox/hooks'; +import { useNodes } from './nodes'; +import AutosuggestPlugin from './plugins/autosuggest-plugin'; +import FloatingBlockTypeToolbarPlugin from './plugins/floating-block-type-toolbar-plugin'; +import FloatingLinkEditorPlugin from './plugins/floating-link-editor-plugin'; +import FloatingTextFormatToolbarPlugin from './plugins/floating-text-format-toolbar-plugin'; +import FocusPlugin from './plugins/focus-plugin'; +import MentionPlugin from './plugins/mention-plugin'; +import StatePlugin from './plugins/state-plugin'; + const LINK_MATCHERS = [ createLinkMatcherWithRegExp( /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, @@ -32,14 +40,6 @@ const LINK_MATCHERS = [ ), ]; -import { useNodes } from './nodes'; -import AutosuggestPlugin from './plugins/autosuggest-plugin'; -import FloatingBlockTypeToolbarPlugin from './plugins/floating-block-type-toolbar-plugin'; -import FloatingLinkEditorPlugin from './plugins/floating-link-editor-plugin'; -import FloatingTextFormatToolbarPlugin from './plugins/floating-text-format-toolbar-plugin'; -import MentionPlugin from './plugins/mention-plugin'; -import StatePlugin from './plugins/state-plugin'; - interface IComposeEditor { className?: string placeholderClassName?: string @@ -104,7 +104,7 @@ const ComposeEditor = React.forwardRef(({ return compose.editorState; } - return function() { + return () => { if (compose.content_type === 'text/markdown') { $createRemarkImport({})(compose.text); } else { @@ -152,11 +152,10 @@ const ComposeEditor = React.forwardRef(({ contentEditable={
} @@ -172,7 +171,6 @@ const ComposeEditor = React.forwardRef(({ )} ErrorBoundary={LexicalErrorBoundary} /> - {autoFocus && } { if (editorStateRef) (editorStateRef as any).current = editor.getEditorState().read($createRemarkExport()); }} @@ -192,6 +190,7 @@ const ComposeEditor = React.forwardRef(({ )} + ); diff --git a/app/soapbox/features/compose/editor/nodes/image-component.tsx b/app/soapbox/features/compose/editor/nodes/image-component.tsx index 3ef95db72..ed686af4b 100644 --- a/app/soapbox/features/compose/editor/nodes/image-component.tsx +++ b/app/soapbox/features/compose/editor/nodes/image-component.tsx @@ -42,7 +42,7 @@ import type { const imageCache = new Set(); -function useSuspenseImage(src: string) { +const useSuspenseImage = (src: string) => { if (!imageCache.has(src)) { throw new Promise((resolve) => { const img = new Image(); @@ -53,9 +53,9 @@ function useSuspenseImage(src: string) { }; }); } -} +}; -function LazyImage({ +const LazyImage = ({ altText, className, imageRef, @@ -65,7 +65,7 @@ function LazyImage({ className: string | null imageRef: {current: null | HTMLImageElement} src: string -}): JSX.Element { +}): JSX.Element => { useSuspenseImage(src); return ( ); -} +}; -export default function ImageComponent({ +const ImageComponent = ({ src, altText, nodeKey, @@ -86,7 +86,7 @@ export default function ImageComponent({ altText: string nodeKey: NodeKey src: string -}): JSX.Element { +}): JSX.Element => { const imageRef = useRef(null); const buttonRef = useRef(null); const [isSelected, setSelected, clearSelection] = @@ -270,4 +270,6 @@ export default function ImageComponent({ ); -} +}; + +export default ImageComponent; diff --git a/app/soapbox/features/compose/editor/plugins/focus-plugin.tsx b/app/soapbox/features/compose/editor/plugins/focus-plugin.tsx new file mode 100644 index 000000000..04d07652e --- /dev/null +++ b/app/soapbox/features/compose/editor/plugins/focus-plugin.tsx @@ -0,0 +1,33 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { useEffect } from 'react'; + +interface IFocusPlugin { + autoFocus?: boolean +} + +const FocusPlugin: React.FC = ({ autoFocus }) => { + const [editor] = useLexicalComposerContext(); + + const focus = () => { + editor.focus( + () => { + const activeElement = document.activeElement; + const rootElement = editor.getRootElement(); + if ( + rootElement !== null && + (activeElement === null || !rootElement.contains(activeElement)) + ) { + rootElement.focus({ preventScroll: true }); + } + }, { defaultSelection: 'rootEnd' }, + ); + }; + + useEffect(() => { + if (autoFocus) focus(); + }, []); + + return null; +}; + +export default FocusPlugin; diff --git a/app/soapbox/features/ui/components/modals/compose-modal.tsx b/app/soapbox/features/ui/components/modals/compose-modal.tsx index 2bbdb4a2e..353d26d91 100644 --- a/app/soapbox/features/ui/components/modals/compose-modal.tsx +++ b/app/soapbox/features/ui/components/modals/compose-modal.tsx @@ -86,6 +86,7 @@ const ComposeModal: React.FC = ({ onClose, composeId = 'compose-m } + autoFocus /> );