Skip to content

Commit 109d87b

Browse files
committed
more robust docs
1 parent 1408d09 commit 109d87b

File tree

9 files changed

+169
-46
lines changed

9 files changed

+169
-46
lines changed

docs/mkdocs.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ nav:
88
- Hooks: learn/hooks.md
99
- Creating a Custom Router 🚧: learn/custom-router.md
1010
- Reference:
11-
- Router Components: reference/router.md
11+
- Routers: reference/routers.md
1212
- Components: reference/components.md
1313
- Hooks: reference/hooks.md
1414
- Types: reference/types.md
@@ -96,8 +96,21 @@ plugins:
9696
- https://reactpy.dev/docs/objects.inv
9797
- https://installer.readthedocs.io/en/stable/objects.inv
9898
options:
99-
show_bases: false
99+
signature_crossrefs: true
100+
scoped_crossrefs: true
101+
relative_crossrefs: true
102+
modernize_annotations: true
103+
unwrap_annotated: true
104+
find_stubs_package: true
100105
show_root_members_full_path: true
106+
show_bases: false
107+
show_source: false
108+
show_root_toc_entry: false
109+
show_labels: false
110+
show_symbol_type_toc: true
111+
show_symbol_type_heading: true
112+
show_object_full_path: true
113+
heading_level: 3
101114
extra:
102115
generator: false
103116
version:

docs/src/dictionary.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ misconfiguration
3737
misconfigurations
3838
backhaul
3939
sublicense
40+
contravariant
File renamed without changes.

docs/src/reference/types.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
::: reactpy_router.types
2+
3+
options:
4+
summary: true
5+
docstring_section_style: "list"

requirements/build-docs.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ mkdocs-minify-plugin
99
mkdocs-section-index
1010
mike
1111
mkdocstrings[python]
12+
black # for mkdocstrings automatic code formatting
1213
.

src/reactpy_router/components.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,21 @@
4141

4242

4343
def link(attributes: dict[str, Any], *children: Any) -> Component:
44-
"""Create a link with the given attributes and children."""
44+
"""
45+
Create a link with the given attributes and children.
46+
47+
Args:
48+
attributes: A dictionary of attributes for the link.
49+
*children: Child elements to be included within the link.
50+
51+
Returns:
52+
A link component with the specified attributes and children.
53+
"""
4554
return _link(attributes, *children)
4655

4756

4857
@component
4958
def _link(attributes: dict[str, Any], *children: Any) -> VdomDict:
50-
"""A component that renders a link to the given path."""
5159
attributes = attributes.copy()
5260
uuid_string = f"link-{uuid4().hex}"
5361
class_name = f"{uuid_string}"
@@ -110,18 +118,39 @@ def on_click(_event: dict[str, Any]) -> None:
110118

111119

112120
def route(path: str, element: Any | None, *routes: Route) -> Route:
113-
"""Create a route with the given path, element, and child routes."""
121+
"""
122+
Create a route with the given path, element, and child routes.
123+
124+
Args:
125+
path: The path for the route.
126+
element: The element to render for this route. Can be None.
127+
routes: Additional child routes.
128+
129+
Returns:
130+
The created route object.
131+
"""
114132
return Route(path, element, routes)
115133

116134

117135
def navigate(to: str, replace: bool = False) -> Component:
118-
"""A `navigate` element changes the current location when it is rendered."""
136+
"""
137+
Navigate to a specified URL.
138+
139+
This function changes the browser's current URL when it is rendered.
140+
141+
Args:
142+
to: The target URL to navigate to.
143+
replace: If True, the current history entry will be replaced \
144+
with the new URL. Defaults to False.
145+
146+
Returns:
147+
The component responsible for navigation.
148+
"""
119149
return _navigate(to, replace)
120150

121151

122152
@component
123153
def _navigate(to: str, replace: bool = False) -> VdomDict | None:
124-
"""A `navigate` element changes the current location when it is rendered."""
125154
location = use_connection().location
126155
set_location = _use_route_state().set_location
127156
pathname = to.split("?", 1)[0]

src/reactpy_router/hooks.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
from __future__ import annotations
22

3-
from dataclasses import dataclass
4-
from typing import Any, Callable
3+
from typing import Any
54
from urllib.parse import parse_qs
65

76
from reactpy import create_context, use_context, use_location
8-
from reactpy.backend.types import Location
97
from reactpy.types import Context
108

9+
from reactpy_router.types import RouteState
1110

