Repository: Rezact/Rezact
Pull request #94 (2024-01-16 05:55:02)

fix nested route bug


Patch:
diff --git a/package.json b/package.json
index ee5f37b..5622632 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@rezact/rezact",
-  "version": "1.0.15-beta.42",
+  "version": "1.0.15-beta.43",
   "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/components/appRouter.ts b/src/components/appRouter.ts
index da6a06b..bf7f930 100644
--- a/src/components/appRouter.ts
+++ b/src/components/appRouter.ts
@@ -1,4 +1,4 @@
-import { nestedRoot, useRouter } from "rezact/router";
+import { useRouter } from "rezact/router";
 import { Page as FourOhFour } from "./404";
 import Users from "src/examples/NestedRoutes/Users";
 import UsersId from "src/examples/NestedRoutes/UsersId";
@@ -17,60 +17,66 @@ router.addRoute("/portals", () => import("src/examples/Portals/Portals"));
 
 router.addRoute(
   "/array-state-persistent-across-route-changes",
-  () => import("src/components/HomePageStatePersistsAcrossRouteChanges"),
+  () => import("src/components/HomePageStatePersistsAcrossRouteChanges")
 );
 router.addRoute(
   "/benchmark",
-  () => import("src/examples/BenchmarkRezact/Benchmark"),
+  () => import("src/examples/BenchmarkRezact/Benchmark")
 );
 router.addRoute("/counter", () => import("src/examples/CounterRezact/Counter"));
 router.addRoute(
   "/counter-multiple",
-  () => import("src/examples/CounterMultipleRezact/CounterMultiple"),
+  () => import("src/examples/CounterMultipleRezact/CounterMultiple")
 );
 router.addRoute("/list", () => import("src/examples/ListRezact/List"));
 router.addRoute(
   "/nested",
-  () => import("src/examples/NestedRezact/NestedChildren"),
+  () => import("src/examples/NestedRezact/NestedChildren")
 );
 router.addRoute(
   "/hello-world",
-  () => import("src/examples/HelloWorldRezact/HelloWorld"),
+  () => import("src/examples/HelloWorldRezact/HelloWorld")
 );
+
+router.addRoute(
+  "/hello-world/multiple",
+  () => import("src/examples/HelloWorldMultipleRezact/HelloWorldMultiple")
+);
+
 router.addRoute(
   "/hello-world-multiple",
-  () => import("src/examples/HelloWorldMultipleRezact/HelloWorldMultiple"),
+  () => import("src/examples/HelloWorldMultipleRezact/HelloWorldMultiple")
 );
 router.addRoute("/mdx", () => import("src/components/Test.mdx"));
 
 router.addRoute(
   "/post/:id/something/:test",
-  () => import("src/examples/RouteWithPathParams/index"),
+  () => import("src/examples/RouteWithPathParams/index")
 );
 
 router.addRoute(
   "/shadow-dom",
-  () => import("src/examples/ShadowDom/ShadowDomForExample"),
+  () => import("src/examples/ShadowDom/ShadowDomForExample")
 );
 
 router.addRoute(
   "/data-fetching",
-  () => import("src/examples/DataFetching/DataFetching"),
+  () => import("src/examples/DataFetching/DataFetching")
 );
 
 router.addRoute(
   "/uncontrolled-forms",
-  () => import("src/examples/Forms/UncontrolledForms"),
+  () => import("src/examples/Forms/UncontrolledForms")
 );
 
 router.addRoute(
   "/controlled-forms",
-  () => import("src/examples/Forms/ControlledForms"),
+  () => import("src/examples/Forms/ControlledForms")
 );
 
 router.addRoute(
   "/escape-hatches",
-  () => import("src/examples/EscapeHatches/EscapeHatches"),
+  () => import("src/examples/EscapeHatches/EscapeHatches")
 );
 
 router.addRoute("/todos", () => import("src/examples/Todo/Todo"));
@@ -79,62 +85,44 @@ router.addRoute("/list-redraw", () => import("src/examples/ListReRender/App"));
 
 router.addRoute(
   "/reactive-computations",
-  () => import("src/examples/ReactiveComputations/ReactiveComp"),
+  () => import("src/examples/ReactiveComputations/ReactiveComp")
 );
 
 router.addRoute("/store-test", () => import("src/examples/StoreTest/App"));
 
 router.addRoute(
   "/simple-string-list",
-  () => import("src/examples/SimpleStringListState/SimpleStringList"),
+  () => import("src/examples/SimpleStringListState/SimpleStringList")
 );
 
 router.addRoute(
   "/form-validation",
-  () => import("src/examples/FormValidation/FormValidation"),
+  () => import("src/examples/FormValidation/FormValidation")
 );
 
 router.addRoute(
   "/value-attribute-dot-notation",
-  () => import("src/examples/ValueAttributeDotNotation/ValueAttributeDot"),
+  () => import("src/examples/ValueAttributeDotNotation/ValueAttributeDot")
 );
 
 router.addRoute(
   "/component-context",
-  () => import("src/examples/ComponentContext/ComponentContext"),
+  () => import("src/examples/ComponentContext/ComponentContext")
 );
 
 router.addRoute(
   "/jsx-signals",
-  () => import("src/examples/JsxSignals/JsxSignals"),
+  () => import("src/examples/JsxSignals/JsxSignals")
 );
 
 router.addRoute(
   "/payments/:id",
-  () => import("src/examples/RouteWithPathParams/AmbiguousTest1"),
+  () => import("src/examples/RouteWithPathParams/AmbiguousTest1")
 );
 
 router.addRoute(
   "/payments/ach/:id",
-  () => import("src/examples/RouteWithPathParams/AmbiguousTest2"),
-);
-
-router.addRoute(
-  "/users",
-  () => import("src/examples/NestedRoutes/Users"),
-  nestedRoot,
-);
-router.addRoute(
-  "/users/:id",
-  () => import("src/examples/NestedRoutes/UsersId"),
-);
-router.addRoute(
-  "/users/:id/settings",
-  () => import("src/examples/NestedRoutes/UsersIdSettings"),
-);
-router.addRoute(
-  "/users/:id/settings/*",
-  () => import("src/examples/NestedRoutes/UsersIdSettingsWildCard"),
+  () => import("src/examples/RouteWithPathParams/AmbiguousTest2")
 );
 
 const routes = [
@@ -143,6 +131,33 @@ const routes = [
     component: () => import("src/components/HomePage"),
     title: "Testing Root Title",
   },
+  {
+    path: "/hello-world/multiple/again",
+    component: () =>
+      import("src/examples/SimpleStringListState/SimpleStringList"),
+  },
+  {
+    path: "/users",
+    component: () => import("src/examples/NestedRoutes/Users"),
+    children: [
+      {
+        path: "/:id",
+        component: () => import("src/examples/NestedRoutes/UsersId"),
+        children: [
+          {
+            path: "/settings",
+            component: () =>
+              import("src/examples/NestedRoutes/UsersIdSettings"),
+          },
+          {
+            path: "/settings/*",
+            component: () =>
+              import("src/examples/NestedRoutes/UsersIdSettingsWildCard"),
+          },
+        ],
+      },
+    ],
+  },
   {
     path: "/onBeforeLeave",
     component: () => import("src/examples/OnBeforeLeave/OnBeforeLeave"),
@@ -152,51 +167,58 @@ const routes = [
     path: "/users2",
     component: () => import("src/examples/NestedRoutes/Users"),
     title: "Users Test 2",
-  },
-  {
-    path: "/users2/:id",
-    component: () => import("src/examples/NestedRoutes/UsersId"),
-    title: "Users ID Test 2",
     children: [
       {
-        path: "/settings",
-        component: () => import("src/examples/NestedRoutes/UsersIdSettings"),
-        title: "Users Settings Test 2",
-      },
-      {
-        path: "/settings/*",
-        component: () =>
-          import("src/examples/NestedRoutes/UsersIdSettingsWildCard"),
-        title: "Users Catch AllTest 2",
+        path: "/:id",
+        component: () => import("src/examples/NestedRoutes/UsersId"),
+        title: "Users ID Test 2",
+        children: [
+          {
+            path: "/settings",
+            component: () =>
+              import("src/examples/NestedRoutes/UsersIdSettings"),
+            title: "Users Settings Test 2",
+          },
+          {
+            path: "/settings/*",
+            component: () =>
+              import("src/examples/NestedRoutes/UsersIdSettingsWildCard"),
+            title: "Users Catch AllTest 2",
+          },
+        ],
       },
     ],
   },
+
   {
     path: "/users3",
     component: Users,
     title: "Users Test 3",
     meta: { metaProp: "Users Meta Test 3" },
-  },
-  {
-    path: "/users3/:id",
-    component: UsersId,
-    title: "Users ID Test 3",
-    meta: { metaProp: "Users ID Meta Test 3" },
     children: [
       {
-        path: "/settings",
-        component: UsersIdSettings,
-        title: "Users Settings Test 3",
-        meta: { metaProp: "Users Settings Meta Test 3" },
-      },
-      {
-        path: "/settings/*",
-        component: UsersIdSettingsWildCard,
-        title: "Users Catch AllTest 3",
-        meta: { metaProp: "Users Catch All Meta Test 3" },
+        path: "/:id",
+        component: UsersId,
+        title: "Users ID Test 3",
+        meta: { metaProp: "Users ID Meta Test 3" },
+        children: [
+          {
+            path: "/settings",
+            component: UsersIdSettings,
+            title: "Users Settings Test 3",
+            meta: { metaProp: "Users Settings Meta Test 3" },
+          },
+          {
+            path: "/settings/*",
+            component: UsersIdSettingsWildCard,
+            title: "Users Catch AllTest 3",
+            meta: { metaProp: "Users Catch All Meta Test 3" },
+          },
+        ],
       },
     ],
   },
+
   {
     path: "/payments2",
     children: [
diff --git a/src/examples/Layout/nestedLayout.tsx b/src/examples/Layout/nestedLayout.tsx
index e6768a3..061fc85 100644
--- a/src/examples/Layout/nestedLayout.tsx
+++ b/src/examples/Layout/nestedLayout.tsx
@@ -27,6 +27,16 @@ export function MyLayout({ router }: routerProp) {
         <li class={$route === "/hello-world" ? "active" : ""}>
           <a href="/hello-world">Hello World</a>
         </li>
+        <li>
+          <a href="/hello-world/multiple">
+            Nested Router Bug Hello World Test 1
+          </a>
+        </li>
+        <li>
+          <a href="/hello-world/multiple/again">
+            Nested Router Bug Hello World Test 2
+          </a>
+        </li>
         <li>
           <a href="/hello-world-multiple">Hello World Multiple</a>
         </li>
diff --git a/src/lib/rezact/router.ts b/src/lib/rezact/router.ts
index 1c043ac..09b977d 100644
--- a/src/lib/rezact/router.ts
+++ b/src/lib/rezact/router.ts
@@ -215,22 +215,22 @@ export class TrieRouter {
     this.afterHooks.push(callback);
   }
 
-  addRoutesFromConfig(config, parentPath = "") {
+  addRoutesFromConfig(config, parentPath = "", nestedRoot = true) {
     config.forEach((route) => {
       const currentPath = `${parentPath}${route.path}`;
       if (route.component)
-        this.addRoute(currentPath, route.component, false, {
+        this.addRoute(currentPath, route.component, nestedRoot, {
           title: route.title,
           meta: route.meta,
         });
 
       if (route.children && route.children.length > 0) {
-        this.addRoutesFromConfig(route.children, currentPath);
+        this.addRoutesFromConfig(route.children, currentPath, false);
       }
     });
   }
 
-  addRoute(path, callback, nestedRoot = false, opts: any = {}) {
+  addRoute(path, callback, nestedRoot = true, opts: any = {}) {
     const parts = path.split("/").filter(Boolean);
     let firstPartRootSet = false;
     let currentNode = this.root;


Test patch:
diff --git a/src/__snapshots__/router.test.js.snap b/src/__snapshots__/router.test.js.snap
index 6e45c71..3f8506f 100644
--- a/src/__snapshots__/router.test.js.snap
+++ b/src/__snapshots__/router.test.js.snap
@@ -124,6 +124,10 @@ exports[`Router Tests Suite > JSX Signals 1`] = `
 </div>
 `;
 
+exports[`Router Tests Suite > Loads the /hello-world/multiple (addRoute) nested router bug test 1`] = `"<!--start map--><h1 disabled="">Hello World</h1><h1 disabled="">Hello World</h1><h1 disabled="">Hello World</h1><h1 disabled="">Hello World</h1><span><h1 disabled="">Hello World</h1></span><span><h1 disabled="">Hello World</h1><h1 disabled="">Hello World</h1><h1 disabled="">Hello World</h1></span><h1 disabled="">Hello World</h1><h1 disabled="">Hello World</h1><!--end map-->"`;
+
+exports[`Router Tests Suite > Loads the /hello-world/multiple/again (addRouteFromConfig) nested router bug test 1`] = `"<!--start map--><h1>Simple String List</h1><!--start map--><div dataval="Jack"><input></div><div dataval="Jill"><input></div><div dataval="John"><input></div><div dataval="Jane"><input></div><!--end map--><!--start map--><div>Jack</div><div>Jill</div><div>John</div><div>Jane</div><!--end map--><!--signal--><!--end map-->"`;
+
 exports[`Router Tests Suite > MDX Route 1`] = `
 "<div id="app"><div><h1>Hello World Test asdf</h1></div>
 <!--start map--><div>## apples asdf</div><div>## oranges asdf</div><div>## bananas asdf</div><!--end map-->
diff --git a/src/router.test.js b/src/router.test.js
index 2798005..bb4f80e 100644
--- a/src/router.test.js
+++ b/src/router.test.js
@@ -72,6 +72,26 @@ describe("Router Tests Suite", () => {
     window.dispatchEvent(popstateEvent);
   });
 
+  it("Loads the /hello-world/multiple (addRoute) nested router bug test", async () => {
+    const links = await screen.findAllByRole("link", {
+      name: /Nested Router Bug Hello World Test 1/i,
+    });
+    await user.click(links[0]);
+    await delay(100);
+    const routerOutlet = document.getElementById("router-outlet-test");
+    expect(routerOutlet.innerHTML).toMatchSnapshot();
+  });
+
+  it("Loads the /hello-world/multiple/again (addRouteFromConfig) nested router bug test", async () => {
+    const links = await screen.findAllByRole("link", {
+      name: /Nested Router Bug Hello World Test 2/i,
+    });
+    await user.click(links[0]);
+    await delay(100);
+    const routerOutlet = document.getElementById("router-outlet-test");
+    expect(routerOutlet.innerHTML).toMatchSnapshot();
+  });
+
   it("Loads the counter route", async () => {
     const links = await screen.findAllByRole("link", { name: /Counter/i });
     await user.click(links[0]);