import type { Injector } from '@furystack/inject';
import type { MatchOptions, MatchResult } from 'path-to-regexp';
import type { RenderOptions } from '../models/render-options.js';
import type { ViewTransitionConfig } from '../view-transition.js';
import type { HashLiterals, QueryValidator } from './nested-route-types.js';
/**
 * Options passed to a dynamic title resolver function.
 * @typeParam TMatchResult - The type of matched URL parameters
 */
export type TitleResolverOptions<TMatchResult = unknown> = {
    match: MatchResult<TMatchResult extends object ? TMatchResult : object>;
    injector: Injector;
};
/**
 * Metadata associated with a route entry.
 * Used by consumers (breadcrumbs, document title, navigation trees) to
 * derive display information from the route hierarchy.
 *
 * This is an `interface` so that applications can augment it with custom fields
 * via declaration merging:
 *
 * @example
 * ```typescript
 * declare module '@furystack/shades' {
 *   interface NestedRouteMeta {
 *     icon?: IconDefinition
 *     hidden?: boolean
 *   }
 * }
 * ```
 *
 * @typeParam TMatchResult - The type of matched URL parameters
 */
export interface NestedRouteMeta<TMatchResult = unknown> {
    title?: string | ((options: TitleResolverOptions<TMatchResult>) => string | Promise<string>);
}
/**
 * A single route entry in a NestedRouter configuration.
 * Unlike flat `Route`, the URL is the Record key (not a field), and the
 * `component` receives an `outlet` for rendering matched child content.
 *
 * Routes may additionally declare:
 * - `query`: a validator that parses the deserialized query string into a
 *   typed shape; `component` receives the parsed value (or `null` when
 *   validation fails). The route still matches on path alone — an invalid
 *   query never prevents navigation.
 * - `hash`: a readonly tuple of allowed URL hash literals; `component`
 *   receives the current hash when it matches one of the listed literals,
 *   or `undefined` otherwise.
 *
 * @typeParam TMatchResult - The type of matched URL parameters
 * @typeParam TQuery - The typed query shape parsed from the URL search string (defaults to `never`)
 * @typeParam THash - The readonly tuple of allowed hash literals (defaults to `never`)
 */
export type NestedRoute<TMatchResult = unknown, TQuery = any, THash extends HashLiterals = readonly any[]> = {
    meta?: NestedRouteMeta<TMatchResult>;
    component: (options: {
        currentUrl: string;
        match: MatchResult<TMatchResult extends object ? TMatchResult : object>;
        query: TQuery | null;
        hash: THash[number] | undefined;
        outlet?: JSX.Element;
    }) => JSX.Element;
    routingOptions?: MatchOptions;
    /**
     * Called after the route's DOM has been mounted. When view transitions are enabled,
     * this runs after the transition's update callback has completed and the new DOM is in place.
     * Use for imperative side effects like data fetching or focus management — not for visual
     * animations, which are handled by the View Transition API when `viewTransition` is enabled.
     */
    onVisit?: (options: RenderOptions<unknown> & {
        element: JSX.Element;
    }) => Promise<void>;
    /**
     * Called before the route's DOM is removed (and before the view transition starts, if enabled).
     * Use for cleanup or teardown logic — not for exit animations, which are handled by the
     * View Transition API when `viewTransition` is enabled.
     */
    onLeave?: (options: RenderOptions<unknown> & {
        element: JSX.Element;
    }) => Promise<void>;
    children?: Record<string, NestedRoute<any, any, any>>;
    viewTransition?: boolean | ViewTransitionConfig;
    /**
     * Optional validator that narrows the deserialized URL query string into a
     * typed shape. Return `null` when the URL's query does not satisfy the route's
     * contract — the route still matches on path, but `component` receives `null`.
     */
    query?: QueryValidator<TQuery>;
    /**
     * Optional readonly tuple of URL hash literals the route understands. Declare
     * with `as const` to preserve literal types, e.g. `hash: ['tab1', 'tab2'] as const`.
     * The router forwards the current hash to `component` only when it matches one
     * of the listed literals; otherwise `component.hash` is `undefined`.
     */
    hash?: THash;
};
/**
 * Props for the NestedRouter component.
 * Routes are defined as a Record where keys are URL patterns.
 */
export type NestedRouterProps = {
    routes: Record<string, NestedRoute<any, any, any>>;
    notFound?: JSX.Element;
    viewTransition?: boolean | ViewTransitionConfig;
};
/**
 * A single entry in a match chain, pairing a matched route with its match
 * result and the typed `query` / `hash` values derived from the URL for that
 * route's declared schema.
 */
export type MatchChainEntry = {
    route: NestedRoute<unknown, any, any>;
    match: MatchResult<object>;
    query: unknown;
    hash: string | undefined;
};
/**
 * Internal state for the NestedRouter component.
 * `matchChain` is `null` when a notFound fallback has been rendered,
 * distinguishing it from the initial empty array (not yet processed).
 */
