mobile: fix scroll into view on keyboard shown (#2762)

This commit is contained in:
Ammar Ahmed
2023-06-19 19:04:53 +05:00
committed by GitHub
parent f0a4a61e1d
commit 6c9c99681e
8 changed files with 56 additions and 22 deletions

View File

@@ -226,7 +226,7 @@ const AppSection = ({
{EditorOverlay ? ( {EditorOverlay ? (
<EditorOverlay editorId={editorId || ""} editor={editor} /> <EditorOverlay editorId={editorId || ""} editor={editor} />
) : null} ) : null}
<ReadonlyButton editor={editor} /> {editorId === "" ? <ReadonlyButton editor={editor} /> : null}
</> </>
) : null; ) : null;
}; };

View File

@@ -153,6 +153,7 @@ export const useEditorEvents = (
useEffect(() => { useEffect(() => {
const handleKeyboardDidShow: KeyboardEventListener = () => { const handleKeyboardDidShow: KeyboardEventListener = () => {
editor.commands.keyboardShown(true); editor.commands.keyboardShown(true);
editor.postMessage(EditorEvents.keyboardShown, undefined);
}; };
const handleKeyboardDidHide: KeyboardEventListener = () => { const handleKeyboardDidHide: KeyboardEventListener = () => {
editor.commands.keyboardShown(false); editor.commands.keyboardShown(false);
@@ -164,7 +165,7 @@ export const useEditorEvents = (
return () => { return () => {
subscriptions.forEach((subscription) => subscription.remove()); subscriptions.forEach((subscription) => subscription.remove());
}; };
}, [editor.commands]); }, [editor.commands, editor.postMessage]);
useEffect(() => { useEffect(() => {
editor.commands.setSettings({ editor.commands.setSettings({

View File

@@ -646,6 +646,7 @@ export const useEditor = (
onContentChanged, onContentChanged,
editorId: editorId, editorId: editorId,
markImageLoaded, markImageLoaded,
overlay overlay,
postMessage
}; };
}; };

View File

@@ -49,7 +49,8 @@ export const EditorEvents: { [name: string]: string } = {
theme: "native:theme", theme: "native:theme",
titleplaceholder: "native:titleplaceholder", titleplaceholder: "native:titleplaceholder",
logger: "native:logger", logger: "native:logger",
status: "native:status" status: "native:status",
keyboardShown: "native:keyboardShown"
}; };
export function randId(prefix: string) { export function randId(prefix: string) {

View File

@@ -25,7 +25,6 @@ import {
usePermissionHandler, usePermissionHandler,
useTiptap useTiptap
} from "@notesnook/editor"; } from "@notesnook/editor";
import { keepLastLineInView } from "@notesnook/editor/dist/extensions/keep-in-view/keep-in-view";
import { Theme, useTheme } from "@notesnook/theme"; import { Theme, useTheme } from "@notesnook/theme";
import { import {
forwardRef, forwardRef,
@@ -44,9 +43,6 @@ import StatusBar from "./statusbar";
import Tags from "./tags"; import Tags from "./tags";
import Title from "./title"; import Title from "./title";
function isIOSBrowser() {
return __PLATFORM__ !== "android";
}
const Tiptap = ({ const Tiptap = ({
editorTheme, editorTheme,
toolbarTheme, toolbarTheme,
@@ -73,17 +69,6 @@ const Tiptap = ({
onUpdate: ({ editor }) => { onUpdate: ({ editor }) => {
global.editorController.contentChange(editor as Editor); global.editorController.contentChange(editor as Editor);
}, },
onSelectionUpdate: (props) => {
if (props.transaction.docChanged) {
if (isIOSBrowser()) {
setTimeout(() => {
keepLastLineInView(props.editor, 80, 1);
}, 1);
} else {
props.transaction.scrollIntoView();
}
}
},
onOpenAttachmentPicker: (editor, type) => { onOpenAttachmentPicker: (editor, type) => {
global.editorController.openFilePicker(type); global.editorController.openFilePicker(type);
return true; return true;

View File

@@ -50,6 +50,36 @@ type Timers = {
wordCounter: NodeJS.Timeout | null; wordCounter: NodeJS.Timeout | null;
}; };
function isInViewport(element: any) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <=
(window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
function scrollIntoView(editor: Editor) {
setTimeout(() => {
const node = editor?.state.selection.$from;
const dom = node ? editor?.view?.domAtPos(node.pos) : null;
let domNode = dom?.node;
if (domNode) {
if (domNode.nodeType === Node.TEXT_NODE && domNode.parentNode) {
domNode = domNode.parentNode;
}
if (isInViewport(domNode)) return;
(domNode as HTMLElement).scrollIntoView({
behavior: "smooth",
block: "end"
});
}
}, 100);
}
export type EditorController = { export type EditorController = {
selectionChange: (editor: Editor) => void; selectionChange: (editor: Editor) => void;
titleChange: (title: string) => void; titleChange: (title: string) => void;
@@ -161,6 +191,11 @@ export function useEditorController(update: () => void): EditorController {
break; break;
case "native:status": case "native:status":
break; break;
case "native:keyboardShown":
if (editor?.current) {
scrollIntoView(editor?.current as any);
}
break;
default: default:
break; break;
} }

View File

@@ -19,12 +19,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Editor, Extension, posToDOMRect } from "@tiptap/core"; import { Editor, Extension, posToDOMRect } from "@tiptap/core";
type KeepInViewOptions = {
scrollIntoViewOnWindowResize: boolean;
};
let onWindowResize: ((this: Window, ev: UIEvent) => void) | undefined = let onWindowResize: ((this: Window, ev: UIEvent) => void) | undefined =
undefined; undefined;
export const KeepInView = Extension.create({ export const KeepInView = Extension.create<KeepInViewOptions>({
name: "keepinview", name: "keepinview",
addOptions() {
return {
scrollIntoViewOnWindowResize: true
};
},
onCreate() { onCreate() {
if (!this.options.scrollIntoViewOnWindowResize) return;
onWindowResize = () => { onWindowResize = () => {
keepLastLineInView(this.editor); keepLastLineInView(this.editor);
}; };

View File

@@ -238,7 +238,9 @@ const useTiptap = (
Codemark, Codemark,
MathInline, MathInline,
MathBlock, MathBlock,
KeepInView, KeepInView.configure({
scrollIntoViewOnWindowResize: !isMobile
}),
DateTime.configure({ dateFormat, timeFormat }), DateTime.configure({ dateFormat, timeFormat }),
KeyMap, KeyMap,
WebClipNode WebClipNode