Phase 1: tabbed workspaces
Each tab is an independent tile tree; PTYs in non-active tabs keep
running (render-all-panes with visibility:hidden on inactive layers
so xterm.js's fit() still sees valid dimensions and the existing
per-pane resize dedupe absorbs no-op SIGWINCHes).
workspace.json shape goes from a bare TreeNode to
`{ version: 2, workspaces: [{ id, name, tree }] }` with a legacy v1
auto-wrap migration (the old single tree becomes one tab named
"Default").
App.tsx wraps the old single-tree state in workspace-aware state
but keeps `tree` / `setTree` / `activeLeafId` / `setActiveLeafId` as
identity-stable derived wrappers (reading currentWorkspaceId from a
ref), so the bulk of App.tsx stays unchanged.
XtermPane's initial term.focus() now checks `visibility !== "hidden"`
on the container so a pane mounting inside a hidden tab on app boot
doesn't yank focus away from the active tab. The focus poller is
scoped to the active workspace layer for the same reason.
Shortcuts: Ctrl+T new tab, Ctrl+Shift+T close current (window.confirm
when there are live panes), Ctrl+PageDown/PageUp navigate, Ctrl+1..9
switch to tab N. README + help overlay auto-generated from
shortcuts.ts.
79/79 vitest pass (7 new envelope-migration cases). tsc -b clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c92847413b
commit
1a035ad0a6
8 changed files with 933 additions and 52 deletions
|
|
@ -273,8 +273,18 @@ export default function XtermPane({
|
|||
});
|
||||
ro.observe(container);
|
||||
|
||||
// Focus so typing immediately lands in the terminal.
|
||||
term?.focus();
|
||||
// Focus so typing immediately lands in the terminal — but ONLY if the
|
||||
// host container is actually visible. With multiple tabs (workspaces),
|
||||
// a pane in a hidden tab still mounts and spawns; we must not yank
|
||||
// focus into a tab the user can't see. CSS `visibility: hidden` is
|
||||
// inherited, so the computed style on the container reflects whether
|
||||
// any ancestor (workspace-layer) is hiding us.
|
||||
if (
|
||||
container.isConnected &&
|
||||
getComputedStyle(container).visibility !== "hidden"
|
||||
) {
|
||||
term?.focus();
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue