From e055f18174eecb8cae28e631011488fd3463ce9a Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sat, 30 May 2026 21:30:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtv=E9=A1=B5=E9=9D=A2=E8=81=9A?= =?UTF-8?q?=E7=84=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/tv/TVVirtualRemote.tsx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/tv/TVVirtualRemote.tsx b/src/components/tv/TVVirtualRemote.tsx index 892b63b..b12d144 100644 --- a/src/components/tv/TVVirtualRemote.tsx +++ b/src/components/tv/TVVirtualRemote.tsx @@ -91,6 +91,10 @@ function scrollIntoScrollableParent(element: HTMLElement) { return true; } +function isTopNavigationElement(element: HTMLElement) { + return Boolean(element.closest('header')); +} + function focusElement(element: HTMLElement) { element.focus({ preventScroll: true }); @@ -138,7 +142,7 @@ function moveSpatialFocus(direction: 'up' | 'down' | 'left' | 'right', lastFocus const cx = current.left + current.width / 2; const cy = current.top + current.height / 2; - let best: { element: HTMLElement; score: number } | null = null; + const candidates: Array<{ element: HTMLElement; score: number }> = []; for (const element of elements) { if (element === active) continue; @@ -160,11 +164,22 @@ function moveSpatialFocus(direction: 'up' | 'down' | 'left' | 'right', lastFocus const secondary = direction === 'left' || direction === 'right' ? Math.abs(dy) : Math.abs(dx); const score = primary + secondary * 2.4; - if (!best || score < best.score) { - best = { element, score }; + candidates.push({ element, score }); + } + + let eligibleCandidates = candidates; + if (direction === 'up' && !isTopNavigationElement(active)) { + const contentCandidates = candidates.filter(({ element }) => !isTopNavigationElement(element)); + if (contentCandidates.length > 0) { + eligibleCandidates = contentCandidates; } } + const best = eligibleCandidates.reduce<{ element: HTMLElement; score: number } | null>( + (currentBest, candidate) => (!currentBest || candidate.score < currentBest.score ? candidate : currentBest), + null + ); + if (best) focusElement(best.element); }