import { createContext, useContext, type ReactNode, type ComponentType } from 'react' import type { NavigationProvider, LinkProps, NavigateOptions } from '../types' export interface NavigationContextValue { /** Navigate to a path */ navigate: (to: string, options?: NavigateOptions) => void /** Get current path */ getCurrentPath: () => string /** Link component for rendering navigation links */ Link: ComponentType } export const NavigationContext = createContext(null) /** Default link component using plain anchor tags */ function DefaultLink({ href, children, className }: LinkProps) { return ( {children} ) } /** Default navigation using window.location */ const defaultNavigationProvider: NavigationProvider = { navigate: (to, options) => { if (options?.replace) { window.history.replaceState(options.state, '', to) } else { window.location.href = to } }, getCurrentPath: () => window.location.pathname, LinkComponent: DefaultLink, } export interface NavigationProviderProps { children: ReactNode navigationProvider?: NavigationProvider } /** * Provides navigation capabilities to child components. * Allows integration with different routers (react-router, next/router, etc.) * * @example * ```tsx * // With react-router * import { Link, useNavigate, useLocation } from 'react-router-dom' * * const reactRouterProvider: NavigationProvider = { * navigate: (to, options) => navigate(to, options), * getCurrentPath: () => location.pathname, * LinkComponent: ({ href, children, className }) => ( * {children} * ), * } * * * * * ``` */ export function NavigationProvider({ children, navigationProvider = defaultNavigationProvider, }: NavigationProviderProps) { return ( {children} ) } /** * Hook to access navigation capabilities. * Must be used within a NavigationProvider. * * @example * ```tsx * const { navigate, getCurrentPath, Link } = useNavigation() * * // Programmatic navigation * navigate('/dashboard') * * // Link rendering * Settings * ``` */ export function useNavigation(): NavigationContextValue { const context = useContext(NavigationContext) if (!context) { throw new Error('useNavigation must be used within a NavigationProvider') } return context }