fix(rename): imperatively focus + select rename inputs

Svelte's native autofocus attribute is unreliable for inputs rendered
via conditional blocks (prior smoke-test fixed this for the new-list
input). Apply the same bind:this + $effect pattern to the list-rename
input (TasksScreen) and the workspace-rename input (SettingsScreen),
and select() the existing text so typing replaces the old name
cleanly.
This commit is contained in:
Claude 2026-04-17 16:26:29 +00:00
parent 6283f9ab2c
commit 391c42aa18
No known key found for this signature in database
2 changed files with 21 additions and 2 deletions

View file

@ -19,9 +19,19 @@
let renaming = $state(false); let renaming = $state(false);
let renameValue = $state(""); let renameValue = $state("");
let renameInput = $state<HTMLInputElement | null>(null);
let showKebab = $state(false); let showKebab = $state(false);
let confirmRename = $state(false); let confirmRename = $state(false);
// Imperative focus — Svelte's native autofocus attribute is unreliable
// for inputs that appear only via conditional blocks.
$effect(() => {
if (renaming && renameInput) {
renameInput.focus();
renameInput.select();
}
});
// Load stored credentials exactly once for this workspace. Previously this // Load stored credentials exactly once for this workspace. Previously this
// ran on every `ws.webdav_url` change, which silently clobbered in-progress // ran on every `ws.webdav_url` change, which silently clobbered in-progress
// user edits whenever any other setting updated the config. // user edits whenever any other setting updated the config.
@ -133,11 +143,11 @@
{#if renaming} {#if renaming}
<input <input
type="text" type="text"
bind:this={renameInput}
bind:value={renameValue} bind:value={renameValue}
class="w-full bg-transparent text-xl font-bold outline-none" class="w-full bg-transparent text-xl font-bold outline-none"
onkeydown={(e) => { if (e.key === "Enter") handleRename(); if (e.key === "Escape") { renaming = false; } }} onkeydown={(e) => { if (e.key === "Enter") handleRename(); if (e.key === "Escape") { renaming = false; } }}
onblur={handleRename} onblur={handleRename}
autofocus
/> />
{:else} {:else}
<p class="text-xl font-bold">{ws?.name}</p> <p class="text-xl font-bold">{ws?.name}</p>

View file

@ -58,6 +58,7 @@
let completedVisible = $state(false); let completedVisible = $state(false);
let renamingListId = $state<string | null>(null); let renamingListId = $state<string | null>(null);
let renameValue = $state(""); let renameValue = $state("");
let renameListInput = $state<HTMLInputElement | null>(null);
let showListMenu = $state(false); let showListMenu = $state(false);
let showSubtasks = $state(false); let showSubtasks = $state(false);
let confirmDeleteList = $state(false); let confirmDeleteList = $state(false);
@ -85,6 +86,14 @@
if (showNewList && newListInput) newListInput.focus(); if (showNewList && newListInput) newListInput.focus();
}); });
// Same imperative-focus trick for the inline list-rename input.
$effect(() => {
if (renamingListId && renameListInput) {
renameListInput.focus();
renameListInput.select();
}
});
async function handleNewList() { async function handleNewList() {
if (!newListName.trim()) return; if (!newListName.trim()) return;
@ -631,11 +640,11 @@
{#if renamingListId === app.activeListId} {#if renamingListId === app.activeListId}
<input <input
type="text" type="text"
bind:this={renameListInput}
bind:value={renameValue} bind:value={renameValue}
class="w-full bg-transparent text-xl font-bold outline-none" class="w-full bg-transparent text-xl font-bold outline-none"
onkeydown={(e) => { if (e.key === "Enter") handleRenameList(); if (e.key === "Escape") renamingListId = null; }} onkeydown={(e) => { if (e.key === "Enter") handleRenameList(); if (e.key === "Escape") renamingListId = null; }}
onblur={handleRenameList} onblur={handleRenameList}
autofocus
/> />
{:else} {:else}
<p class="text-xl font-bold">{app.activeList?.title ?? "Tasks"}</p> <p class="text-xl font-bold">{app.activeList?.title ?? "Tasks"}</p>