From 52d79ba26071a95e1926255e29690eda4695b830 Mon Sep 17 00:00:00 2001 From: kkfluous Date: Fri, 7 Aug 2026 17:31:09 +0800 Subject: [PATCH] feat: preserve BI sub tab history --- src/components/ui/surface.tsx | 32 +++++++++++++++++++++-- src/modules/energy/ElectricModule.tsx | 10 +++++-- src/modules/energy/HydrogenModule.tsx | 10 +++++-- src/modules/energy/SubTabs.tsx | 6 +++-- src/modules/energy/useHashSubTab.test.ts | 16 ++++++++++++ src/modules/energy/useHashSubTab.ts | 33 +++++++++++++++++------- src/modules/mileage/MileageModule.tsx | 28 ++++++++++++++------ 7 files changed, 109 insertions(+), 26 deletions(-) create mode 100644 src/modules/energy/useHashSubTab.test.ts diff --git a/src/components/ui/surface.tsx b/src/components/ui/surface.tsx index e16eba2..4a69989 100644 --- a/src/components/ui/surface.tsx +++ b/src/components/ui/surface.tsx @@ -190,23 +190,51 @@ export function SegmentedNav({ tabs, active, onChange, + idPrefix, + ariaLabel, className, }: { tabs: readonly { id: T; label: string; icon?: SurfaceIcon }[]; active: T; onChange: (id: T) => void; + idPrefix: string; + ariaLabel: string; className?: string; }) { + const activateFromKeyboard = (event: React.KeyboardEvent, currentIndex: number) => { + let nextIndex: number | null = null; + if (event.key === 'ArrowRight') nextIndex = (currentIndex + 1) % tabs.length; + if (event.key === 'ArrowLeft') nextIndex = (currentIndex - 1 + tabs.length) % tabs.length; + if (event.key === 'Home') nextIndex = 0; + if (event.key === 'End') nextIndex = tabs.length - 1; + if (nextIndex === null) return; + event.preventDefault(); + const next = tabs[nextIndex]; + onChange(next.id); + window.requestAnimationFrame(() => document.getElementById(`${idPrefix}-tab-${next.id}`)?.focus()); + }; + return (
-
- {tabs.map(({ id, label, icon: Icon }) => { +
+ {tabs.map(({ id, label, icon: Icon }, index) => { const isActive = active === id; return (