{"version":3,"file":"routing-utils.mjs","sources":["../../../src/lib/routing/routing-utils.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport {\n  useSearchParams,\n  useParams,\n  useLocation,\n  useNavigate,\n  type NavigateOptions,\n} from 'react-router-dom';\nimport { type RoutePath, type RouteParams, type RouteQuery } from './routes';\n\n/**\n * Utilities: useTabParam, useRouteInfo, useRouteNavigate, query helpers.\n */\n\n/**\n * Hook for managing tab state via URL query parameter\n */\nexport function useTabParam(\n  paramName: string = 'tab',\n  defaultTab: string = ''\n): [string, (tab: string) => void] {\n  const [searchParams, setSearchParams] = useSearchParams();\n\n  const currentTab = searchParams.get(paramName) ?? defaultTab;\n\n  const setTab = useCallback(\n    (tab: string) => {\n      const newParams = new URLSearchParams(searchParams);\n      if (tab === defaultTab) {\n        newParams.delete(paramName);\n      } else {\n        newParams.set(paramName, tab);\n      }\n      setSearchParams(newParams, { replace: true });\n    },\n    [searchParams, setSearchParams, paramName, defaultTab]\n  );\n\n  return [currentTab, setTab];\n}\n\n/**\n * Hook for getting current route information\n */\nexport function useRouteInfo(): {\n  pathname: string;\n  search: string;\n  hash: string;\n  state: unknown;\n  params: Record<string, string | undefined>;\n  query: Record<string, string>;\n  isExactMatch: (path: RoutePath) => boolean;\n  isActiveRoute: (path: string) => boolean;\n} {\n  const location = useLocation();\n  const params = useParams();\n  const [searchParams] = useSearchParams();\n\n  return useMemo(\n    () => ({\n      pathname: location.pathname,\n      search: location.search,\n      hash: location.hash,\n      state: location.state as unknown,\n      params,\n      query: Object.fromEntries(searchParams.entries()),\n      isExactMatch: (path: RoutePath) => location.pathname === path,\n      isActiveRoute: (path: string) => location.pathname.startsWith(path),\n    }),\n    [location, params, searchParams]\n  );\n}\n\n/**\n * Hook for type-safe navigation\n */\nexport function useRouteNavigate(): {\n  navigateTo: (path: RoutePath | string, options?: NavigateOptions) => void;\n  navigateWithParams: <T extends keyof RouteParams>(\n    path: T,\n    params: RouteParams[T],\n    options?: NavigateOptions\n  ) => void;\n  navigateWithQuery: <T extends keyof RouteQuery>(\n    path: T,\n    query?: Partial<RouteQuery[T]>,\n    options?: NavigateOptions\n  ) => void;\n  goBack: () => void;\n  goForward: () => void;\n} {\n  const navigate = useNavigate();\n\n  const navigateTo = useCallback(\n    (path: RoutePath | string, options?: NavigateOptions) => {\n      void navigate(path, options);\n    },\n    [navigate]\n  );\n\n  const navigateWithParams = useCallback(\n    <T extends keyof RouteParams>(path: T, params: RouteParams[T], options?: NavigateOptions) => {\n      let resolvedPath: string = path;\n      for (const [key, value] of Object.entries(params)) {\n        resolvedPath = resolvedPath.replace(`:${key}`, encodeURIComponent(String(value)));\n      }\n      void navigate(resolvedPath, options);\n    },\n    [navigate]\n  );\n\n  const navigateWithQuery = useCallback(\n    <T extends keyof RouteQuery>(\n      path: T,\n      query?: Partial<RouteQuery[T]>,\n      options?: NavigateOptions\n    ) => {\n      let resolvedPath: string = path;\n      if (query && Object.keys(query).length > 0) {\n        const searchParams = new URLSearchParams();\n        for (const [key, value] of Object.entries(query)) {\n          if (value !== undefined && value !== null) {\n            let stringValue: string;\n            if (typeof value === 'object') {\n              stringValue = JSON.stringify(value);\n            } else if (\n              typeof value === 'string' ||\n              typeof value === 'number' ||\n              typeof value === 'boolean'\n            ) {\n              stringValue = String(value);\n            } else {\n              stringValue = JSON.stringify(value);\n            }\n            searchParams.set(key, stringValue);\n          }\n        }\n        resolvedPath = `${path}?${searchParams.toString()}`;\n      }\n      void navigate(resolvedPath, options);\n    },\n    [navigate]\n  );\n\n  const goBack = useCallback(() => {\n    void navigate(-1);\n  }, [navigate]);\n\n  const goForward = useCallback(() => {\n    void navigate(1);\n  }, [navigate]);\n\n  return {\n    navigateTo,\n    navigateWithParams,\n    navigateWithQuery,\n    goBack,\n    goForward,\n  };\n}\n\n/**\n * Parse and manage query parameters\n */\nexport function useQueryParams<T extends Record<string, string | undefined>>(): [\n  Partial<T>,\n  (params: Partial<T>, replace?: boolean) => void,\n] {\n  const [searchParams, setSearchParams] = useSearchParams();\n\n  const query = useMemo(() => {\n    const result: Record<string, string> = {};\n    searchParams.forEach((value, key) => {\n      result[key] = value;\n    });\n    return result as Partial<T>;\n  }, [searchParams]);\n\n  const setQuery = useCallback(\n    (params: Partial<T>, replace: boolean = false) => {\n      const newParams = replace ? new URLSearchParams() : new URLSearchParams(searchParams);\n\n      for (const [key, value] of Object.entries(params)) {\n        if (value === undefined || value === null || value === '') {\n          newParams.delete(key);\n        } else {\n          newParams.set(key, String(value));\n        }\n      }\n\n      setSearchParams(newParams, { replace: true });\n    },\n    [searchParams, setSearchParams]\n  );\n\n  return [query, setQuery];\n}\n\n/**\n * Get a single query parameter with type safety\n */\nexport function useQueryParam<T extends string = string>(\n  paramName: string,\n  defaultValue?: T\n): [T | undefined, (value: T | undefined) => void] {\n  const [searchParams, setSearchParams] = useSearchParams();\n\n  const value = (searchParams.get(paramName) as T) ?? defaultValue;\n\n  const setValue = useCallback(\n    (newValue: T | undefined) => {\n      const newParams = new URLSearchParams(searchParams);\n      if (newValue === undefined || newValue === null) {\n        newParams.delete(paramName);\n      } else {\n        newParams.set(paramName, newValue);\n      }\n      setSearchParams(newParams, { replace: true });\n    },\n    [searchParams, setSearchParams, paramName]\n  );\n\n  return [value, setValue];\n}\n"],"names":["useTabParam","paramName","defaultTab","searchParams","setSearchParams","useSearchParams","currentTab","setTab","useCallback","tab","newParams","useRouteInfo","location","useLocation","params","useParams","useMemo","path","useRouteNavigate","navigate","useNavigate","navigateTo","options","navigateWithParams","resolvedPath","key","value","navigateWithQuery","query","stringValue","goBack","goForward","useQueryParams","result","setQuery","replace","useQueryParam","defaultValue","setValue","newValue"],"mappings":"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"}