104 lines
3.5 KiB
TypeScript
104 lines
3.5 KiB
TypeScript
import { store } from "@/store";
|
|
import { render } from "solid-js/web";
|
|
import tippy, { type Instance as TippyInstance } from "tippy.js";
|
|
import { MentionList } from "@/components/MentionList";
|
|
|
|
export const userSuggestion = {
|
|
items: ({ query }: { query: string }) => {
|
|
return store.tagDefinitions
|
|
.filter(tag => tag.isUser && tag.name.toLowerCase().substring(1).startsWith(query.toLowerCase()))
|
|
.map(tag => ({
|
|
id: tag.name, // Use the tag name as ID for sharing logic
|
|
label: tag.name.substring(1),
|
|
type: 'user' as const
|
|
}));
|
|
},
|
|
|
|
render: () => {
|
|
let componentDispose: (() => void) | undefined;
|
|
let popup: TippyInstance | undefined;
|
|
let container: HTMLDivElement | undefined;
|
|
let componentHandlers: { onKeyDown: (e: KeyboardEvent) => boolean } | undefined;
|
|
|
|
return {
|
|
onStart: (props: any) => {
|
|
container = document.createElement("div");
|
|
|
|
componentDispose = render(
|
|
() => <MentionList
|
|
items={props.items}
|
|
command={props.command}
|
|
ref={(h) => componentHandlers = h}
|
|
/>,
|
|
container
|
|
);
|
|
|
|
popup = tippy("body", {
|
|
getReferenceClientRect: props.clientRect,
|
|
appendTo: () => props.editor.options.element || document.body,
|
|
content: container,
|
|
showOnCreate: true,
|
|
interactive: true,
|
|
trigger: "manual",
|
|
placement: "bottom-start",
|
|
})[0];
|
|
},
|
|
|
|
onUpdate(props: any) {
|
|
if (componentDispose) componentDispose();
|
|
|
|
componentDispose = render(
|
|
() => <MentionList
|
|
items={props.items}
|
|
command={props.command}
|
|
ref={(h) => componentHandlers = h}
|
|
/>,
|
|
container!
|
|
);
|
|
|
|
if (props.clientRect) {
|
|
popup?.setProps({
|
|
getReferenceClientRect: props.clientRect,
|
|
});
|
|
}
|
|
},
|
|
|
|
onKeyDown(props: any) {
|
|
if (props.event.key === "Escape") {
|
|
popup?.hide();
|
|
return true;
|
|
}
|
|
return componentHandlers?.onKeyDown(props.event) ?? false;
|
|
},
|
|
|
|
onExit() {
|
|
if (popup && !popup.state.isDestroyed) {
|
|
popup.destroy();
|
|
}
|
|
popup = undefined;
|
|
if (componentDispose) {
|
|
componentDispose();
|
|
componentDispose = undefined;
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
export const noteSuggestion = {
|
|
char: '#',
|
|
items: ({ query }: { query: string }) => {
|
|
return store.notes
|
|
.filter(note => !(note.tags || []).some(t => t.startsWith("child-of-")))
|
|
.filter(note => note.title.toLowerCase().includes(query.toLowerCase()))
|
|
.map(note => ({
|
|
id: note.id,
|
|
label: note.title,
|
|
sublabel: note.content?.substring(0, 50).replace(/<[^>]*>?/gm, ''),
|
|
type: 'note' as const
|
|
}));
|
|
},
|
|
|
|
render: userSuggestion.render, // Share the same renderer
|
|
};
|