diff --git a/apps/client/src/widgets/collections/legacy/ListView.tsx b/apps/client/src/widgets/collections/legacy/ListView.tsx index 62f6505fd..c25f4ac55 100644 --- a/apps/client/src/widgets/collections/legacy/ListView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListView.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import FNote from "../../../entities/fnote"; import Icon from "../../react/Icon"; import { ViewModeProps } from "../interface"; -import { useNoteLabelBoolean, useNoteProperty } from "../../react/hooks"; +import { useNoteLabelBoolean, useImperativeSearchHighlighlighting } from "../../react/hooks"; import NoteLink from "../../react/NoteLink"; import "./ListOrGridView.css"; import content_renderer from "../../../services/content_renderer"; @@ -75,8 +75,8 @@ function ListNoteCard({ note, parentNote, expand, highlightedTokens }: { note: F {isExpanded && <> - - + + } @@ -104,7 +104,7 @@ function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, pa {noteTitle} - + ) } @@ -120,26 +120,29 @@ function NoteAttributes({ note }: { note: FNote }) { return } -function NoteContent({ note, trim }: { note: FNote, trim?: boolean }) { +function NoteContent({ note, trim, highlightedTokens }: { note: FNote, trim?: boolean, highlightedTokens }) { const contentRef = useRef(null); + const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); useEffect(() => { content_renderer.getRenderedContent(note, { trim }) .then(({ $renderedContent, type }) => { - contentRef.current?.replaceChildren(...$renderedContent); - contentRef.current?.classList.add(`type-${type}`); + if (!contentRef.current) return; + contentRef.current.replaceChildren(...$renderedContent); + contentRef.current.classList.add(`type-${type}`); + highlightSearch(contentRef.current); }) .catch(e => { console.warn(`Caught error while rendering note '${note.noteId}' of type '${note.type}'`); console.error(e); contentRef.current?.replaceChildren(t("collections.rendering_error")); }) - }, [ note ]); + }, [ note, highlightedTokens ]); return
; } -function NoteChildren({ note, parentNote }: { note: FNote, parentNote: FNote }) { +function NoteChildren({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) { const imageLinks = note.getRelations("imageLink"); const [ childNotes, setChildNotes ] = useState(); @@ -150,7 +153,7 @@ function NoteChildren({ note, parentNote }: { note: FNote, parentNote: FNote }) }); }, [ note ]); - return childNotes?.map(childNote => ) + return childNotes?.map(childNote => ) } /** diff --git a/apps/client/src/widgets/react/NoteLink.tsx b/apps/client/src/widgets/react/NoteLink.tsx index 4d7925bf7..2a9ec199d 100644 --- a/apps/client/src/widgets/react/NoteLink.tsx +++ b/apps/client/src/widgets/react/NoteLink.tsx @@ -1,7 +1,6 @@ import { useEffect, useRef, useState } from "preact/hooks"; import link from "../../services/link"; -import RawHtml from "./RawHtml"; -import { useSearchHighlighlighting } from "./hooks"; +import { useImperativeSearchHighlighlighting } from "./hooks"; interface NoteLinkOpts { className?: string; @@ -16,15 +15,21 @@ interface NoteLinkOpts { export default function NoteLink({ className, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens }: NoteLinkOpts) { const stringifiedNotePath = Array.isArray(notePath) ? notePath.join("/") : notePath; + const ref = useRef(null); const [ jqueryEl, setJqueryEl ] = useState>(); - const containerRef = useRef(null); - useSearchHighlighlighting(containerRef, highlightedTokens); + const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); useEffect(() => { link.createLink(stringifiedNotePath, { showNotePath, showNoteIcon }) .then(setJqueryEl); }, [ stringifiedNotePath, showNotePath ]); + useEffect(() => { + if (!ref.current || !jqueryEl) return; + ref.current.replaceChildren(jqueryEl[0]); + highlightSearch(ref.current); + }, [ jqueryEl ]); + if (style) { jqueryEl?.css(style); } @@ -42,6 +47,6 @@ export default function NoteLink({ className, notePath, showNotePath, showNoteIc $linkEl?.addClass(className); } - return + return } diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index fa6c901bc..b4148197d 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -550,7 +550,7 @@ export function useSyncedRef(externalRef?: RefObject, initialValue: T | nu return ref; } -export function useSearchHighlighlighting(ref: RefObject, highlightedTokens: string[] | null | undefined) { +export function useImperativeSearchHighlighlighting(highlightedTokens: string[] | null | undefined) { const mark = useRef(); const highlightRegex = useMemo(() => { if (!highlightedTokens?.length) return null; @@ -558,18 +558,17 @@ export function useSearchHighlighlighting(ref: RefObject, highlight return new RegExp(regex, "gi") }, [ highlightedTokens ]); - useEffect(() => { - if (!ref.current || !highlightRegex) return; + return (el: HTMLElement) => { + if (!el || !highlightRegex) return; if (!mark.current) { - mark.current = new Mark(ref.current); + mark.current = new Mark(el); } + mark.current.unmark(); mark.current.markRegExp(highlightRegex, { element: "span", className: "ck-find-result" }); - - return () => mark.current?.unmark(); - }); + }; }