PURPOSE

Universal bottom navigation bar for the React metagame shell. Renders in two distinct modes: a default main-menu bar with Shop/Play/Ships tabs used across Hub/Shop/Ships/Mission/Profile/Collection, and an overlay bar with a wide BACK button plus optional right-aligned tabs used inside fullscreen overlays such as the planet track and challenges.

OWNS

  • BottomNav — default-export functional component rendering the three-tab main-menu bar.
  • OverlayBottomBar — named-export functional component rendering the overlay variant.
  • OverlayTab — exported TypeScript interface describing a single tab passed to the overlay variant (label, optional icon, onClick, optional active).
  • OverlayBarProps — internal props interface for the overlay variant (onBack, optional tabs).
  • Inline SVG icon paths for Shop (cart), Play (triangle), and Ships (ship silhouette).
  • Active-tab detection logic derived from the current router pathname.

READS FROM

  • react-router-domuseNavigate and useLocation for routing and active-route detection.
  • @starship-survivors/services/anchor-registryuseAnchor to register the Ships tab as the nav-collection anchor.
  • location.pathname — drives the three active-state checks: isPlay for /, isShop for paths starting with /shop, isShips for paths starting with /games/starship-survivors/ships.
  • CSS custom properties from the medical-UI scope: --med-panel-raised, --med-border, --med-accent, --med-text-muted.
  • Shop CSS overrides under the BOTTOM NAV section of screens/shop/shop.css.

PUSHES TO

  • React Router via navigate('/shop'), navigate('/'), navigate('/games/starship-survivors/ships') on tab click.
  • The anchor registry, which receives the Ships tab’s DOM ref under the key nav-collection.
  • Consumer-supplied callbacks: onBack and per-tab onClick handlers in the overlay variant.

DOES NOT

  • Manage any local component state.
  • Persist anything to stores, Supabase, or localStorage.
  • Render badges, counts, notification dots, or dynamic icons.
  • Handle keyboard navigation, focus management, or aria roles beyond the semantic <nav> element.
  • Define its own styling — all visual rules live in shared CSS (medical-UI tokens plus shop overrides).
  • Render itself outside a .sig-shop CSS scope; styling silently fails if that contract is violated.
  • Animate transitions between active tabs.
  • Hide or conditionally remove tabs in the main-menu variant — the three tabs are always rendered.

Signals

  • Click on a main-menu tab triggers navigate(...) and updates router state; the active class flips on next render via location.pathname comparison.
  • Click on the overlay BACK button invokes the consumer’s onBack callback.
  • Click on an overlay tab invokes that tab’s onClick callback; active is consumer-controlled and reflected via the active CSS class.
  • The Ships tab’s DOM node is registered with the anchor registry on mount under nav-collection, allowing other systems to position tutorials, tooltips, or effects relative to it.

Entry points

  • Default export BottomNav is consumed by V32Shell and mounted across the main metagame screens.
  • Named export OverlayBottomBar is imported by fullscreen overlay screens (planet track, challenges) that supply their own onBack and optional tab array.
  • The OverlayTab interface is imported by overlay-mounting screens to type their tab definitions.

Pattern notes

  • Two modes share the same .bottom-bar root class so height, background, and 1px top hairline are identical between variants; the overlay variant adds .bottom-bar-overlay for layout differences.
  • Active-state detection is pathname-based with startsWith for nested routes (Shop, Ships) and exact match for the root Play route.
  • The Shop and Play tabs are interactive <div> elements rather than buttons, while the overlay BACK and tab elements are real <button> elements — a deliberate split tied to the existing .bottom-bar-btn versus .btn-cta styling.
  • The BACK button reuses the shop’s .btn-cta styling inside a .back-btn-fire-wrap to inherit the LAUNCH-style fire-stroke wrapper rhythm at a smaller size.
  • The overlay layout uses a flex: 1 spacer div to push optional tabs to the right of the BACK button.
  • Styling is governed by ADR 20260513-001 (medical-UI shared chrome); this component is a pure consumer of those tokens and does not introduce its own colors.
  • Icons are inline SVG with fill="currentColor" so they inherit the active/inactive text color from the surrounding tab class.
  • The component has no props for the main-menu variant — all routing state comes from React Router and all active-state derives from location.pathname.