Files
docmost/apps/client/src/features/editor/hooks/use-editor-scroll.ts
T
Philip Okugbe 89b94e5d19 feat: refactor link menu (#2025)
* link markview - WIP

* WIP

* feat: refactor links

* cleanup
2026-03-15 17:08:59 +00:00

59 lines
1.5 KiB
TypeScript

import { Editor } from "@tiptap/react";
import { useCallback, useEffect, useState } from "react";
function waitForState(checkFn: () => boolean): Promise<void> {
return new Promise((resolve) => {
const interval = setInterval(() => {
if (checkFn()) {
clearInterval(interval);
resolve();
}
}, 800);
});
}
export const useEditorScroll = ({
canScroll,
initialScrollTo,
}: {
canScroll: () => boolean;
initialScrollTo?: string;
}) => {
const [scrollTo, setScrollTo] = useState<string>(initialScrollTo || "");
useEffect(() => {
if (!initialScrollTo) {
setScrollTo(window.location.hash ? window.location.hash.slice(1) : "");
}
}, [initialScrollTo]);
const handleScrollTo = useCallback(async (editor: Editor, _scrollTo: string | null = null, tryCount: number = 0) => {
await waitForState(() => canScroll());
return new Promise((resolve) => {
const MAX_TRY_COUNT = 10;
if (tryCount >= MAX_TRY_COUNT) {
resolve(false);
return;
}
const targetId = _scrollTo || scrollTo;
if (!targetId) {
resolve(false);
return;
}
const dom = editor.view.dom.querySelector(`[id="${targetId}"], [data-id="${targetId}"]`);
if (dom) {
dom.scrollIntoView({ behavior: 'smooth', block: 'start' });
resolve(true);
} else {
setTimeout(async () => {
resolve(await handleScrollTo(editor, targetId, tryCount + 1));
}, 200);
}
});
}, [scrollTo, canScroll]);
return { scrollTo, handleScrollTo };
};