5
5
from typing import Any , Callable , Iterator , Sequence
6
6
from urllib .parse import parse_qs
7
7
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
+ )
9
16
from idom .core .types import VdomAttributesAndChildren , VdomDict
10
17
from idom .core .vdom import coalesce_attributes_and_children
11
- from idom .types import ComponentType , Context , Location
18
+ from idom .types import ComponentType , Location , Context
12
19
from 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
13
22
from starlette .routing import compile_path as _compile_starlette_path
14
23
15
24
from idom_router .types import RoutePattern , RouteCompiler , Route
16
25
17
- try :
18
- from typing import Protocol
19
- except ImportError : # pragma: no cover
20
- from typing_extensions import Protocol # type: ignore
21
-
22
26
23
27
def compile_starlette_route (route : str ) -> RoutePattern :
24
28
pattern , _ , converters = _compile_starlette_path (route )
@@ -30,25 +34,29 @@ def router(
30
34
* routes : Route ,
31
35
compiler : RouteCompiler = compile_starlette_route ,
32
36
) -> 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
+
35
40
compiled_routes = use_memo (
36
41
lambda : [(compiler (r ), e ) for r , e in _iter_routes (routes )],
37
42
dependencies = routes ,
38
43
)
39
44
for compiled_route , element in compiled_routes :
40
45
match = compiled_route .pattern .match (location .pathname )
41
46
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
+ ),
51
58
),
59
+ value = Connection (old_conn .scope , location , old_conn .carrier ),
52
60
key = compiled_route .pattern .pattern ,
53
61
)
54
62
return None
@@ -57,23 +65,18 @@ def router(
57
65
@component
58
66
def link (* attributes_or_children : VdomAttributesAndChildren , to : str ) -> VdomDict :
59
67
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
61
69
attrs = {
62
70
** attributes ,
63
71
"to" : to ,
64
72
"onClick" : lambda event : set_location (Location (** event )),
65
73
}
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 )
72
75
73
76
74
77
def use_params () -> dict [str , Any ]:
75
78
"""Get parameters from the currently matching route pattern"""
76
- return _use_location_state ( ).params
79
+ return use_context ( _route_state_context ).params
77
80
78
81
79
82
def use_query (
@@ -94,29 +97,27 @@ def use_query(
94
97
)
95
98
96
99
100
+ def _use_route_state () -> _RouteState :
101
+ return use_context (_route_state_context )
102
+
103
+
97
104
def _iter_routes (routes : Sequence [Route ]) -> Iterator [tuple [str , Any ]]:
98
105
for r in routes :
99
106
for path , element in _iter_routes (r .routes ):
100
107
yield r .path + path , element
101
108
yield r .path , r .element
102
109
103
110
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
+ )
108
115
109
116
110
117
@dataclass
111
- class _LocationState :
112
- location : Location
118
+ class _RouteState :
113
119
set_location : Callable [[Location ], None ]
114
120
params : dict [str , Any ]
115
121
116
122
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