33from __future__ import annotations
44
55from dataclasses import dataclass , replace
6+ from logging import getLogger
67from pathlib import Path
7- from typing import Any , Callable , Iterator , Sequence , TypeVar
8+ from typing import Any , Callable , Iterator , Literal , Sequence , TypeVar
89from urllib .parse import parse_qs
910
1011from reactpy import (
2425
2526from reactpy_router .types import Route , RouteCompiler , Router , RouteResolver
2627
28+ _logger = getLogger (__name__ )
2729R = TypeVar ("R" , bound = Route )
2830
2931
@@ -35,18 +37,19 @@ def route(path: str, element: Any | None, *routes: Route) -> Route:
3537def create_router (compiler : RouteCompiler [R ]) -> Router [R ]:
3638 """A decorator that turns a route compiler into a router"""
3739
38- def wrapper (* routes : R ) -> ComponentType :
39- return router_component (* routes , compiler = compiler )
40+ def wrapper (* routes : R , select : Literal [ "first" , "all" ] = "first" ) -> ComponentType :
41+ return router_component (* routes , select = select , compiler = compiler )
4042
4143 return wrapper
4244
4345
4446@component
4547def router_component (
4648 * routes : R ,
49+ select : Literal ["first" , "all" ],
4750 compiler : RouteCompiler [R ],
4851) -> VdomDict | None :
49- """A component that renders the first matching route using the given compiler"""
52+ """A component that renders matching route(s) using the given compiler function. """
5053
5154 old_conn = use_connection ()
5255 location , set_location = use_state (old_conn .location )
@@ -56,7 +59,7 @@ def router_component(
5659 dependencies = (compiler , hash (routes )),
5760 )
5861
59- match = use_memo (lambda : _match_route (resolvers , location ))
62+ match = use_memo (lambda : _match_route (resolvers , location , select ))
6063
6164 if match is not None :
6265 element , params = match
@@ -128,12 +131,22 @@ def _iter_routes(routes: Sequence[R]) -> Iterator[R]:
128131 yield parent
129132
130133
131- def _match_route (compiled_routes : Sequence [RouteResolver ], location : Location ) -> tuple [Any , dict [str , Any ]] | None :
134+ def _match_route (
135+ compiled_routes : Sequence [RouteResolver ], location : Location , select : Literal ["first" , "all" ]
136+ ) -> tuple [Any , dict [str , Any ]] | None :
137+ matches = []
138+
132139 for resolver in compiled_routes :
133140 match = resolver .resolve (location .pathname )
134141 if match is not None :
135- return match
136- return None
142+ if select == "first" :
143+ return match
144+ matches .append (match )
145+
146+ if not matches :
147+ _logger .debug ("No matching route found for %s" , location .pathname )
148+
149+ return matches or None
137150
138151
139152_link , _history = export (
0 commit comments