diff --git a/CHANGELOG.md b/CHANGELOG.md index 7380865..f652ffa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,6 @@ Using the following categories, list your changes in this order: ### Changed -- Bump GitHub workflows - Rename `use_query` to `use_search_params`. - Rename `simple.router` to `browser_router`. - Rename `SimpleResolver` to `StarletteResolver`. @@ -58,7 +57,7 @@ Using the following categories, list your changes in this order: - Fix bug where "Match Any" pattern wouldn't work when used in complex or nested paths. - 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. -- Fixed flakey tests on GitHub CI by adding click delays. +- Fix bug where `ctrl` + `click` on a `link` element would not open in a new tab. ## [0.1.1] - 2023-12-13 diff --git a/src/reactpy_router/components.py b/src/reactpy_router/components.py index 3008065..6c023d4 100644 --- a/src/reactpy_router/components.py +++ b/src/reactpy_router/components.py @@ -5,7 +5,7 @@ from urllib.parse import urljoin from uuid import uuid4 -from reactpy import component, event, html, use_connection +from reactpy import component, html, use_connection from reactpy.backend.types import Location from reactpy.core.component import Component from reactpy.core.types import VdomDict @@ -63,8 +63,10 @@ def _link(attributes: dict[str, Any], *children: Any) -> VdomDict: # https://github.com/reactive-python/reactpy/pull/1224 current_path = use_connection().location.pathname - @event(prevent_default=True) def on_click(_event: dict[str, Any]) -> None: + if _event.get("ctrlKey", False): + return + pathname, search = to.split("?", 1) if "?" in to else (to, "") if search: search = f"?{search}" diff --git a/src/reactpy_router/static/link.js b/src/reactpy_router/static/link.js index 0ce08b9..b574201 100644 --- a/src/reactpy_router/static/link.js +++ b/src/reactpy_router/static/link.js @@ -1,8 +1,12 @@ document.querySelector(".UUID").addEventListener( "click", (event) => { - let to = event.target.getAttribute("href"); - window.history.pushState({}, to, new URL(to, window.location)); + // Prevent default if ctrl isn't pressed + if (!event.ctrlKey) { + event.preventDefault(); + let to = event.target.getAttribute("href"); + window.history.pushState({}, to, new URL(to, window.location)); + } }, { once: true }, ); diff --git a/tests/test_core.py b/tests/test_router.py similarity index 93% rename from tests/test_core.py rename to tests/test_router.py index 390236d..d6e0deb 100644 --- a/tests/test_core.py +++ b/tests/test_router.py @@ -1,6 +1,7 @@ import os from typing import Any +from playwright.async_api._generated import Browser, Page from reactpy import Ref, component, html, use_location from reactpy.testing import DisplayFixture @@ -277,3 +278,20 @@ def sample(): _link = await display.page.wait_for_selector("#root") assert "/a" in await _link.get_attribute("href") + + +async def test_ctrl_click(display: DisplayFixture, browser: Browser): + @component + def sample(): + return browser_router( + route("/", link({"to": "/a", "id": "root"}, "Root")), + route("/a", link({"to": "/a", "id": "a"}, "a")), + ) + + await display.show(sample) + + _link = await display.page.wait_for_selector("#root") + await _link.click(delay=CLICK_DELAY, modifiers=["Control"]) + browser_context = browser.contexts[0] + new_page: Page = await browser_context.wait_for_event("page") + await new_page.wait_for_selector("#a")