55from typing import Any , Callable , Iterator , Sequence
66from urllib .parse import parse_qs
77
8- from idom import component , create_context , use_context , use_memo , use_state
8+ from idom import (
9+ component ,
10+ create_context ,
11+ use_memo ,
12+ use_state ,
13+ use_context ,
14+ use_location ,
15+ )
916from idom .core .types import VdomAttributesAndChildren , VdomDict
1017from idom .core .vdom import coalesce_attributes_and_children
11- from idom .types import ComponentType , Context , Location
18+ from idom .types import ComponentType , Location , Context
1219from idom .web .module import export , module_from_file
20+ from idom .backend .hooks import ConnectionContext , use_connection
21+ from idom .backend .types import Connection , Location
1322from starlette .routing import compile_path as _compile_starlette_path
1423
1524from idom_router .types import RoutePattern , RouteCompiler , Route
1625
17- try :
18- from typing import Protocol
19- except ImportError : # pragma: no cover
20- from typing_extensions import Protocol # type: ignore
21-
2226
2327def compile_starlette_route (route : str ) -> RoutePattern :
2428 pattern , _ , converters = _compile_starlette_path (route )
@@ -30,25 +34,29 @@ def router(
3034 * routes : Route ,
3135 compiler : RouteCompiler = compile_starlette_route ,
3236) -> ComponentType | None :
33- initial_location = use_location ()
34- location , set_location = use_state (initial_location )
37+ old_conn = use_connection ()
38+ location , set_location = use_state (old_conn .location )
39+
3540 compiled_routes = use_memo (
3641 lambda : [(compiler (r ), e ) for r , e in _iter_routes (routes )],
3742 dependencies = routes ,
3843 )
3944 for compiled_route , element in compiled_routes :
4045 match = compiled_route .pattern .match (location .pathname )
4146 if match :
42- return _LocationStateContext (
43- element ,
44- value = _LocationState (
45- location ,
46- set_location ,
47- {
48- k : compiled_route .converters [k ](v )
49- for k , v in match .groupdict ().items ()
50- },
47+ convs = compiled_route .converters
48+ return ConnectionContext (
49+ _route_state_context (
50+ element ,
51+ value = _RouteState (
52+ set_location ,
53+ {
54+ k : convs [k ](v ) if k in convs else v
55+ for k , v in match .groupdict ().items ()
56+ },
57+ ),
5158 ),
59+ value = Connection (old_conn .scope , location , old_conn .carrier ),
5260 key = compiled_route .pattern .pattern ,
5361 )
5462 return None
@@ -57,23 +65,18 @@ def router(
5765@component
5866def link (* attributes_or_children : VdomAttributesAndChildren , to : str ) -> VdomDict :
5967 attributes , children = coalesce_attributes_and_children (attributes_or_children )
60- set_location = _use_location_state ().set_location
68+ set_location = _use_route_state ().set_location
6169 attrs = {
6270 ** attributes ,
6371 "to" : to ,
6472 "onClick" : lambda event : set_location (Location (** event )),
6573 }
66- return _Link (attrs , * children )
67-
68-
69- def use_location () -> Location :
70- """Get the current route location"""
71- return _use_location_state ().location
74+ return _link (attrs , * children )
7275
7376
7477def use_params () -> dict [str , Any ]:
7578 """Get parameters from the currently matching route pattern"""
76- return _use_location_state ( ).params
79+ return use_context ( _route_state_context ).params
7780
7881
7982def use_query (
@@ -94,29 +97,27 @@ def use_query(
9497 )
9598
9699
100+ def _use_route_state () -> _RouteState :
101+ return use_context (_route_state_context )
102+
103+
97104def _iter_routes (routes : Sequence [Route ]) -> Iterator [tuple [str , Any ]]:
98105 for r in routes :
99106 for path , element in _iter_routes (r .routes ):
100107 yield r .path + path , element
101108 yield r .path , r .element
102109
103110
104- def _use_location_state () -> _LocationState :
105- location_state = use_context ( _LocationStateContext )
106- assert location_state is not None , "No location state. Did you use a Router?"
107- return location_state
111+ _link = export (
112+ module_from_file ( "idom-router" , file = Path ( __file__ ). parent / "bundle.js" ),
113+ "Link" ,
114+ )
108115
109116
110117@dataclass
111- class _LocationState :
112- location : Location
118+ class _RouteState :
113119 set_location : Callable [[Location ], None ]
114120 params : dict [str , Any ]
115121
116122
117- _LocationStateContext : Context [_LocationState | None ] = create_context (None )
118-
119- _Link = export (
120- module_from_file ("idom-router" , file = Path (__file__ ).parent / "bundle.js" ),
121- "Link" ,
122- )
123+ _route_state_context : Context [_RouteState | None ] = create_context (None )
0 commit comments