11from __future__ import annotations
2- from dataclasses import dataclass
32
3+ import re
4+ from dataclasses import dataclass
45from fnmatch import translate as fnmatch_translate
56from pathlib import Path
6- import re
7- from typing import Any , Iterator , Protocol , Callable , Sequence
7+ from typing import Any , Callable , Iterator , Protocol , Sequence
88
9- from idom import create_context , component , use_context , use_state
10- from idom .web . module import export , module_from_file
11- from idom .core .vdom import coalesce_attributes_and_children , VdomAttributesAndChildren
9+ from idom import component , create_context , use_context , use_state
10+ from idom .core . types import VdomAttributesAndChildren , VdomDict
11+ from idom .core .vdom import coalesce_attributes_and_children
1212from idom .types import BackendImplementation , ComponentType , Context , Location
13+ from idom .web .module import export , module_from_file
1314
1415
15- class Router (Protocol ):
16+ class Routes (Protocol ):
1617 def __call__ (self , * routes : Route ) -> ComponentType :
1718 ...
1819
1920
20- def bind (backend : BackendImplementation ) -> Router :
21+ def configure (
22+ implementation : BackendImplementation [Any ] | Callable [[], Location ]
23+ ) -> Routes :
24+ if isinstance (implementation , BackendImplementation ):
25+ use_location = implementation .use_location
26+ elif callable (implementation ):
27+ use_location = implementation
28+ else :
29+ raise TypeError (
30+ "Expected a BackendImplementation or "
31+ f"`use_location` hook, not { implementation } "
32+ )
33+
2134 @component
22- def Router (* routes : Route ):
23- initial_location = backend . use_location ()
35+ def Router (* routes : Route ) -> ComponentType | None :
36+ initial_location = use_location ()
2437 location , set_location = use_state (initial_location )
2538 for p , r in _compile_routes (routes ):
26- if p .match (location .pathname ):
39+ match = p .match (location .pathname )
40+ if match :
2741 return _LocationStateContext (
2842 r .element ,
29- value = (location , set_location ),
30- key = r . path ,
43+ value = _LocationState (location , set_location , match ),
44+ key = p . pattern ,
3145 )
3246 return None
3347
3448 return Router
3549
3650
37- def use_location () -> str :
38- return _use_location_state ()[0 ]
51+ def use_location () -> Location :
52+ return _use_location_state ().location
53+
54+
55+ def use_match () -> re .Match [str ]:
56+ return _use_location_state ().match
3957
4058
4159@dataclass
4260class Route :
43- path : str | re .Pattern
61+ path : str | re .Pattern [ str ]
4462 element : Any
4563
4664
4765@component
48- def Link (* attributes_or_children : VdomAttributesAndChildren , to : str ) -> None :
66+ def Link (* attributes_or_children : VdomAttributesAndChildren , to : str ) -> VdomDict :
4967 attributes , children = coalesce_attributes_and_children (attributes_or_children )
50- set_location = _use_location_state ()[1 ]
51- return _Link (
52- {
53- ** attributes ,
54- "to" : to ,
55- "onClick" : lambda event : set_location (Location (** event )),
56- },
57- * children ,
58- )
59-
60-
61- def _compile_routes (routes : Sequence [Route ]) -> Iterator [tuple [re .Pattern , Route ]]:
68+ set_location = _use_location_state ().set_location
69+ attrs = {
70+ ** attributes ,
71+ "to" : to ,
72+ "onClick" : lambda event : set_location (Location (** event )),
73+ }
74+ return _Link (attrs , * children )
75+
76+
77+ def _compile_routes (routes : Sequence [Route ]) -> Iterator [tuple [re .Pattern [str ], Route ]]:
6278 for r in routes :
6379 if isinstance (r .path , re .Pattern ):
6480 yield r .path , r
@@ -75,9 +91,14 @@ def _use_location_state() -> _LocationState:
7591 return location_state
7692
7793
78- _LocationSetter = Callable [[str ], None ]
79- _LocationState = tuple [Location , _LocationSetter ]
80- _LocationStateContext : type [Context [_LocationState | None ]] = create_context (None )
94+ @dataclass
95+ class _LocationState :
96+ location : Location
97+ set_location : Callable [[Location ], None ]
98+ match : re .Match [str ]
99+
100+
101+ _LocationStateContext : Context [_LocationState | None ] = create_context (None )
81102
82103_Link = export (
83104 module_from_file (
0 commit comments