1
1
from __future__ import annotations
2
- from dataclasses import dataclass
3
2
3
+ import re
4
+ from dataclasses import dataclass
4
5
from fnmatch import translate as fnmatch_translate
5
6
from pathlib import Path
6
- import re
7
- from typing import Any , Iterator , Protocol , Callable , Sequence
7
+ from typing import Any , Callable , Iterator , Sequence
8
8
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
12
12
from idom .types import BackendImplementation , ComponentType , Context , Location
13
+ from idom .web .module import export , module_from_file
13
14
15
+ try :
16
+ from typing import Protocol
17
+ except ImportError :
18
+ from typing_extensions import Protocol
14
19
15
- class Router (Protocol ):
20
+
21
+ class Routes (Protocol ):
16
22
def __call__ (self , * routes : Route ) -> ComponentType :
17
23
...
18
24
19
25
20
- def bind (backend : BackendImplementation ) -> Router :
26
+ def configure (
27
+ implementation : BackendImplementation [Any ] | Callable [[], Location ]
28
+ ) -> Routes :
29
+ if isinstance (implementation , BackendImplementation ):
30
+ use_location = implementation .use_location
31
+ elif callable (implementation ):
32
+ use_location = implementation
33
+ else :
34
+ raise TypeError (
35
+ "Expected a BackendImplementation or "
36
+ f"`use_location` hook, not { implementation } "
37
+ )
38
+
21
39
@component
22
- def Router (* routes : Route ):
23
- initial_location = backend . use_location ()
40
+ def Router (* routes : Route ) -> ComponentType | None :
41
+ initial_location = use_location ()
24
42
location , set_location = use_state (initial_location )
25
43
for p , r in _compile_routes (routes ):
26
- if p .match (location .pathname ):
44
+ match = p .match (location .pathname )
45
+ if match :
27
46
return _LocationStateContext (
28
47
r .element ,
29
- value = (location , set_location ),
30
- key = r . path ,
48
+ value = _LocationState (location , set_location , match ),
49
+ key = p . pattern ,
31
50
)
32
51
return None
33
52
34
53
return Router
35
54
36
55
37
- def use_location () -> str :
38
- return _use_location_state ()[0 ]
56
+ def use_location () -> Location :
57
+ return _use_location_state ().location
58
+
59
+
60
+ def use_match () -> re .Match [str ]:
61
+ return _use_location_state ().match
39
62
40
63
41
64
@dataclass
42
65
class Route :
43
- path : str | re .Pattern
66
+ path : str | re .Pattern [ str ]
44
67
element : Any
45
68
46
69
47
70
@component
48
- def Link (* attributes_or_children : VdomAttributesAndChildren , to : str ) -> None :
71
+ def Link (* attributes_or_children : VdomAttributesAndChildren , to : str ) -> VdomDict :
49
72
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 ]]:
73
+ set_location = _use_location_state ().set_location
74
+ attrs = {
75
+ ** attributes ,
76
+ "to" : to ,
77
+ "onClick" : lambda event : set_location (Location (** event )),
78
+ }
79
+ return _Link (attrs , * children )
80
+
81
+
82
+ def _compile_routes (routes : Sequence [Route ]) -> Iterator [tuple [re .Pattern [str ], Route ]]:
62
83
for r in routes :
63
84
if isinstance (r .path , re .Pattern ):
64
85
yield r .path , r
@@ -75,9 +96,14 @@ def _use_location_state() -> _LocationState:
75
96
return location_state
76
97
77
98
78
- _LocationSetter = Callable [[str ], None ]
79
- _LocationState = tuple [Location , _LocationSetter ]
80
- _LocationStateContext : type [Context [_LocationState | None ]] = create_context (None )
99
+ @dataclass
100
+ class _LocationState :
101
+ location : Location
102
+ set_location : Callable [[Location ], None ]
103
+ match : re .Match [str ]
104
+
105
+
106
+ _LocationStateContext : Context [_LocationState | None ] = create_context (None )
81
107
82
108
_Link = export (
83
109
module_from_file (
0 commit comments