Skip to content

Commit f52aaa3

Browse files
committed
Remove core.py
1 parent 1b8031b commit f52aaa3

File tree

7 files changed

+233
-234
lines changed

7 files changed

+233
-234
lines changed

src/reactpy_router/__init__.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,15 @@
22
__version__ = "0.1.1"
33

44

5-
from .converters import CONVERTERS
6-
from .core import (
7-
create_router,
8-
link,
9-
route,
10-
use_params,
11-
use_search_params,
12-
)
13-
from .resolvers import Resolver
14-
from .routers import browser_router
15-
from .types import Route, RouteCompiler, RouteResolver
5+
from .components import link, route
6+
from .hooks import use_params, use_search_params
7+
from .routers import browser_router, create_router
168

179
__all__ = (
1810
"create_router",
1911
"link",
2012
"route",
21-
"Route",
22-
"RouteCompiler",
23-
"RouteResolver",
2413
"browser_router",
2514
"use_params",
2615
"use_search_params",
27-
"Resolver",
28-
"CONVERTERS",
2916
)

src/reactpy_router/components.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
from typing import Any
5+
from uuid import uuid4
6+
7+
from reactpy import component, html
8+
from reactpy.backend.types import Location
9+
from reactpy.core.types import VdomChild, VdomDict
10+
from reactpy.web.module import export, module_from_file
11+
12+
from reactpy_router.hooks import _use_route_state
13+
from reactpy_router.types import Route
14+
15+
History = export(
16+
module_from_file("reactpy-router", file=Path(__file__).parent / "static" / "bundle.js"),
17+
("History"),
18+
)
19+
link_js_content = (Path(__file__).parent / "static" / "link.js").read_text(encoding="utf-8")
20+
21+
22+
@component
23+
def link(*children: VdomChild, to: str, **attributes: Any) -> VdomDict:
24+
"""A component that renders a link to the given path."""
25+
# FIXME: This currently works in a "dumb" way by trusting that ReactPy's script tag \
26+
# properly sets the location. When a client-server communication layer is added to a \
27+
# future ReactPy release, this component will need to be rewritten to use that instead. \
28+
set_location = _use_route_state().set_location
29+
uuid = uuid4().hex
30+
31+
def on_click(_event: dict[str, Any]) -> None:
32+
pathname, search = to.split("?", 1) if "?" in to else (to, "")
33+
if search:
34+
search = f"?{search}"
35+
set_location(Location(pathname, search))
36+
37+
attrs = {
38+
**attributes,
39+
"href": to,
40+
"onClick": on_click,
41+
"id": uuid,
42+
}
43+
return html._(html.a(attrs, *children), html.script(link_js_content.replace("UUID", uuid)))
44+
45+
46+
def route(path: str, element: Any | None, *routes: Route) -> Route:
47+
"""Create a route with the given path, element, and child routes."""
48+
return Route(path, element, routes)

src/reactpy_router/core.py

Lines changed: 0 additions & 199 deletions
This file was deleted.

src/reactpy_router/hooks.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from __future__ import annotations
2+
3+
from dataclasses import dataclass
4+
from typing import Any, Callable
5+
from urllib.parse import parse_qs
6+
7+
from reactpy import (
8+
create_context,
9+
use_context,
10+
use_location,
11+
)
12+
from reactpy.backend.types import Location
13+
from reactpy.types import Context
14+
15+
16+
@dataclass
17+
class _RouteState:
18+
set_location: Callable[[Location], None]
19+
params: dict[str, Any]
20+
21+
22+
def _use_route_state() -> _RouteState:
23+
route_state = use_context(_route_state_context)
24+
if route_state is None:
25+
raise RuntimeError(
26+
"ReactPy-Router was unable to find a route context. Are you "
27+
"sure this hook/component is being called within a router?"
28+
)
29+
30+
return route_state
31+
32+
33+
_route_state_context: Context[_RouteState | None] = create_context(None)
34+
35+
36+
def use_params() -> dict[str, Any]:
37+
"""The `use_params` hook returns an object of key/value pairs of the dynamic parameters \
38+
from the current URL that were matched by the `Route`. Child routes inherit all parameters \
39+
from their parent routes.
40+
41+
For example, if you have a `URL_PARAM` defined in the route `/example/<URL_PARAM>/`,
42+
this hook will return the URL_PARAM value that was matched."""
43+
44+
# TODO: Check if this returns all parent params
45+
return _use_route_state().params
46+
47+
48+
def use_search_params(
49+
keep_blank_values: bool = False,
50+
strict_parsing: bool = False,
51+
errors: str = "replace",
52+
max_num_fields: int | None = None,
53+
separator: str = "&",
54+
) -> dict[str, list[str]]:
55+
"""
56+
The `use_search_params` hook is used to read and modify the query string in the URL \
57+
for the current location. Like React's own `use_state` hook, `use_search_params` returns \
58+
an array of two values: the current location's search parameters and a function that may \
59+
be used to update them.
60+
61+
See `urllib.parse.parse_qs` for info on this hook's parameters."""
62+
63+
# FIXME: This needs to return a tuple of the search params and a function to update them
64+
return parse_qs(
65+
use_location().search[1:],
66+
keep_blank_values=keep_blank_values,
67+
strict_parsing=strict_parsing,
68+
errors=errors,
69+
max_num_fields=max_num_fields,
70+
separator=separator,
71+
)

src/reactpy_router/resolvers.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
from reactpy_router.converters import CONVERTERS
77
from reactpy_router.types import ConversionInfo, ConverterMapping, Route
88

9-
__all__ = ["Resolver"]
9+
__all__ = ["StarletteResolver"]
1010

1111

12-
class Resolver:
13-
"""A simple route resolver that uses regex to match paths."""
12+
class StarletteResolver:
13+
"""URL resolver that matches routes that match the starlette URL routing syntax.
14+
15+
However, we add a few additional parameter types on top of Starlette's syntax."""
1416

1517
def __init__(
1618
self,
@@ -21,7 +23,6 @@ def __init__(
2123
self.element = route.element
2224
self.registered_converters = converters or CONVERTERS
2325
self.converter_mapping: ConverterMapping = {}
24-
# self.match_any_indentifier = match_any_identifier
2526
self.param_regex = re.compile(param_pattern)
2627
self.pattern = self.parse_path(route.path)
2728
self.key = self.pattern.pattern # Unique identifier for ReactPy rendering

0 commit comments

Comments
 (0)