2 import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
3 import { Plus, File, MessageSquare, Zap, FolderOpen } from '@lucide/svelte';
4 import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
5 import * as Tooltip from '$lib/components/ui/tooltip';
6 import { buttonVariants } from '$lib/components/ui/button';
7 import { cn } from '$lib/components/ui/utils';
10 ATTACHMENT_TOOLTIP_TEXT,
11 TOOLTIP_DELAY_DURATION
12 } from '$lib/constants';
14 ChatFormActionAddToolsSubmenu,
15 ChatFormActionAddMcpServersSubmenu,
16 ChatFormActionAddReasoningSubmenu
17 } from '$lib/components/app';
18 import { useAttachmentMenu } from '$lib/hooks/use-attachment-menu.svelte';
23 hasAudioModality?: boolean;
24 hasVideoModality?: boolean;
25 hasVisionModality?: boolean;
26 hasMcpPromptsSupport?: boolean;
27 hasMcpResourcesSupport?: boolean;
28 onFileUpload?: () => void;
29 onSystemPromptClick?: () => void;
30 onMcpPromptClick?: () => void;
31 onMcpSettingsClick?: () => void;
32 onMcpResourcesClick?: () => void;
36 class: className = '',
38 hasAudioModality = false,
39 hasVideoModality = false,
40 hasVisionModality = false,
41 hasMcpPromptsSupport = false,
42 hasMcpResourcesSupport = false,
50 let dropdownOpen = $state(false);
51 // The system message action moves focus to the message editor, so the menu
52 // must not restore focus to the trigger on close
53 let suppressCloseAutoFocus = false;
55 function handleMcpSettingsClick() {
57 onMcpSettingsClick?.();
60 const attachmentMenu = useAttachmentMenu(
66 hasMcpResourcesSupport
68 () => ({ onFileUpload, onSystemPromptClick, onMcpPromptClick, onMcpResourcesClick }),
75 <div class="flex items-center gap-1 {className}">
76 <DropdownMenu.Root bind:open={dropdownOpen}>
77 <!-- ignoreNonKeyboardFocus prevents the tooltip from flashing when the
78 menu closes and focus returns to the trigger -->
79 <Tooltip.Root ignoreNonKeyboardFocus>
81 {#snippet child({ props })}
85 buttonVariants({ variant: 'secondary' }),
86 'file-upload-button h-8 w-8 cursor-pointer rounded-full p-0'
90 <span class="sr-only">{ATTACHMENT_TOOLTIP_TEXT}</span>
92 <Plus class={ICON_CLASS_DEFAULT} />
93 </DropdownMenu.Trigger>
98 <p>{ATTACHMENT_TOOLTIP_TEXT}</p>
102 <DropdownMenu.Content
105 onCloseAutoFocus={(e) => {
106 if (suppressCloseAutoFocus) {
107 suppressCloseAutoFocus = false;
112 <ChatFormActionAddReasoningSubmenu />
114 <DropdownMenu.Separator />
117 <DropdownMenu.SubTrigger class="flex cursor-pointer items-center gap-2">
118 <File class={ICON_CLASS_DEFAULT} />
120 <span>Add files</span>
121 </DropdownMenu.SubTrigger>
123 <DropdownMenu.SubContent class="w-48">
124 {#each ATTACHMENT_FILE_ITEMS as item (item.id)}
125 {@const enabled = attachmentMenu.isItemEnabled(item.enabledWhen)}
128 class="{item.class ?? ''} flex cursor-pointer items-center gap-2"
129 onclick={() => attachmentMenu.callbacks[item.action]()}
131 <item.icon class={ICON_CLASS_DEFAULT} />
133 <span>{item.label}</span>
135 {:else if item.disabledTooltip}
136 <Tooltip.Root delayDuration={TOOLTIP_DELAY_DURATION}>
137 <Tooltip.Trigger tabindex={-1}>
138 {#snippet child({ props })}
139 <div {...props} class="cursor-default">
141 class="{item.class ?? ''} flex items-center gap-2"
144 <item.icon class={ICON_CLASS_DEFAULT} />
146 <span>{item.label}</span>
152 <Tooltip.Content side="right">
153 <p>{item.disabledTooltip}</p>
158 </DropdownMenu.SubContent>
162 class="flex cursor-pointer items-center gap-2"
164 suppressCloseAutoFocus = true;
165 onSystemPromptClick?.();
168 <MessageSquare class={ICON_CLASS_DEFAULT} />
170 <span>System Message</span>
173 <ChatFormActionAddToolsSubmenu />
175 <ChatFormActionAddMcpServersSubmenu onMcpSettingsClick={handleMcpSettingsClick} />
177 {#if hasMcpPromptsSupport}
178 <DropdownMenu.Separator />
181 class="flex cursor-pointer items-center gap-2"
182 onclick={onMcpPromptClick}
184 <Zap class={ICON_CLASS_DEFAULT} />
186 <span>MCP Prompt</span>
190 {#if hasMcpResourcesSupport}
192 class="flex cursor-pointer items-center gap-2"
193 onclick={onMcpResourcesClick}
195 <FolderOpen class={ICON_CLASS_DEFAULT} />
197 <span>MCP Resources</span>
200 </DropdownMenu.Content>