Fix the review's findings: drag on pointer events, read the window back
Build App / compute-version (pull_request) Successful in 4s
Build App / build-macos (pull_request) Successful in 2m30s
Build App / build-linux (pull_request) Successful in 5m11s
Build App / build-windows (pull_request) Successful in 5m23s
Build App / create-tag (pull_request) Skipped
Build App / sync-to-github (pull_request) Skipped

Ten findings from the review of the previous commit, all applied.

**The tab drag is now pointer events, not HTML5 drag-and-drop.** Two
independent reasons, either one fatal. Tauri's `dragDropEnabled` blocks
HTML5 drag inside the webview on Windows, and it cannot just be turned
off — `TerminalView` needs Tauri's native drag-drop event, which is the
only one that carries dropped *file paths*. And an HTML5 drag carries a
`DataTransfer`: released over any text field in the app, the default
handler types `term:<uuid>` into it, and in Config that is then saved
with the project. Pointer events have neither problem, and the drag is
measured from the tabs on screen rather than from the event target, so
the marker and the drop agree even over the marker itself. Escape
abandons a drag; a press under 4px stays a click; the click that ends a
drag does not select.

**`Ctrl+Shift+←/→` no longer swallows word-wise selection.** It is bound
on `document` in the capture phase, so in any input — the rename field,
Config, Settings — it was taking the OS's extend-selection chord *and*
silently reordering the strip. Guarded by `inTextField()`, which
excludes xterm's helper textarea: that is an input-method shim, and the
terminal is where the shortcut matters most.

**The pop-out's state is read from the window, never remembered.** The
pane is unmounted whenever another Project Home sub-tab is selected, so
"Keep on top" came back Off over a window still floating on top.
`get_browser_view_popout_state` returns both facts from the window
itself, and the change event carries them. `poppedOut` is tri-state:
until the answer arrives the iframe is not mounted, because guessing
"not popped out" is what flashes a second viewer onto the browser.

Also: `popout::close` and the off-status emit in the supervisor are
behind the same epoch guard as the deregistration above them, so a
supervisor whose teardown outlives a restart can no longer destroy the
*new* session's window; `close()` returns its `destroy()` error instead
of logging it and reporting success, since the pane restores its iframe
on success; the drop marker is `pointer-events-none` and is placed
before the first *visible* tab at or past the slot, so it neither
refuses a drop nor vanishes when a `tabOrder` entry renders nothing; and
the "Keep on top" Toggle's accessible name now matches its visible text.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 07:40:51 -07:00
co-authored by Claude Opus 5
parent d73096c937
commit a41d93ea46
14 changed files with 522 additions and 185 deletions
+13 -7
View File
@@ -128,23 +128,29 @@ pub async fn open_browser_view_popout(
}
/// Close the pop-out, putting the view back in the tab. No-op if it is closed.
///
/// Propagates a failed close rather than reporting success: the pane restores
/// its iframe on success, and doing that with the window still up puts two
/// viewers on one browser.
#[tauri::command]
pub async fn close_browser_view_popout(
project_id: String,
app_handle: AppHandle,
) -> Result<(), String> {
popout::close(&app_handle, &project_id);
Ok(())
popout::close(&app_handle, &project_id)
}
/// Whether the pop-out is open — asked on tab open, since a window can outlive
/// the pane that spawned it.
/// Whether the pop-out is open, and whether it is pinned on top.
///
/// Read on every pane mount: the window outlives the pane — which is unmounted
/// whenever another Project Home sub-tab is selected — so neither fact can be
/// carried in component state.
#[tauri::command]
pub async fn is_browser_view_popout_open(
pub async fn get_browser_view_popout_state(
project_id: String,
app_handle: AppHandle,
) -> Result<bool, String> {
Ok(popout::is_open(&app_handle, &project_id))
) -> Result<popout::PopoutState, String> {
Ok(popout::state(&app_handle, &project_id))
}
/// Pin the pop-out above other windows, so it can be watched while working in