import { createContext, useContext } from "react"; import type { Page } from "../../lib/urlState"; import type { ChannelView } from "./navigationInit"; // The navigation contexts + their hooks, split out of NavigationProvider so that file exports only // components (Fast Refresh can then hot-swap the provider without remounting the tree). // // TWO contexts on purpose: a STABLE actions context (setPage/openChannel/… never change reference) // and a CHANGING state context (page/channelView/ytSearch). Context consumers re-render whenever the // value changes, so deep memo'd leaves (VideoCard, PlayerModal) subscribe to actions ONLY and never // re-render on a page/channel switch — preserving the memo that keeps feed appends from re-rendering // every existing card. export interface NavigationState { page: Page; /** The open channel page (null = none). Overlays `page`; rides in history.state._chan. */ channelView: ChannelView | null; /** Live YouTube search term (null = normal feed). A feed sub-view; rides in history.state._yt. */ ytSearch: string | null; } export interface NavigationActions { /** Switch modules. Closes every open overlay first and pushes only once their history entries are * back (`lib/history.closeOverlaysThenNavigate`), so over an open player the push lands a moment * after the call; with nothing open it is synchronous. The requested page being already current * (with no channel page over it) pushes nothing — but the overlays still close. * * `then` runs once the navigation has happened (the push made, or found unnecessary) — for a * request that belongs to the NEW entry, which over an open player does not exist yet at the * call (`lib/homeIntent`). */ setPage: (next: Page, then?: () => void) => void; openChannel: (id: string, name?: string) => void; closeChannel: () => void; enterYtSearch: (q: string) => void; exitYtSearch: () => void; } export const NavigationStateContext = createContext({ page: "feed", channelView: null, ytSearch: null, }); export const NavigationActionsContext = createContext({ setPage: () => {}, openChannel: () => {}, closeChannel: () => {}, enterYtSearch: () => {}, exitYtSearch: () => {}, }); export function useNavigation(): NavigationState { return useContext(NavigationStateContext); } export function useNavigationActions(): NavigationActions { return useContext(NavigationActionsContext); }