Lexical: Fix autofocus
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
176a3b5ece
commit
b3f9edd41e
|
@ -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<string, IComposeEditor>(({
|
|||
return compose.editorState;
|
||||
}
|
||||
|
||||
return function() {
|
||||
return () => {
|
||||
if (compose.content_type === 'text/markdown') {
|
||||
$createRemarkImport({})(compose.text);
|
||||
} else {
|
||||
|
@ -152,11 +152,10 @@ const ComposeEditor = React.forwardRef<string, IComposeEditor>(({
|
|||
contentEditable={
|
||||
<div className='editor' ref={onRef} onFocus={onFocus} onPaste={handlePaste}>
|
||||
<ContentEditable
|
||||
className={clsx('mr-4 pb-8 outline-none transition-[min-height] motion-reduce:transition-none', {
|
||||
'min-h-[40px]': condensed,
|
||||
'min-h-[100px]': !condensed,
|
||||
className={clsx('outline-none transition-[min-height] motion-reduce:transition-none', {
|
||||
'min-h-[40px] pb-4': condensed,
|
||||
'min-h-[100px] pb-8': !condensed,
|
||||
})}
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
@ -172,7 +171,6 @@ const ComposeEditor = React.forwardRef<string, IComposeEditor>(({
|
|||
)}
|
||||
ErrorBoundary={LexicalErrorBoundary}
|
||||
/>
|
||||
{autoFocus && <AutoFocusPlugin />}
|
||||
<OnChangePlugin onChange={(_, editor) => {
|
||||
if (editorStateRef) (editorStateRef as any).current = editor.getEditorState().read($createRemarkExport());
|
||||
}}
|
||||
|
@ -192,6 +190,7 @@ const ComposeEditor = React.forwardRef<string, IComposeEditor>(({
|
|||
</>
|
||||
)}
|
||||
<StatePlugin composeId={composeId} handleSubmit={handleSubmit} />
|
||||
<FocusPlugin autoFocus={autoFocus} />
|
||||
</div>
|
||||
</LexicalComposer>
|
||||
);
|
||||
|
|
|
@ -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 (
|
||||
<img
|
||||
|
@ -76,9 +76,9 @@ function LazyImage({
|
|||
draggable='false'
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
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 | HTMLImageElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
||||
const [isSelected, setSelected, clearSelection] =
|
||||
|
@ -270,4 +270,6 @@ export default function ImageComponent({
|
|||
</>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default ImageComponent;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface IFocusPlugin {
|
||||
autoFocus?: boolean
|
||||
}
|
||||
|
||||
const FocusPlugin: React.FC<IFocusPlugin> = ({ 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;
|
|
@ -86,6 +86,7 @@ const ComposeModal: React.FC<IComposeModal> = ({ onClose, composeId = 'compose-m
|
|||
<ComposeForm
|
||||
id={composeId}
|
||||
extra={<ComposeFormGroupToggle composeId={composeId} groupId={groupId} />}
|
||||
autoFocus
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue