Repository: Rezact/Rezact
Pull request #90 (2024-01-15 22:29:26)

Fix hashtag routes


Patch:
diff --git a/package.json b/package.json
index 85277bd..b57829b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@rezact/rezact",
-  "version": "1.0.15-beta.37",
+  "version": "1.0.15-beta.38",
   "type": "module",
   "description": "Intuitive Reactivity, Simplified State. Embrace a modern UI framework that encourages direct data mutations, offers module-level reactivity, and simplifies component design. With Rezact, you get the power of reactivity without the boilerplate. Dive into a seamless development experience tailored for today's web.",
   "main": "index.cjs",
diff --git a/src/examples/Layout/nestedLayout.tsx b/src/examples/Layout/nestedLayout.tsx
index d5377ba..fc5fb5b 100644
--- a/src/examples/Layout/nestedLayout.tsx
+++ b/src/examples/Layout/nestedLayout.tsx
@@ -5,7 +5,7 @@ export function MyLayout({ router }: routerProp) {
   const { $route } = router;
   return (
     <MasterLayout>
-      <h1>Layout</h1>
+      <h1 id="testing-hashroute">Layout</h1>
       <ul>
         <li class={$route === "/" ? "active" : ""}>
           <a href="/">Home</a>
@@ -174,6 +174,12 @@ export function MyLayout({ router }: routerProp) {
         <li>
           <a href="/asdfasdfasdfasdf">A Route that does not exist</a>
         </li>
+
+        <hr />
+
+        <li>
+          <a href="#testing-hashroute">Hashtag route</a>
+        </li>
       </ul>
       <button onClick={() => router.back()}>Back</button>
       <button onClick={() => router.forward()}>Forward</button>
diff --git a/src/lib/rezact/router.ts b/src/lib/rezact/router.ts
index b7a36c6..b37ee2e 100644
--- a/src/lib/rezact/router.ts
+++ b/src/lib/rezact/router.ts
@@ -125,6 +125,7 @@ export class TrieRouter {
     if (options.noRoute) this.noRoute = options.noRoute;
     document.body.addEventListener("click", (ev: any) => {
       if (ev.target.nodeName === "A") {
+        if (ev.target.href.includes("#")) return;
         if (!ev.target.href) return;
         if (ev.target.target) return;
         const url = new URL(ev.target.href);


Test patch:
diff --git a/src/router.test.js b/src/router.test.js
index 3f86ad5..9aa3afb 100644
--- a/src/router.test.js
+++ b/src/router.test.js
@@ -765,16 +765,19 @@ describe("Router Tests Suite", () => {
   const beforeEachGuardTest = {
     guard1: false,
     guard2: false,
+    count: 0,
   };
 
   it("Route Guard redirects", async () => {
     router.beforeEach(async (to, from) => {
+      beforeEachGuardTest.count++;
       beforeEachGuardTest.guard1 = true;
       expect(from.pathname).toBe("/simple-string-list");
       expect(to.pathname).toBe("/simple-string-list");
       return "/login";
     });
     router.beforeEach(async (to, from) => {
+      beforeEachGuardTest.count++;
       beforeEachGuardTest.guard2 = true;
       expect(from.pathname).toBe("/simple-string-list");
       expect(to.pathname).toBe("/simple-string-list");
@@ -792,6 +795,7 @@ describe("Router Tests Suite", () => {
 
     expect(beforeEachGuardTest.guard1).toBe(true);
     expect(beforeEachGuardTest.guard2).toBe(false);
+    expect(beforeEachGuardTest.count).toBe(1);
   });
 
   it("Route Guard Reverts - Simple String List Route", async () => {
@@ -808,6 +812,7 @@ describe("Router Tests Suite", () => {
 
   it("Route Guard Cancels Navigation - Simple String List Route", async () => {
     router.beforeEach((to, from) => {
+      beforeEachGuardTest.count++;
       expect(to.pathname).toBe("/data-fetching");
       expect(from.pathname).toBe("/simple-string-list");
       return false;
@@ -822,6 +827,23 @@ describe("Router Tests Suite", () => {
     const routerOutlet = document.getElementById("router-outlet-test");
     expect(routerOutlet.innerHTML).toMatchSnapshot();
     router.beforeHooks = [];
+    router.beforeEach(async (to, from) => {
+      beforeEachGuardTest.count++;
+      return to.pathname;
+    });
+    expect(beforeEachGuardTest.count).toBe(2);
+  });
+
+  it("Hashtag in route bypasses router behavior (allows browser to scroll)", async () => {
+    expect(location.href).toBe("http://localhost:3000/simple-string-list");
+    const links = await screen.findAllByRole("link", {
+      name: /Hashtag route/i,
+    });
+    expect(links[0]._url.hash).toBe("#testing-hashroute");
+    await user.click(links[0]);
+    await delay(100);
+    expect(location.href).toBe("http://localhost:3000/simple-string-list");
+    expect(beforeEachGuardTest.count).toBe(2);
   });
 
   it("Router afterEach Hook", async () => {
@@ -838,6 +860,8 @@ describe("Router Tests Suite", () => {
 
     expect(router.currentRoute.pathname).toBe("/data-fetching");
     router.afterHooks = [];
+    expect(beforeEachGuardTest.count).toBe(3);
+    console.log(beforeEachGuardTest);
   });
 });