From b85b5dacee8482a61fdd94aef5ffca34740da2f6 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Wed, 26 Oct 2022 12:39:18 +0200 Subject: [PATCH] Fix cursor position --- .../components/PlainTextComposer.tsx | 10 ++----- .../components/WysiwygComposer.tsx | 3 ++ .../hooks/usePlainTextInitialization.ts | 28 +++++++++++++++++++ .../hooks/useSetCursorPosition.ts | 27 ++++++++++++++++++ .../rooms/wysiwyg_composer/hooks/utils.ts | 11 ++++++++ 5 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts create mode 100644 src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts diff --git a/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx b/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx index d873c3549c..f23c1725c2 100644 --- a/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx @@ -14,9 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { MutableRefObject, ReactNode, useEffect } from 'react'; +import React, { MutableRefObject, ReactNode } from 'react'; import { useComposerFunctions } from '../hooks/useComposerFunctions'; +import { usePlainTextInitialization } from '../hooks/usePlainTextInitialization'; import { usePlainTextListeners } from '../hooks/usePlainTextListeners'; import { ComposerFunctions } from '../types'; import { Editor } from "./Editor"; @@ -38,12 +39,7 @@ export function PlainTextComposer({ ) { const { ref, onInput, onPaste, onKeyDown } = usePlainTextListeners(onChange, onSend); const composerFunctions = useComposerFunctions(ref); - - useEffect(() => { - if (ref.current) { - ref.current.innerText = initialContent; - } - }, [ref, initialContent]); + usePlainTextInitialization(initialContent, ref); return
diff --git a/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx index 7dc059ffb2..dce20f6815 100644 --- a/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer.tsx @@ -20,6 +20,7 @@ import { useWysiwyg, FormattingFunctions } from "@matrix-org/matrix-wysiwyg"; import { FormattingButtons } from './FormattingButtons'; import { Editor } from './Editor'; import { useInputEventProcessor } from '../hooks/useInputEventProcessor'; +import { useSetCursorPosition } from '../hooks/useSetCursorPosition'; interface WysiwygComposerProps { disabled?: boolean; @@ -47,6 +48,8 @@ export const WysiwygComposer = memo(function WysiwygComposer( } }, [onChange, content, disabled]); + useSetCursorPosition(isWysiwygReady, ref); + return (
diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts new file mode 100644 index 0000000000..dcaacd98ea --- /dev/null +++ b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextInitialization.ts @@ -0,0 +1,28 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { RefObject, useEffect } from "react"; + +import { setCursorPositionAtTheEnd } from "./utils"; + +export function usePlainTextInitialization(initialContent: string, ref: RefObject) { + useEffect(() => { + if (ref.current) { + ref.current.innerText = initialContent; + setCursorPositionAtTheEnd(ref.current); + } + }, [ref, initialContent]); +} diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts b/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts new file mode 100644 index 0000000000..92555f563f --- /dev/null +++ b/src/components/views/rooms/wysiwyg_composer/hooks/useSetCursorPosition.ts @@ -0,0 +1,27 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { RefObject, useEffect } from "react"; + +import { setCursorPositionAtTheEnd } from "./utils"; + +export function useSetCursorPosition(isComposerReady: boolean, ref: RefObject) { + useEffect(() => { + if (ref.current && isComposerReady) { + setCursorPositionAtTheEnd(ref.current); + } + }, [ref, isComposerReady]); +} diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts b/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts index eab855e086..0ae3d7a880 100644 --- a/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts +++ b/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts @@ -41,3 +41,14 @@ export function focusComposer( ); } } + +export function setCursorPositionAtTheEnd(element: HTMLElement) { + const range = document.createRange(); + range.selectNodeContents(element); + range.collapse(false); + const sel = document.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + + element.focus(); +}