refactor: Naming

This commit is contained in:
Aleksander Grygier
2026-08-12 11:02:13 +02:00
parent a6f5dc6910
commit 1042dd8aeb
16 changed files with 168 additions and 109 deletions
@@ -3,12 +3,11 @@
import {
ChatAttachmentsList,
ChatFormActions,
ChatFormContentEditable,
ChatFormFileInputInvisible,
ChatFormCurrentWorkingDirectory,
ChatFormInput,
ChatFormInputFileInputInvisible,
ChatFormMcpResourcesList,
ChatFormPickers,
ChatFormTextarea,
ChatFormWorkingDirectory,
DialogMcpResourcesBrowser
} from '$lib/components/app';
import {
@@ -121,7 +120,7 @@
let audioRecorder: AudioRecorder | undefined;
let chatFormActionsRef: ChatFormActions | undefined = $state(undefined);
let fileInputRef: ChatFormFileInputInvisible | undefined = $state(undefined);
let fileInputRef: ChatFormInputFileInputInvisible | undefined = $state(undefined);
let pickersRef: { handleKeydown: (event: KeyboardEvent) => boolean } | undefined =
$state(undefined);
let inputRef: ChatInputHandle | undefined = $state(undefined);
@@ -544,7 +543,7 @@
}
</script>
<ChatFormFileInputInvisible bind:this={fileInputRef} onFileSelect={handleFileSelect} />
<ChatFormInputFileInputInvisible bind:this={fileInputRef} onFileSelect={handleFileSelect} />
<form
class="relative grid {className}"
@@ -603,35 +602,20 @@
<div
class="flex-column relative min-h-12 items-center rounded-4xl md:rounded-3xl py-2 pb-2.25 shadow-sm transition-all focus-within:shadow-md md:py-3!"
>
{#if useContenteditable}
<ChatFormContentEditable
class="px-5 py-1.5 md:pt-0 mb-0.5"
bind:this={inputRef}
bind:value
onKeydown={handleKeydown}
onInput={() => {
pickers.handleInput();
onValueChange?.(value);
}}
onPaste={handlePaste}
{disabled}
{placeholder}
/>
{:else}
<ChatFormTextarea
class="px-5 py-1.5 md:pt-0"
bind:this={inputRef}
bind:value
onKeydown={handleKeydown}
onInput={() => {
pickers.handleInput();
onValueChange?.(value);
}}
onPaste={handlePaste}
{disabled}
{placeholder}
/>
{/if}
<ChatFormInput
class="px-5 py-1.5 md:pt-0"
bind:this={inputRef}
bind:value
onKeydown={handleKeydown}
onInput={() => {
pickers.handleInput();
onValueChange?.(value);
}}
onPaste={handlePaste}
{disabled}
{placeholder}
{useContenteditable}
/>
{#if mcpResourceStore.hasAttachments}
<ChatFormMcpResourcesList
@@ -667,7 +651,7 @@
<ContextGaugePopup />
{#if toolsStore.hasEnabledCwdTools}
<ChatFormWorkingDirectory
<ChatFormCurrentWorkingDirectory
directory={cwd}
isOpen={pickers.isWorkingDirectoryPickerOpen}
bind:query={pickers.workingDirectoryQuery}
@@ -1,6 +1,6 @@
<script lang="ts">
import ChatFormWorkingDirectoryChip from './ChatFormWorkingDirectoryChip.svelte';
import ChatFormWorkingDirectoryResultsList from './ChatFormWorkingDirectoryResultsList.svelte';
import ChatFormCurrentWorkingDirectoryChip from './ChatFormCurrentWorkingDirectoryChip.svelte';
import ChatFormCurrentWorkingDirectoryResultsList from './ChatFormCurrentWorkingDirectoryResultsList.svelte';
import { FolderOpen } from '@lucide/svelte';
import SearchInput from '$lib/components/app/forms/SearchInput.svelte';
import * as Popover from '$lib/components/ui/popover';
@@ -250,7 +250,7 @@
// user cancelled - silently ignore; other errors are logged
if (err instanceof DOMException && err.name === 'AbortError') return;
console.error('[ChatFormWorkingDirectory] showDirectoryPicker failed:', err);
console.error('[ChatFormCurrentWorkingDirectory] showDirectoryPicker failed:', err);
}
}
@@ -331,7 +331,7 @@
onclick={onOpen}
{disabled}
>
<ChatFormWorkingDirectoryChip
<ChatFormCurrentWorkingDirectoryChip
{directory}
{homeBase}
{disabled}
@@ -372,7 +372,7 @@
{#if !fileSearchEnabled}
<div class="px-2 py-1.5 text-sm text-muted-foreground">{searchUnavailableMessage}</div>
{:else if query.trim() && (search.isSearching || queryResults.length > 0 || searchError)}
<ChatFormWorkingDirectoryResultsList
<ChatFormCurrentWorkingDirectoryResultsList
results={queryResults}
hoveredIndex={nav.hoveredIndex}
isSearching={search.isSearching}
@@ -0,0 +1,80 @@
<script lang="ts">
import ChatFormInputBasic from './ChatFormInputBasic.svelte';
import ChatFormInputRich from './ChatFormInputRich.svelte';
interface Props {
class?: string;
disabled?: boolean;
onInput?: () => void;
onKeydown?: (event: KeyboardEvent) => void;
onPaste?: (event: ClipboardEvent) => void;
placeholder?: string;
value?: string;
useContenteditable?: boolean;
}
let {
class: className = '',
disabled = false,
onInput,
onKeydown,
onPaste,
placeholder = 'Ask anything...',
useContenteditable = false,
value = $bindable('')
}: Props = $props();
let basicRef: ChatFormInputBasic | undefined = $state();
let richRef: ChatFormInputRich | undefined = $state();
// The two renderers share one imperative handle (focus/caret/height), so
// the parent can drive whichever variant is mounted through this one.
export function getElement() {
return useContenteditable ? richRef?.getElement() : basicRef?.getElement();
}
export function focus() {
if (useContenteditable) richRef?.focus();
else basicRef?.focus();
}
export function resetHeight() {
if (useContenteditable) richRef?.resetHeight();
else basicRef?.resetHeight();
}
export function getCaretOffset(): number {
return useContenteditable
? (richRef?.getCaretOffset() ?? 0)
: (basicRef?.getCaretOffset() ?? 0);
}
export function setCaretOffset(offset: number) {
if (useContenteditable) richRef?.setCaretOffset(offset);
else basicRef?.setCaretOffset(offset);
}
</script>
{#if useContenteditable}
<ChatFormInputRich
bind:this={richRef}
class={className}
{disabled}
{onInput}
{onKeydown}
{onPaste}
{placeholder}
bind:value
/>
{:else}
<ChatFormInputBasic
bind:this={basicRef}
class={className}
{disabled}
{onInput}
{onKeydown}
{onPaste}
{placeholder}
bind:value
/>
{/if}
@@ -787,7 +787,7 @@
}
</script>
<div class="flex-1 {className}">
<div class="flex-1 {className} mb-0.5">
<div
bind:this={rootElement}
contenteditable={!disabled}
@@ -1,7 +1,7 @@
<script lang="ts">
import ChatFormCommandPicker from './ChatFormCommandPicker.svelte';
import ChatFormMentionPicker from './ChatFormMentionPicker.svelte';
import ChatFormPickerCommand from './ChatFormPickerCommand.svelte';
import ChatFormPickerMcpPrompts from './ChatFormPickerMcpPrompts/ChatFormPickerMcpPrompts.svelte';
import ChatFormPickerMention from './ChatFormPickerMention.svelte';
import type {
ChatFormCommand,
FileMentionEntry,
@@ -55,9 +55,9 @@
scopePath
}: Props = $props();
let commandPickerRef: ChatFormCommandPicker | undefined = $state(undefined);
let commandPickerRef: ChatFormPickerCommand | undefined = $state(undefined);
let promptPickerRef: ChatFormPickerMcpPrompts | undefined = $state(undefined);
let mentionPickerRef: ChatFormMentionPicker | undefined = $state(undefined);
let mentionPickerRef: ChatFormPickerMention | undefined = $state(undefined);
/** Delegate keyboard events to the active picker child; true if handled. */
export function handleKeydown(event: KeyboardEvent): boolean {
@@ -77,7 +77,7 @@
}
</script>
<ChatFormCommandPicker
<ChatFormPickerCommand
bind:this={commandPickerRef}
isOpen={isCommandPickerOpen ?? false}
query={commandQuery ?? ''}
@@ -96,7 +96,7 @@
{onPromptLoadError}
/>
<ChatFormMentionPicker
<ChatFormPickerMention
bind:this={mentionPickerRef}
isOpen={isMentionPickerOpen ?? false}
query={mentionQuery ?? ''}
+15 -20
View File
@@ -91,7 +91,7 @@ export { default as ChatAttachmentsListItemThumbnailImage } from './ChatAttachme
* preview without carousel, or a gallery/carousel view when multiple items exist.
* Uses ChatAttachmentPreviewSingle internally for each item's content.
*/
export { default as ChatAttachmentsPreview } from './ChatAttachments/ChatAttachmentsPreview.svelte';
export { default as ChatAttachmentsPreview } from './ChatAttachments/ChatAttachmentsPreview/ChatAttachmentsPreview.svelte';
export { default as ChatAttachmentsPreviewNavButtons } from './ChatAttachments/ChatAttachmentsPreview/ChatAttachmentsPreviewNavButtons.svelte';
export { default as ChatAttachmentsPreviewFileInfo } from './ChatAttachments/ChatAttachmentsPreview/ChatAttachmentsPreviewFileInfo.svelte';
export { default as ChatAttachmentsPreviewThumbnailStrip } from './ChatAttachments/ChatAttachmentsPreview/ChatAttachmentsPreviewThumbnailStrip.svelte';
@@ -120,8 +120,8 @@ export { default as ChatAttachmentsPreviewCurrentItem } from './ChatAttachments/
* Used by ChatScreenForm and ChatMessageEditForm for both new conversations and message editing.
*
* **Architecture:**
* - Composes ChatFormTextarea (or ChatFormContentEditable for messages with
* file mention links), ChatFormActions, and ChatFormPickerMcpPrompts
* - Composes ChatFormInput (a plain textarea, or a contenteditable for
* messages with file mention links), ChatFormActions, and ChatFormPickerMcpPrompts
* - Manages file upload state via `uploadedFiles` bindable prop
* - Integrates with ModelsSelectorDropdown for model selection in router mode
* - Communicates with parent via callbacks (onSubmit, onFilesAdd, onStop, etc.)
@@ -258,7 +258,7 @@ export { default as ChatFormContextGauge } from './ChatForm/ChatFormContextGauge
/**
* Hidden file input element for programmatic file selection.
*/
export { default as ChatFormFileInputInvisible } from './ChatForm/ChatFormFileInputInvisible.svelte';
export { default as ChatFormInputFileInputInvisible } from './ChatForm/ChatFormInput/ChatFormInputFileInputInvisible.svelte';
/**
* Displays MCP Resource attachments as a horizontal carousel.
@@ -267,18 +267,13 @@ export { default as ChatFormFileInputInvisible } from './ChatForm/ChatFormFileIn
export { default as ChatFormMcpResourcesList } from './ChatForm/ChatFormMcpResourcesList.svelte';
/**
* Auto-resizing contenteditable input that renders `[name](file://...)`
* mention links as inline chips while keeping the value as the markdown
* source string. ChatForm swaps it in once a mention link lands in the
* buffer. Shares the focus()/resetHeight()/caret handle with the textarea.
* The message editor. Renders a plain auto-resizing textarea by default,
* or a contenteditable that renders `[name](file://...)` mention links as
* inline chips (keeping the value as the markdown source string) once a
* mention link lands in the buffer. The variant is selected via the
* `useContenteditable` prop; both share one imperative handle.
*/
export { default as ChatFormContentEditable } from './ChatForm/ChatFormContentEditable.svelte';
/**
* Plain auto-resizing textarea with IME composition support. Default input
* renderer inside ChatForm until a file mention lands.
*/
export { default as ChatFormTextarea } from './ChatForm/ChatFormTextarea.svelte';
export { default as ChatFormInput } from './ChatForm/ChatFormInput/ChatFormInput.svelte';
/**
* Working directory selector for agent mode. Renders a chip below the chat
@@ -288,7 +283,7 @@ export { default as ChatFormTextarea } from './ChatForm/ChatFormTextarea.svelte'
* synthetic "Set working directory to ..." user message into chat history
* and is enforced on tool calls via the `x-tool-cwd` request header.
*/
export { default as ChatFormWorkingDirectory } from './ChatForm/ChatFormWorkingDirectory.svelte';
export { default as ChatFormCurrentWorkingDirectory } from './ChatForm/ChatFormCurrentWorkingDirectory/ChatFormCurrentWorkingDirectory.svelte';
/**
* **ChatFormPickerMcpPrompts** - MCP prompt selection interface
@@ -359,14 +354,14 @@ export { default as ChatFormPickerPopover } from './ChatForm/ChatFormPickers/Cha
* Generic scrollable list for picker popovers. Provides search input,
* scroll-into-view for keyboard navigation, loading skeletons, empty state,
* and optional footer. Uses Svelte 5 snippets for item/skeleton/footer rendering.
* Shared by ChatFormPickerMcpPrompts and ChatFormMentionPicker.
* Shared by ChatFormPickerMcpPrompts and ChatFormPickerMention.
*/
export { default as ChatFormPickerList } from './ChatForm/ChatFormPickers/ChatFormPicker/ChatFormPickerList.svelte';
/**
* Generic button wrapper for picker list items. Provides consistent styling,
* hover/selected states, and data-picker-index attribute for scroll-into-view.
* Shared by ChatFormPickerMcpPrompts and ChatFormMentionPicker.
* Shared by ChatFormPickerMcpPrompts and ChatFormPickerMention.
*/
export { default as ChatFormPickerListItem } from './ChatForm/ChatFormPickers/ChatFormPicker/ChatFormPickerListItem.svelte';
@@ -389,14 +384,14 @@ export { default as ChatFormPickerListItemSkeleton } from './ChatForm/ChatFormPi
* tool, scoped to the conversation cwd (or server home when unset).
* Selection splices a `[name](file:///<abs path>)` link into the input.
*/
export { default as ChatFormMentionPicker } from './ChatForm/ChatFormPickers/ChatFormMentionPicker.svelte';
export { default as ChatFormMentionPicker } from './ChatForm/ChatFormPickers/ChatFormPickerMention.svelte';
/**
* `/`-triggered slash-command picker. Lists the available slash commands
* (`/prompt`, `/cwd`, `/model`) filtered by the typed query; selection
* hands the command to the parent for dispatch.
*/
export { default as ChatFormCommandPicker } from './ChatForm/ChatFormPickers/ChatFormCommandPicker.svelte';
export { default as ChatFormCommandPicker } from './ChatForm/ChatFormPickers/ChatFormPickerCommand.svelte';
/**
* Hosts the chat-form pickers (slash-command, MCP prompt, file mention)
@@ -3,7 +3,7 @@
// contributes its full `[name](file://...)` link) and pasting such
// markdown re-renders the badges.
import ChatFormContentEditable from '$lib/components/app/chat/ChatForm/ChatFormContentEditable.svelte';
import ChatFormInputRich from '$lib/components/app/chat/ChatForm/ChatFormInput/ChatFormInputRich.svelte';
import { rangeToTextOffset, serializeContent, textOffsetToRange } from '$lib/utils';
import { tick } from 'svelte';
import { describe, expect, it, vi } from 'vitest';
@@ -43,9 +43,9 @@ function clipboardEvent(type: 'copy' | 'cut' | 'paste', text = '') {
return { data, event };
}
describe('ChatFormContentEditable clipboard', () => {
describe('ChatFormInputRich clipboard', () => {
it('copy exposes the markdown source of the selection', async () => {
const { container } = render(ChatFormContentEditable, { value: SOURCE });
const { container } = render(ChatFormInputRich, { value: SOURCE });
await tick();
@@ -62,7 +62,7 @@ describe('ChatFormContentEditable clipboard', () => {
});
it('cut exposes the markdown source and removes the slice', async () => {
const { container } = render(ChatFormContentEditable, { value: SOURCE });
const { container } = render(ChatFormInputRich, { value: SOURCE });
await tick();
@@ -88,7 +88,7 @@ describe('ChatFormContentEditable clipboard', () => {
});
it('paste of markdown mention links re-renders badges', async () => {
const { container } = render(ChatFormContentEditable, { value: 'hello ' });
const { container } = render(ChatFormInputRich, { value: 'hello ' });
await tick();
@@ -114,7 +114,7 @@ describe('ChatFormContentEditable clipboard', () => {
});
it('paste without mention links keeps the DOM untouched', async () => {
const { container } = render(ChatFormContentEditable, { value: 'hello ' });
const { container } = render(ChatFormInputRich, { value: 'hello ' });
await tick();
@@ -138,9 +138,9 @@ describe('ChatFormContentEditable clipboard', () => {
});
});
describe('ChatFormContentEditable code spans', () => {
describe('ChatFormInputRich code spans', () => {
it('renders inline code from the initial value', async () => {
const { container } = render(ChatFormContentEditable, { value: 'run `npm test` now' });
const { container } = render(ChatFormInputRich, { value: 'run `npm test` now' });
await tick();
@@ -153,7 +153,7 @@ describe('ChatFormContentEditable code spans', () => {
it('renders a fenced code block with a language', async () => {
const source = 'before\n```js\nconst a = 1;\n```\nafter';
const { container } = render(ChatFormContentEditable, { value: source });
const { container } = render(ChatFormInputRich, { value: source });
await tick();
@@ -166,7 +166,7 @@ describe('ChatFormContentEditable code spans', () => {
it('copy exposes the markdown source of a selection spanning code', async () => {
const source = 'run `npm test` now';
const { container } = render(ChatFormContentEditable, { value: source });
const { container } = render(ChatFormInputRich, { value: source });
await tick();
@@ -183,7 +183,7 @@ describe('ChatFormContentEditable code spans', () => {
});
it('paste of a code span renders the styled element', async () => {
const { container } = render(ChatFormContentEditable, { value: 'run ' });
const { container } = render(ChatFormInputRich, { value: 'run ' });
await tick();
@@ -210,7 +210,7 @@ describe('ChatFormContentEditable code spans', () => {
it('highlights a fenced block content and stays byte-exact', async () => {
const source = '```js\nconst a = 1;\n```';
const { container } = render(ChatFormContentEditable, { value: source });
const { container } = render(ChatFormInputRich, { value: source });
await tick();
@@ -223,7 +223,7 @@ describe('ChatFormContentEditable code spans', () => {
});
it('does not highlight inline code', async () => {
const { container } = render(ChatFormContentEditable, { value: 'run `const` now' });
const { container } = render(ChatFormInputRich, { value: 'run `const` now' });
await tick();
@@ -233,7 +233,7 @@ describe('ChatFormContentEditable code spans', () => {
});
});
describe('ChatFormContentEditable code block escape hatches', () => {
describe('ChatFormInputRich code block escape hatches', () => {
const BLOCK_SOURCE = '```js\nconst a = 1;\n```';
const BLOCK_SELECTOR = 'code[data-code-token="block"]';
@@ -273,7 +273,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
}
it('pads a trailing code block with a br hatch that stays invisible to copy', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -292,7 +292,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('escapes a trailing code block with ArrowDown and types after it', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -318,7 +318,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('escapes a leading code block with ArrowUp and types before it', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -343,7 +343,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('escapes a leading code block with ArrowLeft from its first character', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -358,7 +358,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('removes the transient leading hatch when the caret moves back into the block', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -378,7 +378,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('extends the selection out of the block with Shift+ArrowDown', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -397,7 +397,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('line-separates text typed right after the closing fence', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -419,7 +419,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('does not double the newline when Shift+Enter already added one', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -437,7 +437,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('moves a caret stuck before the inserted newline onto the new line', async () => {
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
value: BLOCK_SOURCE + '\ntext after the code block'
});
@@ -469,7 +469,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('appends the artificial trailing newline when the browser did not add one', async () => {
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
value: BLOCK_SOURCE + '\ntext after the code block'
});
@@ -501,7 +501,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('lands the caret on the new line with a single Shift+Enter after text below a block', async () => {
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
value: BLOCK_SOURCE + '\ntext after the code block'
});
@@ -534,7 +534,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('lets Backspace at the text start move into the block without a source fight', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -560,7 +560,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('lets forward Delete eat the text after a block normally', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -581,7 +581,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('renders text after a block without a phantom empty line', async () => {
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
value: BLOCK_SOURCE + '\nhello'
});
@@ -594,7 +594,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('keeps an intentional blank line after a block out of the separator', async () => {
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
value: BLOCK_SOURCE + '\n\nhello'
});
@@ -607,7 +607,7 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
it('re-highlights while typing inside a block and keeps the caret', async () => {
const { container } = render(ChatFormContentEditable, { value: BLOCK_SOURCE });
const { container } = render(ChatFormInputRich, { value: BLOCK_SOURCE });
await tick();
@@ -639,12 +639,12 @@ describe('ChatFormContentEditable code block escape hatches', () => {
});
});
describe('ChatFormContentEditable Enter in code blocks', () => {
describe('ChatFormInputRich Enter in code blocks', () => {
const BLOCK_SOURCE = '```js\nconst a = 1;\n```';
it('adds a line instead of submitting on plain Enter inside a block', async () => {
const onKeydown = vi.fn();
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
onKeydown,
value: BLOCK_SOURCE
});
@@ -679,7 +679,7 @@ describe('ChatFormContentEditable Enter in code blocks', () => {
it('adds a line after a still-open fence (no closing ``` yet)', async () => {
const onKeydown = vi.fn();
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
onKeydown,
value: '```js\nconst a = 1;'
});
@@ -707,7 +707,7 @@ describe('ChatFormContentEditable Enter in code blocks', () => {
it('forwards plain Enter to the parent when the caret is outside a block', async () => {
const onKeydown = vi.fn();
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
onKeydown,
value: BLOCK_SOURCE + '\nafter'
});
@@ -730,7 +730,7 @@ describe('ChatFormContentEditable Enter in code blocks', () => {
it('forwards plain Enter on the trailing hatch line after a block', async () => {
const onKeydown = vi.fn();
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
onKeydown,
value: BLOCK_SOURCE
});
@@ -753,7 +753,7 @@ describe('ChatFormContentEditable Enter in code blocks', () => {
it('forwards Ctrl+Enter inside a block so explicit submit survives', async () => {
const onKeydown = vi.fn();
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
onKeydown,
value: BLOCK_SOURCE
});
@@ -780,7 +780,7 @@ describe('ChatFormContentEditable Enter in code blocks', () => {
it('forwards Enter inside an inline code span', async () => {
const onKeydown = vi.fn();
const { container } = render(ChatFormContentEditable, {
const { container } = render(ChatFormInputRich, {
onKeydown,
value: 'run `npm test` now'
});
@@ -3,7 +3,7 @@
// it, the picker still opens but explains why instead of firing searches
// that would only fail with "Search failed".
import ChatFormMentionPicker from '$lib/components/app/chat/ChatForm/ChatFormPickers/ChatFormMentionPicker.svelte';
import ChatFormMentionPicker from '$lib/components/app/chat/ChatForm/ChatFormPickers/ChatFormPickerMention.svelte';
import { DISABLED_TOOL_KEYS_LOCALSTORAGE_KEY } from '$lib/constants';
import { BuiltInTool } from '$lib/enums';
import { toolsStore } from '$lib/stores/tools.svelte';
@@ -1,5 +1,5 @@
<script lang="ts">
import ChatFormContentEditable from '$lib/components/app/chat/ChatForm/ChatFormContentEditable.svelte';
import ChatFormInputRich from '$lib/components/app/chat/ChatForm/ChatFormInput/ChatFormInputRich.svelte';
import { untrack } from 'svelte';
interface Props {
@@ -9,7 +9,7 @@
let { value: initial = '' }: Props = $props();
let value = $state(untrack(() => initial));
let inputRef: ChatFormContentEditable | undefined = $state(undefined);
let inputRef: ChatFormInputRich | undefined = $state(undefined);
export function getValue() {
return value;
@@ -24,4 +24,4 @@
}
</script>
<ChatFormContentEditable bind:this={inputRef} bind:value />
<ChatFormInputRich bind:this={inputRef} bind:value />