mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-30 19:09:28 +00:00
fix(desktop): stay on the tab that fills a closed slot
Closing an active layout tab always selected the previous neighbor, so focus jumped left every time. Prefer the right neighbor instead (left only at the end) — same rule terminals and the preview rail already use.
This commit is contained in:
parent
383829df2e
commit
ec1645a5ba
2 changed files with 46 additions and 4 deletions
|
|
@ -184,9 +184,9 @@ export function normalize(node: LayoutNode): LayoutNode | null {
|
|||
return { ...node, children, weights }
|
||||
}
|
||||
|
||||
/** Remove a pane wherever it lives. Closing the ACTIVE tab activates its
|
||||
* previous neighbor (the next one when it was first) — browser-tab feel,
|
||||
* never a jump to the strip's start. */
|
||||
/** Remove a pane wherever it lives. Closing the ACTIVE tab leaves selection on
|
||||
* the neighbor that fills its slot (right; left when it was last) — same rule
|
||||
* as terminals and the preview rail. */
|
||||
export function removePane(node: LayoutNode, paneId: string): LayoutNode | null {
|
||||
const walk = (n: LayoutNode): LayoutNode => {
|
||||
if (n.type === 'group') {
|
||||
|
|
@ -198,7 +198,8 @@ export function removePane(node: LayoutNode, paneId: string): LayoutNode | null
|
|||
|
||||
const panes = n.panes.filter(p => p !== paneId)
|
||||
|
||||
return { ...n, panes, active: n.active === paneId ? panes[Math.max(0, at - 1)] : n.active }
|
||||
// After splice, `at` indexes the old right neighbor (clamp left at end).
|
||||
return { ...n, panes, active: n.active === paneId ? (panes[Math.min(at, panes.length - 1)] ?? '') : n.active }
|
||||
}
|
||||
|
||||
return { ...n, children: n.children.map(walk) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { findGroup, group, removePane, split } from './model'
|
||||
|
||||
describe('removePane close-neighbor selection', () => {
|
||||
it('closing a middle active tab keeps you on the tab that slides into its slot', () => {
|
||||
// [a, b, c] active=b → close b → [a, c] active=c (was right of b), not a
|
||||
const next = removePane(group(['a', 'b', 'c'], { active: 'b', id: 'g' }), 'b')
|
||||
|
||||
expect(next).toMatchObject({ type: 'group', panes: ['a', 'c'], active: 'c' })
|
||||
})
|
||||
|
||||
it('closing the first active tab still advances to the former next tab', () => {
|
||||
const next = removePane(group(['a', 'b', 'c'], { active: 'a', id: 'g' }), 'a')
|
||||
|
||||
expect(next).toMatchObject({ type: 'group', panes: ['b', 'c'], active: 'b' })
|
||||
})
|
||||
|
||||
it('closing the last active tab falls back to its left neighbor', () => {
|
||||
const next = removePane(group(['a', 'b', 'c'], { active: 'c', id: 'g' }), 'c')
|
||||
|
||||
expect(next).toMatchObject({ type: 'group', panes: ['a', 'b'], active: 'b' })
|
||||
})
|
||||
|
||||
it('closing a non-active tab leaves the selection alone', () => {
|
||||
const next = removePane(group(['a', 'b', 'c'], { active: 'c', id: 'g' }), 'b')
|
||||
|
||||
expect(next).toMatchObject({ type: 'group', panes: ['a', 'c'], active: 'c' })
|
||||
})
|
||||
|
||||
it('walks nested splits so session stacks still get the slot rule', () => {
|
||||
const tree = split('row', [
|
||||
group(['workspace'], { active: 'workspace', id: 'main' }),
|
||||
group(['tile:1', 'tile:2', 'tile:3'], { active: 'tile:2', id: 'stack' })
|
||||
])
|
||||
const next = removePane(tree, 'tile:2')
|
||||
const stack = next ? findGroup(next, 'stack') : null
|
||||
|
||||
expect(stack).toMatchObject({ panes: ['tile:1', 'tile:3'], active: 'tile:3' })
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue