import * as React from 'react' import invariant from 'tiny-invariant' import { useRouterState } from './useRouterState' import { dummyMatchContext, matchContext } from './matchContext' import type { StructuralSharingOption, ValidateSelected, } from './structuralSharing' import type { AnyRouter, MakeRouteMatch, MakeRouteMatchUnion, RegisteredRouter, StrictOrFrom, ThrowConstraint, ThrowOrOptional, } from '@tanstack/router-core' export interface UseMatchBaseOptions< TRouter extends AnyRouter, TFrom, TStrict extends boolean, TThrow extends boolean, TSelected, TStructuralSharing extends boolean, > { select?: ( match: MakeRouteMatch, ) => ValidateSelected shouldThrow?: TThrow } export type UseMatchRoute = < TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean, >( opts?: UseMatchBaseOptions< TRouter, TFrom, true, true, TSelected, TStructuralSharing > & StructuralSharingOption, ) => UseMatchResult export type UseMatchOptions< TRouter extends AnyRouter, TFrom extends string | undefined, TStrict extends boolean, TThrow extends boolean, TSelected, TStructuralSharing extends boolean, > = StrictOrFrom & UseMatchBaseOptions< TRouter, TFrom, TStrict, TThrow, TSelected, TStructuralSharing > & StructuralSharingOption export type UseMatchResult< TRouter extends AnyRouter, TFrom, TStrict extends boolean, TSelected, > = unknown extends TSelected ? TStrict extends true ? MakeRouteMatch : MakeRouteMatchUnion : TSelected export function useMatch< TRouter extends AnyRouter = RegisteredRouter, const TFrom extends string | undefined = undefined, TStrict extends boolean = true, TThrow extends boolean = true, TSelected = unknown, TStructuralSharing extends boolean = boolean, >( opts: UseMatchOptions< TRouter, TFrom, TStrict, ThrowConstraint, TSelected, TStructuralSharing >, ): ThrowOrOptional, TThrow> { const nearestMatchId = React.useContext( opts.from ? dummyMatchContext : matchContext, ) const matchSelection = useRouterState({ select: (state: any) => { const match = state.matches.find((d: any) => opts.from ? opts.from === d.routeId : d.id === nearestMatchId, ) invariant( !((opts.shouldThrow ?? true) && !match), `Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`, ) if (match === undefined) { return undefined } return opts.select ? opts.select(match) : match }, structuralSharing: opts.structuralSharing, } as any) return matchSelection as any }