Skip to content

New Navigate component #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a4e90aa
Fix docs publishing
Archmonger Oct 14, 2024
491027d
functional navigate component
Archmonger Oct 15, 2024
cac297b
Better fix for key identity of route components
Archmonger Oct 15, 2024
e730eea
Add tests for navigate component
Archmonger Oct 15, 2024
831aa20
Add comments to javascript
Archmonger Oct 15, 2024
c126be9
Temporary fix for `History`'s first load behavior
Archmonger Oct 15, 2024
eee3a87
Longer test delays
Archmonger Oct 15, 2024
b50afd4
Fix `test_router` failures
Archmonger Oct 15, 2024
d0ac25b
Fix coverage
Archmonger Oct 15, 2024
7ff7427
Increase click delay again
Archmonger Oct 15, 2024
9bf48f4
Move first load component to the bottom
Archmonger Oct 15, 2024
66bef6a
Run coverage on python 3.11
Archmonger Oct 15, 2024
53cdb9e
More clear comment on _match_route
Archmonger Oct 15, 2024
6e64956
Update changelog
Archmonger Oct 15, 2024
c8e06fb
Fix tests on windows
Archmonger Oct 15, 2024
fb69cef
simplify test_browser_popstate
Archmonger Oct 15, 2024
8875643
Attempt fix for flakey tests: add sleep before each `go_back` action
Archmonger Oct 16, 2024
698eed9
Attempt fix for flakey tests: Check if new page already exists before…
Archmonger Oct 16, 2024
e1c442a
more comments
Archmonger Oct 16, 2024
7c169b0
Add python 3.12 tests
Archmonger Oct 16, 2024
a6c378f
Attempt decreasing GH delay to 250ms
Archmonger Oct 16, 2024
a8a7d27
Standardize history.pushstate args
Archmonger Oct 16, 2024
364e186
Remove unused pytest arg
Archmonger Oct 16, 2024
0084b56
minor test tweaks
Archmonger Oct 16, 2024
1408d09
add changelog for fixing win tests
Archmonger Oct 16, 2024
109d87b
more robust docs
Archmonger Oct 17, 2024
0e4304c
Format all docs examples
Archmonger Oct 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ jobs:
pip install -r requirements/build-docs.txt
pip install -r requirements/check-types.txt
pip install -r requirements/check-style.txt
pip install -e .
- name: Check docs build
run: |
linkcheckMarkdown docs/ -v -r
Expand Down
70 changes: 35 additions & 35 deletions .github/workflows/test-src.yaml
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
name: Test

on:
push:
branches:
- main
pull_request:
branches:
- main
schedule:
- cron: "0 0 * * *"
push:
branches:
- main
pull_request:
branches:
- main
schedule:
- cron: "0 0 * * *"

jobs:
source:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v4
- name: Use Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Python Dependencies
run: pip install -r requirements/test-run.txt
- name: Run Tests
run: nox -t test
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Latest Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install Python Dependencies
run: pip install -r requirements/test-run.txt
- name: Run Tests
run: nox -t test -- --coverage
source:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Use Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Python Dependencies
run: pip install -r requirements/test-run.txt
- name: Run Tests
run: nox -t test
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Latest Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install Python Dependencies
run: pip install -r requirements/test-run.txt
- name: Run Tests
run: nox -t test -- --coverage
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ Using the following categories, list your changes in this order:
- Rename `CONVERSION_TYPES` to `CONVERTERS`.
- Change "Match Any" syntax from a star `*` to `{name:any}`.
- Rewrite `reactpy_router.link` to be a server-side component.
- Simplified top-level exports within `reactpy_router`.
- Simplified top-level exports that are available within `reactpy_router.*`.

### Added

- New error for ReactPy router elements being used outside router context.
- Configurable/inheritable `Resolver` base class.
- Add debug log message for when there are no router matches.
- Add slug as a supported type.
- Add `reactpy_router.navigate` component that will force the client to navigate to a new URL (when rendered).
- New error for ReactPy router elements being used outside router context.
- Configurable/inheritable `Resolver` base class.

### Fixed

Expand All @@ -58,6 +59,7 @@ Using the following categories, list your changes in this order:
- Fix bug where `link` elements could not have `@component` type children.
- Fix bug where the ReactPy would not detect the current URL after a reconnection.
- Fix bug where `ctrl` + `click` on a `link` element would not open in a new tab.
- Fix test suite on Windows machines.

## [0.1.1] - 2023-12-13

Expand Down
1 change: 1 addition & 0 deletions docs/examples/python/basic-routing-more-routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from reactpy import component, html, run

from reactpy_router import browser_router, route


Expand Down
1 change: 1 addition & 0 deletions docs/examples/python/basic-routing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from reactpy import component, html, run

from reactpy_router import browser_router, route


Expand Down
17 changes: 15 additions & 2 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ nav:
- Hooks: learn/hooks.md
- Creating a Custom Router 🚧: learn/custom-router.md
- Reference:
- Router Components: reference/router.md
- Routers: reference/routers.md
- Components: reference/components.md
- Hooks: reference/hooks.md
- Types: reference/types.md
Expand Down Expand Up @@ -96,8 +96,21 @@ plugins:
- https://reactpy.dev/docs/objects.inv
- https://installer.readthedocs.io/en/stable/objects.inv
options:
show_bases: false
signature_crossrefs: true
scoped_crossrefs: true
relative_crossrefs: true
modernize_annotations: true
unwrap_annotated: true
find_stubs_package: true
show_root_members_full_path: true
show_bases: false
show_source: false
show_root_toc_entry: false
show_labels: false
show_symbol_type_toc: true
show_symbol_type_heading: true
show_object_full_path: true
heading_level: 3
extra:
generator: false
version:
Expand Down
1 change: 1 addition & 0 deletions docs/src/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ misconfiguration
misconfigurations
backhaul
sublicense
contravariant
2 changes: 1 addition & 1 deletion docs/src/reference/components.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
::: reactpy_router

options:
members: ["route", "link"]
members: ["route", "link", "navigate"]
File renamed without changes.
4 changes: 4 additions & 0 deletions docs/src/reference/types.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
::: reactpy_router.types

options:
summary: true
docstring_section_style: "list"
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ line-length = 120

[tool.pytest.ini_options]
testpaths = "tests"
asyncio_mode = "auto"
2 changes: 2 additions & 0 deletions requirements/build-docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ mkdocs-minify-plugin
mkdocs-section-index
mike
mkdocstrings[python]
black # for mkdocstrings automatic code formatting
.
2 changes: 1 addition & 1 deletion requirements/test-env.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
twine
pytest
pytest-asyncio
anyio
pytest-cov
reactpy[testing,starlette]
nodejs-bin==18.4.0a4
106 changes: 88 additions & 18 deletions src/js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@ export function bind(node) {
};
}

