mirror of
https://github.com/docmost/docmost.git
synced 2026-09-11 07:56:54 +08:00
fix: clean up jump search state on close
This commit is contained in:
+2
-2
@@ -181,10 +181,10 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(pageFindState.isOpen){
|
if (pageFindState.isOpen) {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
}
|
}
|
||||||
}, [location]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
|
|||||||
+51
-15
@@ -1,10 +1,15 @@
|
|||||||
import { ActionIcon, Dialog, Flex, Text, Tooltip } from "@mantine/core";
|
import { ActionIcon, Dialog, Flex, Text, Tooltip } from "@mantine/core";
|
||||||
import { IconArrowNarrowDown, IconArrowNarrowUp, IconX } from "@tabler/icons-react";
|
import {
|
||||||
import { useEditor } from "@tiptap/react";
|
IconArrowNarrowDown,
|
||||||
|
IconArrowNarrowUp,
|
||||||
|
IconX,
|
||||||
|
} from "@tabler/icons-react";
|
||||||
|
import { useEditor } from "@tiptap/react";
|
||||||
import { isEditorReady } from "@docmost/editor-ext";
|
import { isEditorReady } from "@docmost/editor-ext";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import classes from "./search-replace.module.css";
|
import classes from "./search-replace.module.css";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
interface SearchNavigationDialogProps {
|
interface SearchNavigationDialogProps {
|
||||||
editor: ReturnType<typeof useEditor>;
|
editor: ReturnType<typeof useEditor>;
|
||||||
@@ -18,8 +23,11 @@ interface SearchNavigationEvent extends CustomEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SearchNavigationDialog({ editor }: SearchNavigationDialogProps) {
|
function SearchNavigationDialog({ editor }: SearchNavigationDialogProps) {
|
||||||
const {t} = useTranslation()
|
const { t } = useTranslation();
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const openRef = useRef(false);
|
||||||
const [resultState, setResultState] = useState({
|
const [resultState, setResultState] = useState({
|
||||||
resultIndex: 0,
|
resultIndex: 0,
|
||||||
resultsLength: 0,
|
resultsLength: 0,
|
||||||
@@ -56,6 +64,28 @@ function SearchNavigationDialog({ editor }: SearchNavigationDialogProps) {
|
|||||||
goToSelection();
|
goToSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const close = useCallback(() => {
|
||||||
|
if (!openRef.current) return;
|
||||||
|
|
||||||
|
openRef.current = false;
|
||||||
|
setOpen(false);
|
||||||
|
if (isEditorReady(editor)) {
|
||||||
|
editor.commands.setSearchTerms([""]);
|
||||||
|
}
|
||||||
|
const nextParams = new URLSearchParams(location.search);
|
||||||
|
nextParams.delete("q");
|
||||||
|
nextParams.delete("m");
|
||||||
|
const nextSearch = nextParams.toString();
|
||||||
|
navigate(
|
||||||
|
{
|
||||||
|
pathname: location.pathname,
|
||||||
|
search: nextSearch ? `?${nextSearch}` : "",
|
||||||
|
hash: location.hash,
|
||||||
|
},
|
||||||
|
{ replace: true },
|
||||||
|
);
|
||||||
|
}, [editor, location.hash, location.pathname, location.search, navigate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleOpen = (event: Event) => {
|
const handleOpen = (event: Event) => {
|
||||||
const { searchTerms: terms, wholeWord = true } = (
|
const { searchTerms: terms, wholeWord = true } = (
|
||||||
@@ -64,12 +94,19 @@ function SearchNavigationDialog({ editor }: SearchNavigationDialogProps) {
|
|||||||
|
|
||||||
if (!terms?.length || !isEditorReady(editor)) return;
|
if (!terms?.length || !isEditorReady(editor)) return;
|
||||||
|
|
||||||
setOpen(true);
|
openRef.current = false;
|
||||||
editor.commands.setSearchTerms(terms);
|
editor.commands.setSearchTerms(terms);
|
||||||
editor.commands.setWholeWord(wholeWord);
|
editor.commands.setWholeWord(wholeWord);
|
||||||
editor.commands.resetIndex();
|
editor.commands.resetIndex();
|
||||||
|
|
||||||
const { results, resultIndex } = editor.storage.searchAndReplace;
|
const { results, resultIndex } = editor.storage.searchAndReplace;
|
||||||
|
openRef.current = true;
|
||||||
|
if (results.length === 0) {
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen(true);
|
||||||
setResultState({
|
setResultState({
|
||||||
resultIndex,
|
resultIndex,
|
||||||
resultsLength: results.length,
|
resultsLength: results.length,
|
||||||
@@ -79,25 +116,29 @@ function SearchNavigationDialog({ editor }: SearchNavigationDialogProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setOpen(false);
|
if (openRef.current) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("openSearchNavigationDialog", handleOpen);
|
document.addEventListener("openSearchNavigationDialog", handleOpen);
|
||||||
document.addEventListener("openFindDialogFromEditor", handleClose);
|
document.addEventListener("openFindDialogFromEditor", handleClose);
|
||||||
|
document.addEventListener("closeFindDialogFromEditor", handleClose);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener("openSearchNavigationDialog", handleOpen);
|
document.removeEventListener("openSearchNavigationDialog", handleOpen);
|
||||||
document.removeEventListener("openFindDialogFromEditor", handleClose);
|
document.removeEventListener("openFindDialogFromEditor", handleClose);
|
||||||
|
document.removeEventListener("closeFindDialogFromEditor", handleClose);
|
||||||
};
|
};
|
||||||
}, [editor]);
|
}, [close, editor]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleTransaction = () => {
|
const handleTransaction = () => {
|
||||||
if (!open || editor.isDestroyed) return;
|
if (!openRef.current || editor.isDestroyed) return;
|
||||||
|
|
||||||
const { results } = editor.storage.searchAndReplace;
|
const { results } = editor.storage.searchAndReplace;
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
setOpen(false);
|
close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,12 +146,7 @@ function SearchNavigationDialog({ editor }: SearchNavigationDialogProps) {
|
|||||||
return () => {
|
return () => {
|
||||||
editor.off("transaction", handleTransaction);
|
editor.off("transaction", handleTransaction);
|
||||||
};
|
};
|
||||||
}, [editor, open]);
|
}, [close, editor]);
|
||||||
|
|
||||||
const close = () => {
|
|
||||||
editor.commands.setSearchTerms([""]);
|
|
||||||
setOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import type { useEditor } from "@tiptap/react";
|
||||||
|
|
||||||
|
interface UseSearchNavigationParamsProps {
|
||||||
|
editor: ReturnType<typeof useEditor>;
|
||||||
|
isSynced: boolean;
|
||||||
|
pageId: string;
|
||||||
|
searchParams: URLSearchParams;
|
||||||
|
showStatic: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSearchNavigationParams({
|
||||||
|
editor,
|
||||||
|
isSynced,
|
||||||
|
pageId,
|
||||||
|
searchParams,
|
||||||
|
showStatic,
|
||||||
|
}: UseSearchNavigationParamsProps) {
|
||||||
|
const appliedSearchKeyRef = useRef<string | null>(null);
|
||||||
|
const searchKey = `${pageId}:${searchParams.toString()}`;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const searchQueries = searchParams.getAll("q");
|
||||||
|
if (!searchQueries.length) {
|
||||||
|
appliedSearchKeyRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!editor ||
|
||||||
|
editor.isDestroyed ||
|
||||||
|
!editor.view.dom.isConnected ||
|
||||||
|
appliedSearchKeyRef.current === searchKey
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = searchParams.get("m");
|
||||||
|
appliedSearchKeyRef.current = searchKey;
|
||||||
|
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent("openSearchNavigationDialog", {
|
||||||
|
detail: { searchTerms: searchQueries, wholeWord: match === "whole" },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [editor, isSynced, searchKey, searchParams, showStatic]);
|
||||||
|
}
|
||||||
@@ -62,6 +62,7 @@ import DrawioMenu from "./components/drawio/drawio-menu";
|
|||||||
import { useCollabToken } from "@/features/auth/queries/auth-query.tsx";
|
import { useCollabToken } from "@/features/auth/queries/auth-query.tsx";
|
||||||
import SearchAndReplaceDialog from "@/features/editor/components/search-and-replace/search-and-replace-dialog.tsx";
|
import SearchAndReplaceDialog from "@/features/editor/components/search-and-replace/search-and-replace-dialog.tsx";
|
||||||
import SearchNavigationDialog from "@/features/editor/components/search-and-replace/search-navigation-dialog.tsx";
|
import SearchNavigationDialog from "@/features/editor/components/search-and-replace/search-navigation-dialog.tsx";
|
||||||
|
import { useSearchNavigationParams } from "@/features/editor/components/search-and-replace/use-search-navigation-params.ts";
|
||||||
import { useDebouncedCallback, useDocumentVisibility } from "@mantine/hooks";
|
import { useDebouncedCallback, useDocumentVisibility } from "@mantine/hooks";
|
||||||
import { useIdle } from "@/hooks/use-idle.ts";
|
import { useIdle } from "@/hooks/use-idle.ts";
|
||||||
import { queryClient } from "@/main.tsx";
|
import { queryClient } from "@/main.tsx";
|
||||||
@@ -417,31 +418,13 @@ function CollabPageEditor({
|
|||||||
const hasConnectedOnceRef = useRef(false);
|
const hasConnectedOnceRef = useRef(false);
|
||||||
const [showStatic, setShowStatic] = useState(true);
|
const [showStatic, setShowStatic] = useState(true);
|
||||||
|
|
||||||
const appliedSearchKeyRef = useRef<string | null>(null);
|
useSearchNavigationParams({
|
||||||
const searchKey = `${pageId}:${searchParams.toString()}`;
|
editor,
|
||||||
|
isSynced,
|
||||||
useEffect(() => {
|
pageId,
|
||||||
if (
|
searchParams,
|
||||||
!editor ||
|
showStatic,
|
||||||
editor.isDestroyed ||
|
});
|
||||||
!editor.view.dom.isConnected ||
|
|
||||||
appliedSearchKeyRef.current === searchKey
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchQueries = searchParams.getAll("q");
|
|
||||||
const match = searchParams.get("m");
|
|
||||||
if (!searchQueries.length) return;
|
|
||||||
|
|
||||||
appliedSearchKeyRef.current = searchKey;
|
|
||||||
|
|
||||||
document.dispatchEvent(
|
|
||||||
new CustomEvent("openSearchNavigationDialog", {
|
|
||||||
detail: { searchTerms: searchQueries, wholeWord: match === "whole" },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}, [editor, isSynced, showStatic, searchKey, searchParams]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
|
|||||||
+1
-1
Submodule apps/server/src/ee updated: 13ca295ed9...5e7120dcc8
Reference in New Issue
Block a user