3
3
from __future__ import annotations
4
4
5
5
from dataclasses import dataclass , replace
6
+ from logging import getLogger
6
7
from pathlib import Path
7
- from typing import Any , Callable , Iterator , Sequence , TypeVar
8
+ from typing import Any , Callable , Iterator , Literal , Sequence , TypeVar
8
9
from urllib .parse import parse_qs
9
10
10
11
from reactpy import (
24
25
25
26
from reactpy_router .types import Route , RouteCompiler , Router , RouteResolver
26
27
28
+ _logger = getLogger (__name__ )
27
29
R = TypeVar ("R" , bound = Route )
28
30
29
31
@@ -35,18 +37,19 @@ def route(path: str, element: Any | None, *routes: Route) -> Route:
35
37
def create_router (compiler : RouteCompiler [R ]) -> Router [R ]:
36
38
"""A decorator that turns a route compiler into a router"""
37
39
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 )
40
42
41
43
return wrapper
42
44
43
45
44
46
@component
45
47
def router_component (
46
48
* routes : R ,
49
+ select : Literal ["first" , "all" ],
47
50
compiler : RouteCompiler [R ],
48
51
) -> 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. """
50
53
51
54
old_conn = use_connection ()
52
55
location , set_location = use_state (old_conn .location )
@@ -56,7 +59,7 @@ def router_component(
56
59
dependencies = (compiler , hash (routes )),
57
60
)
58
61
59
- match = use_memo (lambda : _match_route (resolvers , location ))
62
+ match = use_memo (lambda : _match_route (resolvers , location , select ))
60
63
61
64
if match is not None :
62
65
element , params = match
@@ -128,12 +131,22 @@ def _iter_routes(routes: Sequence[R]) -> Iterator[R]:
128
131
yield parent
129
132
130
133
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
+
132
139
for resolver in compiled_routes :
133
140
match = resolver .resolve (location .pathname )
134
141
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
137
150
138
151
139
152
_link , _history = export (
0 commit comments