export function History({ onHistoryChange }) {
// Capture browser "history go back" action and tell the server about it
// Note: Browsers do not allow us to detect "history go forward" actions.
/**
* History component that captures browser "history go back" actions and notifies the server.
*
* @param {Object} props - The properties object.
* @param {Function} props.onHistoryChangeCallback - Callback function to notify the server about history changes.
* @returns {null} This component does not render any visible output.
* @description
* This component uses the `popstate` event to detect when the user navigates back in the browser history.
* It then calls the `onHistoryChangeCallback` with the current pathname and search parameters.
* Note: Browsers do not allow detection of "history go forward" actions.
* @see https://github.com/reactive-python/reactpy/pull/1224
*/
export function History({ onHistoryChangeCallback }) {
React.useEffect(() => {
// Register a listener for the "popstate" event and send data back to the server using the `onHistoryChange` callback.
const listener = () => {
onHistoryChange({
onHistoryChangeCallback({
pathname: window.location.pathname,
search: window.location.search,
});
Expand All @@ -32,31 +42,42 @@ export function History({ onHistoryChange }) {
});

// Tell the server about the URL during the initial page load
// FIXME: This currently runs every time any component is mounted due to a ReactPy core rendering bug.
// FIXME: This code is commented out since it currently runs every time any component
// is mounted due to a ReactPy core rendering bug. `FirstLoad` component is used instead.
// https://github.com/reactive-python/reactpy/pull/1224
React.useEffect(() => {
onHistoryChange({
pathname: window.location.pathname,
search: window.location.search,
});
return () => {};
}, []);

// React.useEffect(() => {
// onHistoryChange({
// pathname: window.location.pathname,
// search: window.location.search,
// });
// return () => {};
// }, []);
return null;
}

// FIXME: The Link component is unused due to a ReactPy core rendering bug
// which causes duplicate rendering (and thus duplicate event listeners).
// https://github.com/reactive-python/reactpy/pull/1224
export function Link({ onClick, linkClass }) {
/**
* Link component that captures clicks on anchor links and notifies the server.
*
* @param {Object} props - The properties object.
* @param {Function} props.onClickCallback - Callback function to notify the server about link clicks.
* @param {string} props.linkClass - The class name of the anchor link.
* @returns {null} This component does not render any visible output.
*/
export function Link({ onClickCallback, linkClass }) {
// FIXME: This component is currently unused due to a ReactPy core rendering bug
// which causes duplicate rendering (and thus duplicate event listeners).
// https://github.com/reactive-python/reactpy/pull/1224

// This component is not the actual anchor link.
// It is an event listener for the link component created by ReactPy.
React.useEffect(() => {
// Event function that will tell the server about clicks
const handleClick = (event) => {
event.preventDefault();
let to = event.target.getAttribute("href");
window.history.pushState({}, to, new URL(to, window.location));
onClick({
window.history.pushState(null, "", new URL(to, window.location));
onClickCallback({
pathname: window.location.pathname,
search: window.location.search,
});
Expand All @@ -78,3 +99,52 @@ export function Link({ onClick, linkClass }) {
});
return null;
}

/**
* Client-side portion of the navigate component, that allows the server to command the client to change URLs.
*
* @param {Object} props - The properties object.
* @param {Function} props.onNavigateCallback - Callback function that transmits data to the server.
* @param {string} props.to - The target URL to navigate to.
* @param {boolean} props.replace - If true, replaces the current history entry instead of adding a new one.
* @returns {null} This component does not render anything.
*/
export function Navigate({ onNavigateCallback, to, replace }) {
React.useEffect(() => {
if (replace) {
window.history.replaceState(null, "", new URL(to, window.location));
} else {
window.history.pushState(null, "", new URL(to, window.location));
}
onNavigateCallback({
pathname: window.location.pathname,
search: window.location.search,
});
return () => {};
}, []);

return null;
}

/**
* FirstLoad component that captures the URL during the initial page load and notifies the server.
*
* @param {Object} props - The properties object.
* @param {Function} props.onFirstLoadCallback - Callback function to notify the server about the first load.
* @returns {null} This component does not render any visible output.
* @description
* This component sends the current URL to the server during the initial page load.
* @see https://github.com/reactive-python/reactpy/pull/1224
*/
export function FirstLoad({ onFirstLoadCallback }) {
// FIXME: This component only exists because of a ReactPy core rendering bug, and should be removed when the bug
// is fixed. Ideally all this logic would be handled by the `History` component.
React.useEffect(() => {
onFirstLoadCallback({
pathname: window.location.pathname,
search: window.location.search,
});
return () => {};
}, []);
return null;
}
3 changes: 2 additions & 1 deletion src/reactpy_router/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__version__ = "0.1.1"


from .components import link, route
from .components import link, navigate, route
from .hooks import use_params, use_search_params
from .routers import browser_router, create_router

Expand All @@ -13,4 +13,5 @@
"browser_router",
"use_params",
"use_search_params",
"navigate",
)
Loading