Skip to content
File

Blob: src/client/components/editor/lib/insert-palette.ts

typescript63 lines
1import { launchEmojiPicker } from "../controllers/emoji/insert-panel";
2import { insertImageFromSlashMenu } from "../controllers/image/insert-panel";
3import { getSlashMenuItems, type SlashMenuItem } from "../controllers/slash/items";
4import { startGenerateAtRange } from "../controllers/slash/ai-insert";
5import { getAiBusyReason } from "./ai-busy";
6import { runtimeToUploadContext } from "./media-actions";
7import { canInsertPageMentionAtRange } from "./page-mention/can-insert";
8import { launchPageMentionPicker } from "./page-mention/open-picker";
9import type { EditorRuntimeSnapshot } from "../editor-runtime-context";
10import type { EditorAffordance } from "@/client/lib/affordance/editor";
11import type { PageMentionCandidate } from "@/client/components/page-mention/types";
12 
13interface CreateInsertPaletteItemsOptions {
14 getRuntime: () => EditorRuntimeSnapshot;
15 getAffordance: () => EditorAffordance;
16 getPageMentionCandidates: (excludePageId: string | undefined) => PageMentionCandidate[];
17}
18 
19function canOpenMentions(getAffordance: () => EditorAffordance, editable: boolean) {
20 return editable && getAffordance().canInsertPageMentions;
21}
22 
23export function createInsertPaletteItems({
24 getRuntime,
25 getAffordance,
26 getPageMentionCandidates,
27}: CreateInsertPaletteItemsOptions): SlashMenuItem[] {
28 return getSlashMenuItems({
29 pageMention: {
30 isAvailable: ({ editor }) =>
31 canOpenMentions(getAffordance, editor.isEditable) && canInsertPageMentionAtRange(editor),
32 openPicker: ({ editor, range }) => {
33 if (!canOpenMentions(getAffordance, editor.isEditable)) return;
34 launchPageMentionPicker(editor, {
35 range,
36 candidates: getPageMentionCandidates(getRuntime().pageId),
37 });
38 },
39 },
40 image: {
41 isAvailable: ({ editor }) => editor.isEditable && getAffordance().canInsertImages && !!getRuntime().workspaceId,
42 insertImage: ({ editor, range }) => {
43 insertImageFromSlashMenu(editor, range, runtimeToUploadContext(getRuntime()));
44 },
45 },
46 emoji: {
47 openPicker: ({ editor, range }) => {
48 launchEmojiPicker(editor, range);
49 },
50 },
51 ai: {
52 isAvailable: ({ editor }) => {
53 const runtime = getRuntime();
54 return editor.isEditable && getAffordance().canUseAiGenerate && !!runtime.workspaceId && !!runtime.pageId;
55 },
56 isBlocked: ({ editor }) => getAiBusyReason(editor.state),
57 startGenerate: ({ editor, range, intent }) => {
58 void startGenerateAtRange({ editor, range, intent, runtime: getRuntime() });
59 },
60 },
61 });
62}