fix: stop preview input from the move's first step

The editors stay mounted while the move drains them, and a keystroke
typed during that drain was lost when they closed, or left in the parent
of an existing fork. The preview tabs are inert from the move's first
step, so nothing new reaches an editor after the drain starts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Guilhem Lemouel
2026-10-27 02:28:14 -07:00
co-authored by Claude Opus 5.5
parent b313a09abc
commit e555a2a79f
2 changed files with 18 additions and 1 deletions
@@ -334,6 +334,7 @@
bind:this={overlayHostEl}
class="absolute inset-0 flex flex-col min-h-0 bg-surface {visibility}"
aria-hidden={!active}
inert={permissions.moveStarted}
>
<!-- Only the side the tab shows is mounted. A hidden editor would be a second editor on
the item's one cell that tab dedupe, reading URLs, cannot see; a hidden side's drawers
@@ -439,6 +440,7 @@
bind:this={overlayHostEl}
class="absolute inset-0 flex flex-col min-h-0 bg-surface {visibility}"
aria-hidden={!active}
inert={permissions.moveStarted}
>
<!-- Waits for the host element, as the run form does: the editors' own drawers and
modals portal when they mount, and resolve their host only then. -->
@@ -455,6 +457,7 @@
bind:this={overlayHostEl}
class="absolute inset-0 flex flex-col min-h-0 bg-surface {visibility}"
aria-hidden={!active}
inert={permissions.moveStarted}
>
{#if overlayHostEl}
{#await import('./PageListView.svelte')}
@@ -476,6 +479,7 @@
bind:this={overlayHostEl}
class="absolute inset-0 flex flex-col min-h-0 bg-surface {visibility}"
aria-hidden={!active}
inert={permissions.moveStarted}
>
{#if overlayHostEl}
{#await import('./RunViewerView.svelte')}
@@ -499,6 +503,7 @@
bind:this={overlayHostEl}
class="absolute inset-0 flex flex-col min-h-0 bg-surface {visibility}"
aria-hidden={!active}
inert={permissions.moveStarted}
>
{#if artifact && runtime}
<ArtifactViewer
@@ -516,6 +521,7 @@
bind:this={overlayHostEl}
class="absolute inset-0 flex flex-col min-h-0 bg-surface {visibility}"
aria-hidden={!active}
inert={permissions.moveStarted}
>
<!-- Waits for the host element itself: Drawer portals when it mounts, and the portal
action reads its target once, so a form mounted in the same pass as this div would
@@ -42,7 +42,11 @@ export function useSessionReadOnly(workspace: () => string | undefined) {
}
/** The session chat whose work mode the session UI follows. */
type WorkModeHost = { readonly workMode: AIWorkMode; readonly moving?: boolean }
type WorkModeHost = {
readonly workMode: AIWorkMode
readonly moving?: boolean
readonly moveStarted?: boolean
}
/**
* What the session UI may offer in `workspace`. Its editors save drafts, so it reads
@@ -70,6 +74,7 @@ export function useSessionPermissions(
host?.workMode === AIWorkMode.USE
)
const moving = $derived(!!host?.moving)
const moveStarted = $derived(!!host?.moveStarted)
const workspaces = fromStore(userWorkspaces)
const entry = $derived(workspaces.current.find((w) => w.id === workspace()))
@@ -82,6 +87,12 @@ export function useSessionPermissions(
get moving() {
return moving
},
/** A move has started: the preview takes no more input, so what its editors hold can be
* drained before `moving` closes them. A keystroke after the drain would be lost with the
* editor. */
get moveStarted() {
return moveStarted
},
/** Whether this user can save the drafts the `kind` editor writes. */
canOpenEditor: (kind: string) => !readOnly && !moving && rights.roleCanDraft(kind),
/** The same, and this item's own permissions let them write it. */