diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 6b918293fa..7577e8d1da 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -518,6 +518,7 @@ return true; }); }; + const withSelectedText = (text: string) => embedded && selectedText?.trim() ? `${text}\n\nSelected note text for replace_note_content operations:\n${selectedText.trim()}` @@ -620,8 +621,7 @@ await setDefaults(); } - const chatInput = document.getElementById('chat-input'); - chatInput?.focus(); + messageInput?.focus({ preventScroll: true }); } else if (!embedded) { await goto('/'); } else { @@ -670,7 +670,7 @@ await setDefaults(); loading = false; await tick(); - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); }; const onSelect = async (e) => { @@ -1212,7 +1212,7 @@ if (inputElement) { messageInput?.setText(event.data.text); - inputElement.focus(); + messageInput?.focus({ preventScroll: true }); } } @@ -1389,8 +1389,7 @@ } catch (e) {} } - const chatInput = document.getElementById('chat-input'); - chatInput?.focus(); + messageInput?.focus({ preventScroll: true }); }; init(); @@ -2002,8 +2001,8 @@ $models.map((m) => m.id).includes(modelId) ? modelId : '' ); - const chatInput = document.getElementById('chat-input'); - setTimeout(() => chatInput?.focus(), 0); + await tick(); + messageInput?.focus({ preventScroll: true }); }; const loadChat = async () => { @@ -2643,8 +2642,7 @@ // focus on chat input (skip during voice call to avoid triggering mobile keyboard) if (!$showCallOverlay) { - const chatInput = document.getElementById('chat-input'); - chatInput?.focus(); + messageInput?.focus({ preventScroll: true }); } saveSessionSelectedModels(); @@ -2699,13 +2697,13 @@ const message = error?.detail ?? error?.message ?? $i18n.t('Context compaction failed'); toast.error(message, { id: toastId }); } finally { - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); } }; const handleStatusCommand = () => { messageInput?.showStatus(); - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); }; const handleModelCommand = (modelId = '') => { @@ -2720,7 +2718,7 @@ ); messageInput?.setText(''); prompt = ''; - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); return; } @@ -2729,7 +2727,7 @@ toast.error(`Model not found: ${modelId}`); messageInput?.setText(''); prompt = ''; - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); return; } @@ -2739,7 +2737,7 @@ toast.success(`Model switched to: ${model.id}`); messageInput?.setText(''); prompt = ''; - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); }; const handleForkChat = async (messageId: string | null = null) => { @@ -2783,7 +2781,7 @@ } catch (error) { toast.error(`${error}`, { id: toastId }); } finally { - document.getElementById('chat-input')?.focus(); + messageInput?.focus({ preventScroll: true }); } }; @@ -4205,7 +4203,10 @@ {/if} -
+
{ + chatInputElement?.focus(options); + }; + export const setText = async (text?: string, cb?: (text: string) => void) => { const chatInput = document.getElementById('chat-input'); @@ -371,7 +375,7 @@ chatInputElement?.setText(text); if (!$showCallOverlay) { - chatInputElement?.focus(); + focus(); } if (text !== '') { @@ -386,7 +390,7 @@ export const showStatus = async () => { showStatusPanel = true; await tick(); - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }; const formatTokenCount = (value: number) => { @@ -536,7 +540,7 @@ await tick(); if (chatInput) { - chatInput.focus(); + focus({ preventScroll: true }); chatInput.dispatchEvent(new Event('input')); const words = extractCurlyBraceWords(prompt); @@ -604,7 +608,7 @@ await tick(); await inputVariableHandler(text); await tick(); - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }; let command = ''; @@ -1220,7 +1224,7 @@ atSelectedModel = data; } - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }, insertTextHandler: insertTextAtCursor, @@ -1293,7 +1297,7 @@ atSelectedModel = data; } - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }, insertTextHandler: insertTextAtCursor, @@ -1331,7 +1335,7 @@ atSelectedModel = data; } - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }, insertTextHandler: insertTextAtCursor, @@ -1363,7 +1367,7 @@ render: getSuggestionRenderer(CommandSuggestionList, { i18n, onSelect: (e) => { - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }, insertTextHandler: insertTextAtCursor, @@ -1382,7 +1386,7 @@ render: getSuggestionRenderer(CommandSuggestionList, { i18n, onSelect: (e) => { - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }, insertTextHandler: insertTextAtCursor, @@ -1468,7 +1472,7 @@ }} onClose={async () => { await tick(); - chatInputElement?.focus(); + focus(); }} /> @@ -1544,7 +1548,7 @@ recording = false; await tick(); - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); }} onConfirm={async (data) => { const { text, filename } = data; @@ -1554,7 +1558,7 @@ await tick(); await insertTextAtCursor(`${text}`); await tick(); - document.getElementById('chat-input')?.focus(); + focus({ preventScroll: true }); if ($settings?.speechAutoSend ?? false) { dispatch('submit', prompt); @@ -1565,7 +1569,6 @@
{ - // check if selectedModels support image input dispatch('submit', prompt); }} > @@ -2424,7 +2427,7 @@ {/if} {/if} - {#if prompt === '' && files.length === 0 && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.call ?? true))} + {#if !embedded && prompt === '' && files.length === 0 && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.call ?? true))}
diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index bd608722d4..e4c469acd5 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -576,7 +576,7 @@ } }; - export const focus = () => { + export const focus = (options: FocusOptions = {}) => { if (editor && editor.view) { // Check if the editor is destroyed if (editor.isDestroyed) { @@ -584,9 +584,13 @@ } try { - editor.view.focus(); - // Scroll to the current selection - editor.view.dispatch(editor.view.state.tr.scrollIntoView()); + if (options.preventScroll && editor.view.dom instanceof HTMLElement) { + editor.view.dom.focus(options); + } else { + editor.view.focus(); + // Scroll to the current selection + editor.view.dispatch(editor.view.state.tr.scrollIntoView()); + } } catch (e) { // sometimes focusing throws an error, ignore console.warn('Error focusing editor', e);