mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
mobile: fix scroll into view on keyboard shown (#2762)
This commit is contained in:
@@ -226,7 +226,7 @@ const AppSection = ({
|
||||
{EditorOverlay ? (
|
||||
<EditorOverlay editorId={editorId || ""} editor={editor} />
|
||||
) : null}
|
||||
<ReadonlyButton editor={editor} />
|
||||
{editorId === "" ? <ReadonlyButton editor={editor} /> : null}
|
||||
</>
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -153,6 +153,7 @@ export const useEditorEvents = (
|
||||
useEffect(() => {
|
||||
const handleKeyboardDidShow: KeyboardEventListener = () => {
|
||||
editor.commands.keyboardShown(true);
|
||||
editor.postMessage(EditorEvents.keyboardShown, undefined);
|
||||
};
|
||||
const handleKeyboardDidHide: KeyboardEventListener = () => {
|
||||
editor.commands.keyboardShown(false);
|
||||
@@ -164,7 +165,7 @@ export const useEditorEvents = (
|
||||
return () => {
|
||||
subscriptions.forEach((subscription) => subscription.remove());
|
||||
};
|
||||
}, [editor.commands]);
|
||||
}, [editor.commands, editor.postMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
editor.commands.setSettings({
|
||||
|
||||
@@ -646,6 +646,7 @@ export const useEditor = (
|
||||
onContentChanged,
|
||||
editorId: editorId,
|
||||
markImageLoaded,
|
||||
overlay
|
||||
overlay,
|
||||
postMessage
|
||||
};
|
||||
};
|
||||
|
||||
@@ -49,7 +49,8 @@ export const EditorEvents: { [name: string]: string } = {
|
||||
theme: "native:theme",
|
||||
titleplaceholder: "native:titleplaceholder",
|
||||
logger: "native:logger",
|
||||
status: "native:status"
|
||||
status: "native:status",
|
||||
keyboardShown: "native:keyboardShown"
|
||||
};
|
||||
|
||||
export function randId(prefix: string) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
usePermissionHandler,
|
||||
useTiptap
|
||||
} from "@notesnook/editor";
|
||||
import { keepLastLineInView } from "@notesnook/editor/dist/extensions/keep-in-view/keep-in-view";
|
||||
import { Theme, useTheme } from "@notesnook/theme";
|
||||
import {
|
||||
forwardRef,
|
||||
@@ -44,9 +43,6 @@ import StatusBar from "./statusbar";
|
||||
import Tags from "./tags";
|
||||
import Title from "./title";
|
||||
|
||||
function isIOSBrowser() {
|
||||
return __PLATFORM__ !== "android";
|
||||
}
|
||||
const Tiptap = ({
|
||||
editorTheme,
|
||||
toolbarTheme,
|
||||
@@ -73,17 +69,6 @@ const Tiptap = ({
|
||||
onUpdate: ({ 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) => {
|
||||
global.editorController.openFilePicker(type);
|
||||
return true;
|
||||
|
||||
@@ -50,6 +50,36 @@ type Timers = {
|
||||
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 = {
|
||||
selectionChange: (editor: Editor) => void;
|
||||
titleChange: (title: string) => void;
|
||||
@@ -161,6 +191,11 @@ export function useEditorController(update: () => void): EditorController {
|
||||
break;
|
||||
case "native:status":
|
||||
break;
|
||||
case "native:keyboardShown":
|
||||
if (editor?.current) {
|
||||
scrollIntoView(editor?.current as any);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -19,12 +19,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Editor, Extension, posToDOMRect } from "@tiptap/core";
|
||||
|
||||
type KeepInViewOptions = {
|
||||
scrollIntoViewOnWindowResize: boolean;
|
||||
};
|
||||
|
||||
let onWindowResize: ((this: Window, ev: UIEvent) => void) | undefined =
|
||||
undefined;
|
||||
export const KeepInView = Extension.create({
|
||||
export const KeepInView = Extension.create<KeepInViewOptions>({
|
||||
name: "keepinview",
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
scrollIntoViewOnWindowResize: true
|
||||
};
|
||||
},
|
||||
onCreate() {
|
||||
if (!this.options.scrollIntoViewOnWindowResize) return;
|
||||
onWindowResize = () => {
|
||||
keepLastLineInView(this.editor);
|
||||
};
|
||||
|
||||
@@ -238,7 +238,9 @@ const useTiptap = (
|
||||
Codemark,
|
||||
MathInline,
|
||||
MathBlock,
|
||||
KeepInView,
|
||||
KeepInView.configure({
|
||||
scrollIntoViewOnWindowResize: !isMobile
|
||||
}),
|
||||
DateTime.configure({ dateFormat, timeFormat }),
|
||||
KeyMap,
|
||||
WebClipNode
|
||||
|
||||
Reference in New Issue
Block a user