I am trying to use tiptap mention extension but with a list of suggestions from infinitequery but I just couldn't do it.
Is it even possible? Please share any ideas you might have
I tried next to everything. Matter of fact, the code I will paste is the code of a desperate man and I just put here for you to have some references so if you don't understand it, it's okay because me too (just too many things attempted).
Anyway after many attempts I realized that the issue is that no matter what I do, in the items
functions of suggestions
(in const editor
) I can't update the filter of the infinitequery so it always ends up empty/undefined.
"use client";
import tippy, { Instance, Props } from "tippy.js";
import { useEditor, EditorContent, ReactRenderer } from "@tiptap/react";
import Document from "@tiptap/extension-document";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";
import Mention from "@tiptap/extension-mention";
import { MentionList } from "./MentionList";
import { Editor } from "@tiptap/core"; // To type the `editor` instance
import { useInfiniteQuery } from "@tanstack/react-query";
import kyInstance from "@/lib/ky";
import { UserData, UsersPage } from "@/lib/type";
import { useCallback, useEffect, useState } from "react";
interface MentionListProps {
items: UserData[];
command: (item: { user: UserData }) => void;
}
export default function MyEditor() {
const [mentionQuery, setMentionQuery] = useState("");
const {
data,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
status,
} = useInfiniteQuery({
queryKey: ["users", mentionQuery],
queryFn: ({ pageParam }) => {
const searchParams: Record<string, string> = {};
if (pageParam) {
searchParams.cursor = pageParam;
}
if (!!mentionQuery) {
searchParams.filter = mentionQuery;
}
return kyInstance.get("/api/users", { searchParams }).json<UsersPage>();
},
initialPageParam: null as string | null,
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
const Myitems = ({ query }: { query: string }) => {
const {
data,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
status,
} = useInfiniteQuery({
queryKey: ["users", query],
queryFn: ({ pageParam }) => {
const searchParams: Record<string, string> = {};
if (pageParam) {
searchParams.cursor = pageParam;
}
if (!!mentionQuery) {
searchParams.filter = query;
}
return kyInstance.get("/api/users", { searchParams }).json<UsersPage>();
},
initialPageParam: null as string | null,
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
const allUsers = data ? data.pages.flatMap((page) => page.users) : [];
console.log("users", allUsers);
return allUsers;
};
// const getMentionSuggestions = useCallback(async ({ query }: { query: string }) => {
// const allUsers = data ? data.pages.flatMap((page) => page.users) : [];
// setMentionQuery(query);
// // Trigger a refetch when the query changes
// await fetchNextPage();
// console.log("users", allUsers)
// return allUsers;
// }, [data,fetchNextPage]);
const editor: Editor | null = useEditor({
extensions: [
Document,
Paragraph,
Text,
Mention.configure({
HTMLAttributes: {
class: "mention",
},
suggestion: {
items: async ({ query }: { query: string }) => {
setMentionQuery(query);
const users = data?.pages.flatMap((page) => page.users);
setTimeout(() => {
const users = data?.pages.flatMap((page) => page.users);
console.log("users", users);
return users || [];
}, 5000);
return users || [];
},
render: () => {
let reactRenderer: ReactRenderer<MentionListProps>;
let popup: Instance<Props>;
return {
onStart: (props) => {
reactRenderer = new ReactRenderer(MentionList, {
props,
editor: props.editor,
});
popup = tippy(document.body, {
getReferenceClientRect: () => {
if (props.clientRect) {
return props.clientRect() as DOMRect;
}
// Fallback to an empty DOMRect if `props.clientRect` is null
return new DOMRect();
},
appendTo: () => document.body,
content: reactRenderer.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
onUpdate(props) {
reactRenderer.updateProps(props);
popup.setProps({
getReferenceClientRect: () => {
if (props.clientRect) {
return props.clientRect() as DOMRect;
}
// Return a default client rect or handle as needed
return new DOMRect(); // Provides a non-null fallback
},
});
},
// onKeyDown(props) {
// return reactRenderer.ref?.onKeyDown(props);
// },
onExit() {
popup.destroy();
reactRenderer.destroy();
},
};
},
},
}),
],
content: `
<p>
What do you all think about the new <span data-mention="Winona Ryder"></span> movie?
</p>
`,
});
return (
<div>
<EditorContent editor={editor} />
</div>
);
}