Skip to content
File

Blob: src/client/components/editor/controllers/slash/extension.ts

typescript73 lines
1import { Extension } from "@tiptap/core";
2import Suggestion from "@tiptap/suggestion";
3import type { SuggestionProps, SuggestionKeyDownProps } from "@tiptap/suggestion";
4import { isChangeOrigin } from "@tiptap/extension-collaboration";
5import { filterItems, type ResolvedSlashMenuItem, type SlashMenuItem } from "./items";
6import { mountSlashMenu, type SlashMenuOverlayHandle } from "./overlay";
7 
8interface SlashCommandsOptions {
9 getItems: () => SlashMenuItem[];
10}
11 
12export const SlashCommands = Extension.create<SlashCommandsOptions>({
13 name: "slashCommands",
14 
15 addOptions() {
16 return {
17 getItems: () => [],
18 };
19 },
20 
21 addProseMirrorPlugins() {
22 const getItems = this.options.getItems;
23 
24 return [
25 Suggestion<ResolvedSlashMenuItem, ResolvedSlashMenuItem>({
26 editor: this.editor,
27 char: "/",
28 shouldShow: ({ transaction }) => !isChangeOrigin(transaction),
29 items: ({ query, editor }) => filterItems(getItems(), query, { editor }),
30 command: ({ editor, range, props: item }) => {
31 if (item.blockedReason) return;
32 item.command({ editor, range });
33 },
34 render: () => {
35 let handle: SlashMenuOverlayHandle | null = null;
36 
37 return {
38 onStart: (props: SuggestionProps<ResolvedSlashMenuItem>) => {
39 handle = mountSlashMenu(props.editor, {
40 items: props.items,
41 command: (item) => props.command(item),
42 clientRect: props.clientRect ?? null,
43 });
44 },
45 
46 onUpdate: (props: SuggestionProps<ResolvedSlashMenuItem>) => {
47 handle?.updateProps({
48 items: props.items,
49 command: (item) => props.command(item),
50 clientRect: props.clientRect ?? null,
51 });
52 },
53 
54 onKeyDown: (props: SuggestionKeyDownProps) => {
55 if (props.event.key === "Escape") {
56 handle?.destroy();
57 handle = null;
58 return true;
59 }
60 return handle?.onKeyDown(props) ?? false;
61 },
62 
63 onExit: () => {
64 handle?.destroy();
65 handle = null;
66 },
67 };
68 },
69 }),
70 ];
71 },
72});