From 6ec75e894b8e5e07cde7d9d97bab6a6fe5b8fcff Mon Sep 17 00:00:00 2001
From: Zack Tanner <1939140+ztanner@users.noreply.github.com>
Date: Thu, 25 Apr 2024 13:45:31 -0700
Subject: [PATCH] support breadcrumb style catch-all routes
---
.../next/src/server/app-render/app-render.tsx | 17 +++++--
.../app/@slot/[...catchAll]/page.tsx | 12 +++++
.../app/@slot/default.tsx | 3 ++
.../app/[artist]/[album]/[track]/page.tsx | 10 ++++
.../app/[artist]/[album]/page.tsx | 20 ++++++++
.../app/[artist]/page.tsx | 17 +++++++
.../app/layout.tsx | 18 +++++++
.../parallel-routes-breadcrumbs/app/page.tsx | 17 +++++++
.../next.config.js | 6 +++
.../parallel-routes-breadcrumbs.test.ts | 47 +++++++++++++++++++
10 files changed, 163 insertions(+), 4 deletions(-)
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/[...catchAll]/page.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/default.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/[track]/page.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/page.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/page.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/layout.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/app/page.tsx
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/next.config.js
create mode 100644 test/e2e/app-dir/parallel-routes-breadcrumbs/parallel-routes-breadcrumbs.test.ts
diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx
index 95560e8aa8fc3..8a598b6cc3737 100644
--- a/packages/next/src/server/app-render/app-render.tsx
+++ b/packages/next/src/server/app-render/app-render.tsx
@@ -234,15 +234,24 @@ function makeGetDynamicParamFromSegment(
}
if (!value) {
- // Handle case where optional catchall does not have a value, e.g. `/dashboard/[...slug]` when requesting `/dashboard`
- if (segmentParam.type === 'optional-catchall') {
+ // Handle case where optional catchall does not have a value, e.g. `/dashboard/[[...slug]]` when requesting `/dashboard`
+ if (
+ segmentParam.type === 'optional-catchall' ||
+ segmentParam.type === 'catchall'
+ ) {
+ // If we weren't able to match the segment to a URL param, and we have a catch-all route,
+ // provide all of the known params (in array format) to the route
+ // It should be safe to assume the order of these params is consistent with the order of the segments.
+ // However, if not, we could re-parse the `pagePath` with `getRouteRegex` and iterate over the positional order.
+ value = Object.values(params).map((i) => encodeURIComponent(i))
+ const hasValues = value.length > 0
const type = dynamicParamTypes[segmentParam.type]
return {
param: key,
- value: null,
+ value: hasValues ? value : null,
type: type,
// This value always has to be a string.
- treeSegment: [key, '', type],
+ treeSegment: [key, hasValues ? value.join('/') : '', type],
}
}
return findDynamicParamFromRouterState(flightRouterState, segment)
diff --git a/test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/[...catchAll]/page.tsx b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/[...catchAll]/page.tsx
new file mode 100644
index 0000000000000..f9c359f5c0712
--- /dev/null
+++ b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/[...catchAll]/page.tsx
@@ -0,0 +1,12 @@
+export default function Page({ params: { catchAll } }) {
+ return (
+
+
Parallel Route!
+
+
Artist: {catchAll[0]}
+
Album: {catchAll[1] ?? 'Select an album'}
+
Track: {catchAll[2] ?? 'Select a track'}
+
+
+ )
+}
diff --git a/test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/default.tsx b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/default.tsx
new file mode 100644
index 0000000000000..c17431379f962
--- /dev/null
+++ b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/@slot/default.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return null
+}
diff --git a/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/[track]/page.tsx b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/[track]/page.tsx
new file mode 100644
index 0000000000000..c957176c3daf6
--- /dev/null
+++ b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/[track]/page.tsx
@@ -0,0 +1,10 @@
+import Link from 'next/link'
+
+export default function Page({ params }) {
+ return (
+
+
Track: {params.track}
+ Back to album
+
+ )
+}
diff --git a/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/page.tsx b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/page.tsx
new file mode 100644
index 0000000000000..29184ed8c515f
--- /dev/null
+++ b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/[album]/page.tsx
@@ -0,0 +1,20 @@
+import Link from 'next/link'
+
+export default function Page({ params }) {
+ const tracks = ['track1', 'track2', 'track3']
+ return (
+
+
Album: {params.album}
+
+ {tracks.map((track) => (
+
+
+ {track}
+
+
+ ))}
+
+ Back to artist
+
+ )
+}
diff --git a/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/page.tsx b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/page.tsx
new file mode 100644
index 0000000000000..7396f3914b7fd
--- /dev/null
+++ b/test/e2e/app-dir/parallel-routes-breadcrumbs/app/[artist]/page.tsx
@@ -0,0 +1,17 @@
+import Link from 'next/link'
+
+export default function Page({ params }) {
+ const albums = ['album1', 'album2', 'album3']
+ return (
+