12-
@dataclass
13-
class _RouteState:
14-
set_location: Callable[[Location], None]
15-
params: dict[str, Any]
11+
_route_state_context: Context[RouteState | None] = create_context(None)
1612

1713

18-
def _use_route_state() -> _RouteState:
14+
def _use_route_state() -> RouteState:
1915
route_state = use_context(_route_state_context)
2016
if route_state is None: # pragma: no cover
2117
raise RuntimeError(
@@ -26,16 +22,17 @@ def _use_route_state() -> _RouteState:
2622
return route_state
2723

2824

29-
_route_state_context: Context[_RouteState | None] = create_context(None)
30-
31-
3225
def use_params() -> dict[str, Any]:
33-
"""The `use_params` hook returns an object of key/value pairs of the dynamic parameters \
26+
"""This hook returns an object of key/value pairs of the dynamic parameters \
3427
from the current URL that were matched by the `Route`. Child routes inherit all parameters \
3528
from their parent routes.
3629
3730
For example, if you have a `URL_PARAM` defined in the route `/example/<URL_PARAM>/`,
38-
this hook will return the URL_PARAM value that was matched."""
31+
this hook will return the `URL_PARAM` value that was matched.
32+
33+
Returns:
34+
A dictionary of the current URL's parameters.
35+
"""
3936

4037
# TODO: Check if this returns all parent params
4138
return _use_route_state().params
@@ -49,10 +46,14 @@ def use_search_params(
4946
separator: str = "&",
5047
) -> dict[str, list[str]]:
5148
"""
52-
The `use_search_params` hook is used to read the query string in the URL \
53-
for the current location.
49+
This hook is used to read the query string in the URL for the current location.
50+
51+
See [`urllib.parse.parse_qs`](https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qs) \
52+
for info on this hook's parameters.
5453
55-
See `urllib.parse.parse_qs` for info on this hook's parameters."""
54+
Returns:
55+
A dictionary of the current URL's query string parameters.
56+
"""
5657
location = use_location()
5758
query_string = location.search[1:] if len(location.search) > 1 else ""
5859

src/reactpy_router/routers.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
from reactpy import component, use_memo, use_state
1010
from reactpy.backend.hooks import ConnectionContext, use_connection
1111
from reactpy.backend.types import Connection, Location
12+
from reactpy.core.component import Component
1213
from reactpy.types import ComponentType, VdomDict
1314

1415
from reactpy_router.components import FirstLoad, History
15-
from reactpy_router.hooks import _route_state_context, _RouteState
16+
from reactpy_router.hooks import RouteState, _route_state_context
1617
from reactpy_router.resolvers import StarletteResolver
1718
from reactpy_router.types import CompiledRoute, Resolver, Router, RouteType
1819

@@ -23,15 +24,27 @@
2324
def create_router(resolver: Resolver[RouteType]) -> Router[RouteType]:
2425
"""A decorator that turns a resolver into a router"""
2526

26-
def wrapper(*routes: RouteType) -> ComponentType:
27+
def wrapper(*routes: RouteType) -> Component:
2728
return router(*routes, resolver=resolver)
2829

2930
return wrapper
3031

3132

32-
browser_router = create_router(StarletteResolver)
33-
"""This is the recommended router for all ReactPy Router web projects.
34-
It uses the JavaScript DOM History API to manage the history stack."""
33+
_starlette_router = create_router(StarletteResolver)
34+
35+
36+
def browser_router(*routes: RouteType) -> Component:
37+
"""This is the recommended router for all ReactPy-Router web projects.
38+
It uses the JavaScript [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)
39+
to manage the history stack.
40+
41+
Args:
42+
*routes (RouteType): A list of routes to be rendered by the router.
43+
44+
Returns:
45+
A router component that renders the given routes.
46+
"""
47+
return _starlette_router(*routes)
3548

3649

3750
@component
@@ -59,7 +72,7 @@ def router(
5972
route_elements = [
6073
_route_state_context(
6174
element,
62-
value=_RouteState(set_location, params),
75+
value=RouteState(set_location, params),
6376
)
6477
for element, params in match
6578
]

src/reactpy_router/types.py

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,36 @@
55
from dataclasses import dataclass, field
66
from typing import Any, Callable, Sequence, TypedDict, TypeVar
77

8+
from reactpy.backend.types import Location
9+
from reactpy.core.component import Component
810
from reactpy.core.vdom import is_vdom
9-
from reactpy.types import ComponentType, Key
11+
from reactpy.types import Key
1012
from typing_extensions import Protocol, Self, TypeAlias
1113

1214
ConversionFunc: TypeAlias = Callable[[str], Any]
15+
"""A function that converts a string to a specific type."""
16+
1317
ConverterMapping: TypeAlias = dict[str, ConversionFunc]
18+
"""A mapping of conversion types to their respective functions."""
1419

1520

1621
@dataclass(frozen=True)
1722
class Route:
18-
"""A route that can be matched against a path."""
23+
"""
24+
A class representing a route that can be matched against a path.
1925
20-
path: str
21-
"""The path to match against."""
26+
Attributes:
27+
path (str): The path to match against.
28+
element (Any): The element to render if the path matches.
29+
routes (Sequence[Self]): Child routes.
2230
23-
element: Any = field(hash=False)
24-
"""The element to render if the path matches."""
31+
Methods:
32+
__hash__() -> int: Returns a hash value for the route based on its path, element, and child routes.
33+
"""
2534

35+
path: str
36+
element: Any = field(hash=False)
2637
routes: Sequence[Self]
27-
"""Child routes."""
2838

2939
def __hash__(self) -> int:
3040
el = self.element
@@ -33,36 +43,87 @@ def __hash__(self) -> int:
3343

3444

3545
RouteType = TypeVar("RouteType", bound=Route)
46+
"""A type variable for `Route`."""
47+
3648
RouteType_contra = TypeVar("RouteType_contra", bound=Route, contravariant=True)
49+
"""A contravariant type variable for `Route`."""
3750

3851

3952
class Router(Protocol[RouteType_contra]):
40-
"""Return a component that renders the first matching route."""
53+
"""Return a component that renders the matching route(s)."""
54+
55+
def __call__(self, *routes: RouteType_contra) -> Component:
56+
"""
57+
Process the given routes and return a component that renders the matching route(s).
4158
42-
def __call__(self, *routes: RouteType_contra) -> ComponentType: ...
59+
Args:
60+
*routes: A variable number of route arguments.
61+
62+
Returns:
63+
The resulting component after processing the routes.
64+
"""
4365

4466

4567
class Resolver(Protocol[RouteType_contra]):
4668
"""Compile a route into a resolver that can be matched against a given path."""
4769

48-
def __call__(self, route: RouteType_contra) -> CompiledRoute: ...
70+
def __call__(self, route: RouteType_contra) -> CompiledRoute:
71+
"""
72+
Compile a route into a resolver that can be matched against a given path.
73+
74+
Args:
75+
route: The route to compile.
76+
77+
Returns:
78+
The compiled route.
79+
"""
4980

5081

5182
class CompiledRoute(Protocol):
52-
"""A compiled route that can be matched against a path."""
83+
"""
84+
A protocol for a compiled route that can be matched against a path.
85+
86+
Attributes:
87+
key (Key): A property that uniquely identifies this resolver.
88+
"""
5389

5490
@property
55-
def key(self) -> Key:
56-
"""Uniquely identified this resolver."""
91+
def key(self) -> Key: ...
5792

5893
def resolve(self, path: str) -> tuple[Any, dict[str, Any]] | None:
59-
"""Return the path's associated element and path parameters or None."""
94+
"""
95+
Return the path's associated element and path parameters or None.
96+
97+
Args:
98+
path (str): The path to resolve.
99+
100+
Returns:
101+
A tuple containing the associated element and a dictionary of path parameters, or None if the path cannot be resolved.
102+
"""
60103

61104

62105
class ConversionInfo(TypedDict):
63-
"""Information about a conversion type."""
106+
"""
107+
A TypedDict that holds information about a conversion type.
108+
109+
Attributes:
110+
regex (str): The regex to match the conversion type.
111+
func (ConversionFunc): The function to convert the matched string to the expected type.
112+
"""
64113

65114
regex: str
66-
"""The regex to match the conversion type."""
67115
func: ConversionFunc
68-
"""The function to convert the matched string to the expected type."""
116+
117+
118+
@dataclass
119+
class RouteState:
120+
"""
121+
Represents the state of a route in the application.
122+
123+
Attributes:
124+
set_location: A callable to set the location.
125+
params: A dictionary containing route parameters.
126+
"""
127+
128+
set_location: Callable[[Location], None]
129+
params: dict[str, Any]

0 commit comments

Comments
 (0)