From 6fbdda772f33a42ad84137d1afffe62c4418ee2a Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 30 Mar 2026 09:50:50 +0100 Subject: [PATCH] fix: vertical nav prefers closest element over widest overlap Down from Identity name input now lands on Personal button (closest) instead of Continue (wider overlap but further away). Co-Authored-By: Claude Opus 4.6 (1M context) --- neode-ui/src/composables/useControllerNav.ts | 22 ++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/neode-ui/src/composables/useControllerNav.ts b/neode-ui/src/composables/useControllerNav.ts index c0091c85..ec541d1d 100644 --- a/neode-ui/src/composables/useControllerNav.ts +++ b/neode-ui/src/composables/useControllerNav.ts @@ -149,13 +149,23 @@ function findNearestInDirection( }) scored.sort((a, b) => { - if (b.overlap !== a.overlap) return b.overlap - a.overlap - if (a.dist !== b.dist) return a.dist - b.dist - // Tiebreaker: prefer leftmost for up/down - if (direction === 'up' || direction === 'down') { - return a.el.getBoundingClientRect().left - b.el.getBoundingClientRect().left + const isVertical = direction === 'up' || direction === 'down' + // For vertical nav: prefer closest element first, use overlap as tiebreaker. + // This prevents a distant full-width element from winning over a closer narrow one. + if (isVertical) { + // Both have overlap — prefer closer distance + if (a.overlap > 0 && b.overlap > 0) { + if (a.dist !== b.dist) return a.dist - b.dist + if (b.overlap !== a.overlap) return b.overlap - a.overlap + return a.el.getBoundingClientRect().left - b.el.getBoundingClientRect().left + } + // One has overlap, the other doesn't — prefer the one with overlap + if (a.overlap !== b.overlap) return b.overlap - a.overlap + return a.dist - b.dist } - return 0 + // Horizontal: overlap first (same row), then distance + if (b.overlap !== a.overlap) return b.overlap - a.overlap + return a.dist - b.dist }) return scored[0]?.el ?? null