export type NestedRouterState = {
    matchChain: MatchChainEntry[] | null;
    jsx: JSX.Element;
    chainElements: JSX.Element[];
};
/**
 * Recursively builds a match chain from outermost to innermost matched route.
 *
 * For routes with children, a prefix match (`end: false`) is attempted first.
 * If a child matches the remaining URL, the parent and child chain are combined.
 * If no child matches, an exact match on the parent alone is attempted.
 *
 * For leaf routes (no children), only exact matching is used.
 *
 * The returned entries contain placeholder `query: null` / `hash: undefined`
 * values; callers are expected to populate them via {@link enrichMatchChain}.
 *
 * @param routes - The route definitions to match against
 * @param currentUrl - The URL path to match
 * @returns An array of matched chain entries from outermost to innermost, or null if no match
 */
export declare const buildMatchChain: (routes: Record<string, NestedRoute<any, any, any>>, currentUrl: string) => MatchChainEntry[] | null;
/**
 * Populates each chain entry's `query` and `hash` fields by running the route's
 * declared validator against the URL's deserialized query string, and matching
 * the current URL hash against the route's declared literal tuple.
 *
 * Entries whose route declares neither `query` nor `hash` are returned with
 * `query: null` / `hash: undefined`.
 *
 * When no entry in the chain declares either `query` or `hash`, the input
 * array is returned unchanged to avoid a per-navigation allocation on the
 * common path-only case.
 *
 * @param chain - The chain produced by {@link buildMatchChain}
 * @param deserializedSearch - The deserialized URL query string
 * @param currentHash - The current URL hash (without the leading `#`)
 */
export declare const enrichMatchChain: (chain: MatchChainEntry[], deserializedSearch: Record<string, unknown>, currentHash: string) => MatchChainEntry[];
/**
 * Finds the first index where two match chains diverge, considering route
 * identity and matched path parameters only. Used to scope lifecycle hooks
 * (`onLeave` / `onVisit`) so that a query string or hash change does not
 * fire spurious mount / unmount callbacks.
 *
 * Returns the length of the shorter chain if one is a prefix of the other.
 */
export declare const findDivergenceIndex: (oldChain: MatchChainEntry[], newChain: MatchChainEntry[]) => number;
/**
 * Returns true when any chain entry differs in its `query` value or `hash`
 * segment, ignoring path-level fields (route identity and params). Used to
 * force a re-render when the URL's query string or hash changes without the
 * matched route chain itself changing.
 *
 * Query values are compared with a key-order-independent shallow equality —
 * sufficient for the typed shapes a route's `query` validator surfaces.
 */
export declare const hasQueryOrHashChanged: (oldChain: MatchChainEntry[], newChain: MatchChainEntry[]) => boolean;
/**
 * The result of rendering a match chain, containing both the fully composed
 * JSX tree and per-entry elements for scoped lifecycle animations.
 */
export type RenderMatchChainResult = {
    jsx: JSX.Element;
    chainElements: JSX.Element[];
};
/**
 * Renders a match chain inside-out: starts with the innermost (leaf) route
 * rendered with `outlet: undefined`, then passes its JSX as `outlet` to
 * each successive parent up the chain.
 *
 * Returns per-entry elements so that lifecycle hooks (`onLeave`/`onVisit`)
 * receive only the element for their own route level, not the full tree.
 *
 * @param chain - The match chain from outermost to innermost
 * @param currentUrl - The current URL path
 * @returns The fully composed JSX element and per-entry rendered elements
 */
export declare const renderMatchChain: (chain: MatchChainEntry[], currentUrl: string) => RenderMatchChainResult;
/**
 * Resolves the effective view transition config for a navigation by merging
 * the router-level default with the innermost (leaf) route's override.
 * A per-route `false` disables transitions even when the router default is on.
 */
export declare const resolveViewTransition: (routerConfig: boolean | ViewTransitionConfig | undefined, newChain: MatchChainEntry[]) => ViewTransitionConfig | false;
/**
 * A nested router component that supports hierarchical route definitions
 * with parent/child relationships. Parent routes receive an `outlet` prop
 * containing the rendered child route, enabling layout composition.
 *
 * Routes are defined as a Record where keys are URL patterns (following the
 * RestApi pattern). The matching algorithm builds a chain from outermost to
 * innermost route, then renders inside-out so each parent wraps its child.
 *
 * The router subscribes to path, query string and hash changes; path-level
 * changes drive `onLeave` / `onVisit` lifecycle hooks while query / hash
 * changes re-render the chain without firing lifecycle callbacks.
 */
export declare const NestedRouter: (props: NestedRouterProps & Omit<Partial<HTMLElement>, "style"> & {
    style?: Partial<CSSStyleDeclaration>;
} & {
    ref?: import("../models/render-options.js").RefObject<Element>;
}, children?: import("../index.js").ChildrenList) => JSX.Element;
//# sourceMappingURL=nested-router.d.ts.map