diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts index e44ac41896d..9731548cc84 100644 --- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts @@ -31,13 +31,16 @@ import { Route as SearchParamsDefaultRouteImport } from './routes/search-params/ import { Route as RedirectTargetRouteImport } from './routes/redirect/$target' import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' import { Route as LayoutLayout2RouteImport } from './routes/_layout/_layout-2' +import { Route as virtualLayoutBarRouteImport } from './routes/(virtualLayout)/bar' import { Route as groupLazyinsideRouteImport } from './routes/(group)/lazyinside' import { Route as groupInsideRouteImport } from './routes/(group)/inside' import { Route as groupLayoutRouteImport } from './routes/(group)/_layout' import { Route as anotherGroupOnlyrouteinsideRouteImport } from './routes/(another-group)/onlyrouteinside' +import { Route as virtualLayoutQuxRouteRouteImport } from './routes/(virtualLayout)/qux/route' import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index' import { Route as ParamsPsWildcardIndexRouteImport } from './routes/params-ps/wildcard/index' import { Route as ParamsPsNamedIndexRouteImport } from './routes/params-ps/named/index' +import { Route as virtualLayoutBazIndexRouteImport } from './routes/(virtualLayout)/baz/index' import { Route as RedirectPreloadThirdRouteImport } from './routes/redirect/preload/third' import { Route as RedirectPreloadSecondRouteImport } from './routes/redirect/preload/second' import { Route as RedirectPreloadFirstRouteImport } from './routes/redirect/preload/first' @@ -53,10 +56,19 @@ import { Route as ParamsPsNamedPrefixChar123fooChar125RouteImport } from './rout import { Route as ParamsPsNamedFooRouteImport } from './routes/params-ps/named/$foo' import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b' import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a' +import { Route as virtualLayoutQuxQuxLayoutRouteImport } from './routes/(virtualLayout)/qux/_quxLayout' +import { Route as virtualLayoutQuuxQuuxLayoutRouteImport } from './routes/(virtualLayout)/quux/_quuxLayout' +import { Route as virtualLayoutFooFooLayoutRouteImport } from './routes/(virtualLayout)/foo/_fooLayout' +import { Route as virtualLayoutBazBazLayoutRouteImport } from './routes/(virtualLayout)/baz/_bazLayout' +import { Route as virtualLayoutBarBarLayoutRouteImport } from './routes/(virtualLayout)/bar/_barLayout' import { Route as groupSubfolderInsideRouteImport } from './routes/(group)/subfolder/inside' import { Route as groupLayoutInsidelayoutRouteImport } from './routes/(group)/_layout.insidelayout' +import { Route as virtualLayoutQuuxQuuxLayoutHelloRouteImport } from './routes/(virtualLayout)/quux/_quuxLayout.hello' const groupRouteImport = createFileRoute('/(group)')() +const virtualLayoutQuuxRouteImport = createFileRoute('/(virtualLayout)/quux')() +const virtualLayoutFooRouteImport = createFileRoute('/(virtualLayout)/foo')() +const virtualLayoutBazRouteImport = createFileRoute('/(virtualLayout)/baz')() const groupRoute = groupRouteImport.update({ id: '/(group)', @@ -117,6 +129,23 @@ const IndexRoute = IndexRouteImport.update({ path: '/', getParentRoute: () => rootRouteImport, } as any) +const virtualLayoutQuuxRoute = virtualLayoutQuuxRouteImport.update({ + id: '/(virtualLayout)/quux', + path: '/quux', + getParentRoute: () => rootRouteImport, + isVirtualLayout: true, +} as any) +const virtualLayoutFooRoute = virtualLayoutFooRouteImport.update({ + id: '/(virtualLayout)/foo', + path: '/foo', + getParentRoute: () => rootRouteImport, + isVirtualLayout: true, +} as any) +const virtualLayoutBazRoute = virtualLayoutBazRouteImport.update({ + id: '/(virtualLayout)/baz', + path: '/baz', + getParentRoute: () => rootRouteImport, +} as any) const SearchParamsIndexRoute = SearchParamsIndexRouteImport.update({ id: '/', path: '/', @@ -162,6 +191,11 @@ const LayoutLayout2Route = LayoutLayout2RouteImport.update({ id: '/_layout-2', getParentRoute: () => LayoutRoute, } as any) +const virtualLayoutBarRoute = virtualLayoutBarRouteImport.update({ + id: '/(virtualLayout)/bar', + path: '/bar', + getParentRoute: () => rootRouteImport, +} as any) const groupLazyinsideRoute = groupLazyinsideRouteImport .update({ id: '/lazyinside', @@ -184,6 +218,11 @@ const anotherGroupOnlyrouteinsideRoute = path: '/onlyrouteinside', getParentRoute: () => rootRouteImport, } as any) +const virtualLayoutQuxRouteRoute = virtualLayoutQuxRouteRouteImport.update({ + id: '/(virtualLayout)/qux', + path: '/qux', + getParentRoute: () => rootRouteImport, +} as any) const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({ id: '/', path: '/', @@ -199,6 +238,11 @@ const ParamsPsNamedIndexRoute = ParamsPsNamedIndexRouteImport.update({ path: '/params-ps/named/', getParentRoute: () => rootRouteImport, } as any) +const virtualLayoutBazIndexRoute = virtualLayoutBazIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => virtualLayoutBazRoute, +} as any) const RedirectPreloadThirdRoute = RedirectPreloadThirdRouteImport.update({ id: '/redirect/preload/third', path: '/redirect/preload/third', @@ -279,6 +323,31 @@ const LayoutLayout2LayoutARoute = LayoutLayout2LayoutARouteImport.update({ path: '/layout-a', getParentRoute: () => LayoutLayout2Route, } as any) +const virtualLayoutQuxQuxLayoutRoute = + virtualLayoutQuxQuxLayoutRouteImport.update({ + id: '/_quxLayout', + getParentRoute: () => virtualLayoutQuxRouteRoute, + } as any) +const virtualLayoutQuuxQuuxLayoutRoute = + virtualLayoutQuuxQuuxLayoutRouteImport.update({ + id: '/_quuxLayout', + getParentRoute: () => virtualLayoutQuuxRoute, + } as any) +const virtualLayoutFooFooLayoutRoute = + virtualLayoutFooFooLayoutRouteImport.update({ + id: '/_fooLayout', + getParentRoute: () => virtualLayoutFooRoute, + } as any) +const virtualLayoutBazBazLayoutRoute = + virtualLayoutBazBazLayoutRouteImport.update({ + id: '/_bazLayout', + getParentRoute: () => virtualLayoutBazRoute, + } as any) +const virtualLayoutBarBarLayoutRoute = + virtualLayoutBarBarLayoutRouteImport.update({ + id: '/_barLayout', + getParentRoute: () => virtualLayoutBarRoute, + } as any) const groupSubfolderInsideRoute = groupSubfolderInsideRouteImport.update({ id: '/subfolder/inside', path: '/subfolder/inside', @@ -289,6 +358,12 @@ const groupLayoutInsidelayoutRoute = groupLayoutInsidelayoutRouteImport.update({ path: '/insidelayout', getParentRoute: () => groupLayoutRoute, } as any) +const virtualLayoutQuuxQuuxLayoutHelloRoute = + virtualLayoutQuuxQuuxLayoutHelloRouteImport.update({ + id: '/hello', + path: '/hello', + getParentRoute: () => virtualLayoutQuuxQuuxLayoutRoute, + } as any) export interface FileRoutesByFullPath { '/': typeof groupLayoutRouteWithChildren @@ -301,9 +376,11 @@ export interface FileRoutesByFullPath { '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute '/대한민국': typeof Char45824Char54620Char48124Char44397Route + '/qux': typeof virtualLayoutQuxQuxLayoutRoute '/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute '/inside': typeof groupInsideRoute '/lazyinside': typeof groupLazyinsideRoute + '/bar': typeof virtualLayoutBarBarLayoutRoute '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren '/search-params/default': typeof SearchParamsDefaultRoute @@ -314,6 +391,9 @@ export interface FileRoutesByFullPath { '/search-params/': typeof SearchParamsIndexRoute '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute + '/baz': typeof virtualLayoutBazBazLayoutRoute + '/foo': typeof virtualLayoutFooFooLayoutRoute + '/quux': typeof virtualLayoutQuuxQuuxLayoutRouteWithChildren '/layout-a': typeof LayoutLayout2LayoutARoute '/layout-b': typeof LayoutLayout2LayoutBRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRoute @@ -329,9 +409,11 @@ export interface FileRoutesByFullPath { '/redirect/preload/first': typeof RedirectPreloadFirstRoute '/redirect/preload/second': typeof RedirectPreloadSecondRoute '/redirect/preload/third': typeof RedirectPreloadThirdRoute + '/baz/': typeof virtualLayoutBazIndexRoute '/params-ps/named': typeof ParamsPsNamedIndexRoute '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute + '/quux/hello': typeof virtualLayoutQuuxQuuxLayoutHelloRoute } export interface FileRoutesByTo { '/': typeof groupLayoutRouteWithChildren @@ -342,9 +424,11 @@ export interface FileRoutesByTo { '/notRemountDeps': typeof NotRemountDepsRoute '/remountDeps': typeof RemountDepsRoute '/대한민국': typeof Char45824Char54620Char48124Char44397Route + '/qux': typeof virtualLayoutQuxQuxLayoutRoute '/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute '/inside': typeof groupInsideRoute '/lazyinside': typeof groupLazyinsideRoute + '/bar': typeof virtualLayoutBarBarLayoutRoute '/posts/$postId': typeof PostsPostIdRoute '/search-params/default': typeof SearchParamsDefaultRoute '/structural-sharing/$enabled': typeof StructuralSharingEnabledRoute @@ -354,6 +438,9 @@ export interface FileRoutesByTo { '/search-params': typeof SearchParamsIndexRoute '/insidelayout': typeof groupLayoutInsidelayoutRoute '/subfolder/inside': typeof groupSubfolderInsideRoute + '/baz': typeof virtualLayoutBazIndexRoute + '/foo': typeof virtualLayoutFooFooLayoutRoute + '/quux': typeof virtualLayoutQuuxQuuxLayoutRouteWithChildren '/layout-a': typeof LayoutLayout2LayoutARoute '/layout-b': typeof LayoutLayout2LayoutBRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRoute @@ -372,6 +459,7 @@ export interface FileRoutesByTo { '/params-ps/named': typeof ParamsPsNamedIndexRoute '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute '/redirect/$target': typeof RedirectTargetIndexRoute + '/quux/hello': typeof virtualLayoutQuuxQuuxLayoutHelloRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -386,11 +474,13 @@ export interface FileRoutesById { '/posts': typeof PostsRouteWithChildren '/remountDeps': typeof RemountDepsRoute '/대한민국': typeof Char45824Char54620Char48124Char44397Route + '/(virtualLayout)/qux': typeof virtualLayoutQuxRouteRouteWithChildren '/(another-group)/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute '/(group)': typeof groupRouteWithChildren '/(group)/_layout': typeof groupLayoutRouteWithChildren '/(group)/inside': typeof groupInsideRoute '/(group)/lazyinside': typeof groupLazyinsideRoute + '/(virtualLayout)/bar': typeof virtualLayoutBarRouteWithChildren '/_layout/_layout-2': typeof LayoutLayout2RouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/redirect/$target': typeof RedirectTargetRouteWithChildren @@ -402,6 +492,14 @@ export interface FileRoutesById { '/search-params/': typeof SearchParamsIndexRoute '/(group)/_layout/insidelayout': typeof groupLayoutInsidelayoutRoute '/(group)/subfolder/inside': typeof groupSubfolderInsideRoute + '/(virtualLayout)/bar/_barLayout': typeof virtualLayoutBarBarLayoutRoute + '/(virtualLayout)/baz': typeof virtualLayoutBazRouteWithChildren + '/(virtualLayout)/baz/_bazLayout': typeof virtualLayoutBazBazLayoutRoute + '/(virtualLayout)/foo': typeof virtualLayoutFooRouteWithChildren + '/(virtualLayout)/foo/_fooLayout': typeof virtualLayoutFooFooLayoutRoute + '/(virtualLayout)/quux': typeof virtualLayoutQuuxRouteWithChildren + '/(virtualLayout)/quux/_quuxLayout': typeof virtualLayoutQuuxQuuxLayoutRouteWithChildren + '/(virtualLayout)/qux/_quxLayout': typeof virtualLayoutQuxQuxLayoutRoute '/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute '/_layout/_layout-2/layout-b': typeof LayoutLayout2LayoutBRoute '/params-ps/named/$foo': typeof ParamsPsNamedFooRoute @@ -417,9 +515,11 @@ export interface FileRoutesById { '/redirect/preload/first': typeof RedirectPreloadFirstRoute '/redirect/preload/second': typeof RedirectPreloadSecondRoute '/redirect/preload/third': typeof RedirectPreloadThirdRoute + '/(virtualLayout)/baz/': typeof virtualLayoutBazIndexRoute '/params-ps/named/': typeof ParamsPsNamedIndexRoute '/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute '/redirect/$target/': typeof RedirectTargetIndexRoute + '/(virtualLayout)/quux/_quuxLayout/hello': typeof virtualLayoutQuuxQuuxLayoutHelloRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -434,9 +534,11 @@ export interface FileRouteTypes { | '/posts' | '/remountDeps' | '/대한민국' + | '/qux' | '/onlyrouteinside' | '/inside' | '/lazyinside' + | '/bar' | '/posts/$postId' | '/redirect/$target' | '/search-params/default' @@ -447,6 +549,9 @@ export interface FileRouteTypes { | '/search-params/' | '/insidelayout' | '/subfolder/inside' + | '/baz' + | '/foo' + | '/quux' | '/layout-a' | '/layout-b' | '/params-ps/named/$foo' @@ -462,9 +567,11 @@ export interface FileRouteTypes { | '/redirect/preload/first' | '/redirect/preload/second' | '/redirect/preload/third' + | '/baz/' | '/params-ps/named' | '/params-ps/wildcard' | '/redirect/$target/' + | '/quux/hello' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -475,9 +582,11 @@ export interface FileRouteTypes { | '/notRemountDeps' | '/remountDeps' | '/대한민국' + | '/qux' | '/onlyrouteinside' | '/inside' | '/lazyinside' + | '/bar' | '/posts/$postId' | '/search-params/default' | '/structural-sharing/$enabled' @@ -487,6 +596,9 @@ export interface FileRouteTypes { | '/search-params' | '/insidelayout' | '/subfolder/inside' + | '/baz' + | '/foo' + | '/quux' | '/layout-a' | '/layout-b' | '/params-ps/named/$foo' @@ -505,6 +617,7 @@ export interface FileRouteTypes { | '/params-ps/named' | '/params-ps/wildcard' | '/redirect/$target' + | '/quux/hello' id: | '__root__' | '/' @@ -518,11 +631,13 @@ export interface FileRouteTypes { | '/posts' | '/remountDeps' | '/대한민국' + | '/(virtualLayout)/qux' | '/(another-group)/onlyrouteinside' | '/(group)' | '/(group)/_layout' | '/(group)/inside' | '/(group)/lazyinside' + | '/(virtualLayout)/bar' | '/_layout/_layout-2' | '/posts/$postId' | '/redirect/$target' @@ -534,6 +649,14 @@ export interface FileRouteTypes { | '/search-params/' | '/(group)/_layout/insidelayout' | '/(group)/subfolder/inside' + | '/(virtualLayout)/bar/_barLayout' + | '/(virtualLayout)/baz' + | '/(virtualLayout)/baz/_bazLayout' + | '/(virtualLayout)/foo' + | '/(virtualLayout)/foo/_fooLayout' + | '/(virtualLayout)/quux' + | '/(virtualLayout)/quux/_quuxLayout' + | '/(virtualLayout)/qux/_quxLayout' | '/_layout/_layout-2/layout-a' | '/_layout/_layout-2/layout-b' | '/params-ps/named/$foo' @@ -549,9 +672,11 @@ export interface FileRouteTypes { | '/redirect/preload/first' | '/redirect/preload/second' | '/redirect/preload/third' + | '/(virtualLayout)/baz/' | '/params-ps/named/' | '/params-ps/wildcard/' | '/redirect/$target/' + | '/(virtualLayout)/quux/_quuxLayout/hello' fileRoutesById: FileRoutesById } export interface RootRouteChildren { @@ -566,12 +691,17 @@ export interface RootRouteChildren { PostsRoute: typeof PostsRouteWithChildren RemountDepsRoute: typeof RemountDepsRoute Char45824Char54620Char48124Char44397Route: typeof Char45824Char54620Char48124Char44397Route + virtualLayoutQuxRouteRoute: typeof virtualLayoutQuxRouteRouteWithChildren anotherGroupOnlyrouteinsideRoute: typeof anotherGroupOnlyrouteinsideRoute groupRoute: typeof groupRouteWithChildren + virtualLayoutBarRoute: typeof virtualLayoutBarRouteWithChildren RedirectTargetRoute: typeof RedirectTargetRouteWithChildren StructuralSharingEnabledRoute: typeof StructuralSharingEnabledRoute ParamsPsIndexRoute: typeof ParamsPsIndexRoute RedirectIndexRoute: typeof RedirectIndexRoute + virtualLayoutBazRoute: typeof virtualLayoutBazRouteWithChildren + virtualLayoutFooRoute: typeof virtualLayoutFooRouteWithChildren + virtualLayoutQuuxRoute: typeof virtualLayoutQuuxRouteWithChildren ParamsPsNamedFooRoute: typeof ParamsPsNamedFooRoute ParamsPsNamedPrefixChar123fooChar125Route: typeof ParamsPsNamedPrefixChar123fooChar125Route ParamsPsNamedChar123fooChar125suffixRoute: typeof ParamsPsNamedChar123fooChar125suffixRoute @@ -673,6 +803,27 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } + '/(virtualLayout)/quux': { + id: '/(virtualLayout)/quux' + path: '/quux' + fullPath: '/quux' + preLoaderRoute: typeof virtualLayoutQuuxRouteImport + parentRoute: typeof rootRouteImport + } + '/(virtualLayout)/foo': { + id: '/(virtualLayout)/foo' + path: '/foo' + fullPath: '/foo' + preLoaderRoute: typeof virtualLayoutFooRouteImport + parentRoute: typeof rootRouteImport + } + '/(virtualLayout)/baz': { + id: '/(virtualLayout)/baz' + path: '/baz' + fullPath: '/baz' + preLoaderRoute: typeof virtualLayoutBazRouteImport + parentRoute: typeof rootRouteImport + } '/search-params/': { id: '/search-params/' path: '/' @@ -736,6 +887,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutLayout2RouteImport parentRoute: typeof LayoutRoute } + '/(virtualLayout)/bar': { + id: '/(virtualLayout)/bar' + path: '/bar' + fullPath: '/bar' + preLoaderRoute: typeof virtualLayoutBarRouteImport + parentRoute: typeof rootRouteImport + } '/(group)/lazyinside': { id: '/(group)/lazyinside' path: '/lazyinside' @@ -764,6 +922,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof anotherGroupOnlyrouteinsideRouteImport parentRoute: typeof rootRouteImport } + '/(virtualLayout)/qux': { + id: '/(virtualLayout)/qux' + path: '/qux' + fullPath: '/qux' + preLoaderRoute: typeof virtualLayoutQuxRouteRouteImport + parentRoute: typeof rootRouteImport + } '/redirect/$target/': { id: '/redirect/$target/' path: '/' @@ -785,6 +950,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ParamsPsNamedIndexRouteImport parentRoute: typeof rootRouteImport } + '/(virtualLayout)/baz/': { + id: '/(virtualLayout)/baz/' + path: '/' + fullPath: '/baz/' + preLoaderRoute: typeof virtualLayoutBazIndexRouteImport + parentRoute: typeof virtualLayoutBazRoute + } '/redirect/preload/third': { id: '/redirect/preload/third' path: '/redirect/preload/third' @@ -890,6 +1062,41 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutLayout2LayoutARouteImport parentRoute: typeof LayoutLayout2Route } + '/(virtualLayout)/qux/_quxLayout': { + id: '/(virtualLayout)/qux/_quxLayout' + path: '' + fullPath: '/qux' + preLoaderRoute: typeof virtualLayoutQuxQuxLayoutRouteImport + parentRoute: typeof virtualLayoutQuxRouteRoute + } + '/(virtualLayout)/quux/_quuxLayout': { + id: '/(virtualLayout)/quux/_quuxLayout' + path: '/quux' + fullPath: '/quux' + preLoaderRoute: typeof virtualLayoutQuuxQuuxLayoutRouteImport + parentRoute: typeof virtualLayoutQuuxRoute + } + '/(virtualLayout)/foo/_fooLayout': { + id: '/(virtualLayout)/foo/_fooLayout' + path: '/foo' + fullPath: '/foo' + preLoaderRoute: typeof virtualLayoutFooFooLayoutRouteImport + parentRoute: typeof virtualLayoutFooRoute + } + '/(virtualLayout)/baz/_bazLayout': { + id: '/(virtualLayout)/baz/_bazLayout' + path: '/baz' + fullPath: '/baz' + preLoaderRoute: typeof virtualLayoutBazBazLayoutRouteImport + parentRoute: typeof virtualLayoutBazRoute + } + '/(virtualLayout)/bar/_barLayout': { + id: '/(virtualLayout)/bar/_barLayout' + path: '' + fullPath: '/bar' + preLoaderRoute: typeof virtualLayoutBarBarLayoutRouteImport + parentRoute: typeof virtualLayoutBarRoute + } '/(group)/subfolder/inside': { id: '/(group)/subfolder/inside' path: '/subfolder/inside' @@ -904,6 +1111,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof groupLayoutInsidelayoutRouteImport parentRoute: typeof groupLayoutRoute } + '/(virtualLayout)/quux/_quuxLayout/hello': { + id: '/(virtualLayout)/quux/_quuxLayout/hello' + path: '/hello' + fullPath: '/quux/hello' + preLoaderRoute: typeof virtualLayoutQuuxQuuxLayoutHelloRouteImport + parentRoute: typeof virtualLayoutQuuxQuuxLayoutRoute + } } } @@ -957,6 +1171,19 @@ const PostsRouteChildren: PostsRouteChildren = { const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) +interface virtualLayoutQuxRouteRouteChildren { + virtualLayoutQuxQuxLayoutRoute: typeof virtualLayoutQuxQuxLayoutRoute +} + +const virtualLayoutQuxRouteRouteChildren: virtualLayoutQuxRouteRouteChildren = { + virtualLayoutQuxQuxLayoutRoute: virtualLayoutQuxQuxLayoutRoute, +} + +const virtualLayoutQuxRouteRouteWithChildren = + virtualLayoutQuxRouteRoute._addFileChildren( + virtualLayoutQuxRouteRouteChildren, + ) + interface groupLayoutRouteChildren { groupLayoutInsidelayoutRoute: typeof groupLayoutInsidelayoutRoute } @@ -985,6 +1212,17 @@ const groupRouteChildren: groupRouteChildren = { const groupRouteWithChildren = groupRoute._addFileChildren(groupRouteChildren) +interface virtualLayoutBarRouteChildren { + virtualLayoutBarBarLayoutRoute: typeof virtualLayoutBarBarLayoutRoute +} + +const virtualLayoutBarRouteChildren: virtualLayoutBarRouteChildren = { + virtualLayoutBarBarLayoutRoute: virtualLayoutBarBarLayoutRoute, +} + +const virtualLayoutBarRouteWithChildren = + virtualLayoutBarRoute._addFileChildren(virtualLayoutBarRouteChildren) + interface RedirectTargetRouteChildren { RedirectTargetViaBeforeLoadRoute: typeof RedirectTargetViaBeforeLoadRoute RedirectTargetViaLoaderRoute: typeof RedirectTargetViaLoaderRoute @@ -1001,6 +1239,57 @@ const RedirectTargetRouteWithChildren = RedirectTargetRoute._addFileChildren( RedirectTargetRouteChildren, ) +interface virtualLayoutBazRouteChildren { + virtualLayoutBazBazLayoutRoute: typeof virtualLayoutBazBazLayoutRoute + virtualLayoutBazIndexRoute: typeof virtualLayoutBazIndexRoute +} + +const virtualLayoutBazRouteChildren: virtualLayoutBazRouteChildren = { + virtualLayoutBazBazLayoutRoute: virtualLayoutBazBazLayoutRoute, + virtualLayoutBazIndexRoute: virtualLayoutBazIndexRoute, +} + +const virtualLayoutBazRouteWithChildren = + virtualLayoutBazRoute._addFileChildren(virtualLayoutBazRouteChildren) + +interface virtualLayoutFooRouteChildren { + virtualLayoutFooFooLayoutRoute: typeof virtualLayoutFooFooLayoutRoute +} + +const virtualLayoutFooRouteChildren: virtualLayoutFooRouteChildren = { + virtualLayoutFooFooLayoutRoute: virtualLayoutFooFooLayoutRoute, +} + +const virtualLayoutFooRouteWithChildren = + virtualLayoutFooRoute._addFileChildren(virtualLayoutFooRouteChildren) + +interface virtualLayoutQuuxQuuxLayoutRouteChildren { + virtualLayoutQuuxQuuxLayoutHelloRoute: typeof virtualLayoutQuuxQuuxLayoutHelloRoute +} + +const virtualLayoutQuuxQuuxLayoutRouteChildren: virtualLayoutQuuxQuuxLayoutRouteChildren = + { + virtualLayoutQuuxQuuxLayoutHelloRoute: + virtualLayoutQuuxQuuxLayoutHelloRoute, + } + +const virtualLayoutQuuxQuuxLayoutRouteWithChildren = + virtualLayoutQuuxQuuxLayoutRoute._addFileChildren( + virtualLayoutQuuxQuuxLayoutRouteChildren, + ) + +interface virtualLayoutQuuxRouteChildren { + virtualLayoutQuuxQuuxLayoutRoute: typeof virtualLayoutQuuxQuuxLayoutRouteWithChildren +} + +const virtualLayoutQuuxRouteChildren: virtualLayoutQuuxRouteChildren = { + virtualLayoutQuuxQuuxLayoutRoute: + virtualLayoutQuuxQuuxLayoutRouteWithChildren, +} + +const virtualLayoutQuuxRouteWithChildren = + virtualLayoutQuuxRoute._addFileChildren(virtualLayoutQuuxRouteChildren) + const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, SearchParamsRouteRoute: SearchParamsRouteRouteWithChildren, @@ -1014,12 +1303,17 @@ const rootRouteChildren: RootRouteChildren = { RemountDepsRoute: RemountDepsRoute, Char45824Char54620Char48124Char44397Route: Char45824Char54620Char48124Char44397Route, + virtualLayoutQuxRouteRoute: virtualLayoutQuxRouteRouteWithChildren, anotherGroupOnlyrouteinsideRoute: anotherGroupOnlyrouteinsideRoute, groupRoute: groupRouteWithChildren, + virtualLayoutBarRoute: virtualLayoutBarRouteWithChildren, RedirectTargetRoute: RedirectTargetRouteWithChildren, StructuralSharingEnabledRoute: StructuralSharingEnabledRoute, ParamsPsIndexRoute: ParamsPsIndexRoute, RedirectIndexRoute: RedirectIndexRoute, + virtualLayoutBazRoute: virtualLayoutBazRouteWithChildren, + virtualLayoutFooRoute: virtualLayoutFooRouteWithChildren, + virtualLayoutQuuxRoute: virtualLayoutQuuxRouteWithChildren, ParamsPsNamedFooRoute: ParamsPsNamedFooRoute, ParamsPsNamedPrefixChar123fooChar125Route: ParamsPsNamedPrefixChar123fooChar125Route, diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/bar.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/bar.tsx new file mode 100644 index 00000000000..dcc3779cc64 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/bar.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/bar')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/bar"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/bar/_barLayout.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/bar/_barLayout.tsx new file mode 100644 index 00000000000..1d709d4b3c8 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/bar/_barLayout.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/bar/_barLayout')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/bar/_barLayout"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/baz/_bazLayout.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/baz/_bazLayout.tsx new file mode 100644 index 00000000000..8c7c0fbfd8f --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/baz/_bazLayout.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/baz/_bazLayout')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/baz/_bazLayout"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/baz/index.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/baz/index.tsx new file mode 100644 index 00000000000..e9cce8e57fa --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/baz/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/baz/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/baz/"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/foo/_fooLayout.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/foo/_fooLayout.tsx new file mode 100644 index 00000000000..cbd13adab7b --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/foo/_fooLayout.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/foo/_fooLayout')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/foo/_fooLayout"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/quux/_quuxLayout.hello.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/quux/_quuxLayout.hello.tsx new file mode 100644 index 00000000000..f2f41719f02 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/quux/_quuxLayout.hello.tsx @@ -0,0 +1,11 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/quux/_quuxLayout/hello')( + { + component: RouteComponent, + }, +) + +function RouteComponent() { + return
Hello "/(virtualLayout)/quux/_quuxLayout/hello"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/quux/_quuxLayout.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/quux/_quuxLayout.tsx new file mode 100644 index 00000000000..7a3c7194272 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/quux/_quuxLayout.tsx @@ -0,0 +1,13 @@ +import { Outlet, createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/quux/_quuxLayout')({ + component: RouteComponent, +}) + +function RouteComponent() { + return ( +
+ +
+ ) +} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/qux/_quxLayout.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/qux/_quxLayout.tsx new file mode 100644 index 00000000000..ce6b33221d8 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/qux/_quxLayout.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/qux/_quxLayout')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/qux/_quxLayout"!
+} diff --git a/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/qux/route.tsx b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/qux/route.tsx new file mode 100644 index 00000000000..94184044482 --- /dev/null +++ b/e2e/react-router/basic-file-based/src/routes/(virtualLayout)/qux/route.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(virtualLayout)/qux')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(virtualLayout)/qux"!
+} diff --git a/e2e/react-router/basic-file-based/tests/app.spec.ts b/e2e/react-router/basic-file-based/tests/app.spec.ts index d825ca7b51f..a26234baef8 100644 --- a/e2e/react-router/basic-file-based/tests/app.spec.ts +++ b/e2e/react-router/basic-file-based/tests/app.spec.ts @@ -308,3 +308,37 @@ test('Should remount deps when remountDeps does change ', async ({ page }) => { 'Page component mounts: 2', ) }) + +test('Should match notFoundComponent when navigating to a route with a virtualLayout', async ({ + page, +}) => { + await page.goto('/foo') + await expect(page.getByRole('paragraph')).toContainText( + 'This is the notFoundComponent configured on root route', + ) + + await page.goto('/bar') + await expect(page.locator('#app')).toContainText( + 'Hello "/(virtualLayout)/bar"!', + ) + + await page.goto('/baz/') + await expect(page.locator('#app')).toContainText( + 'Hello "/(virtualLayout)/baz/"!', + ) + + await page.goto('/qux') + await expect(page.locator('#app')).toContainText( + 'Hello "/(virtualLayout)/qux"!', + ) + + await page.goto('/quux') + await expect(page.getByRole('paragraph')).toContainText( + 'This is the notFoundComponent configured on root route', + ) + + await page.goto('/quux/hello') + await expect(page.locator('#app')).toContainText( + 'Hello "/(virtualLayout)/quux/_quuxLayout/hello"!', + ) +}) diff --git a/packages/router-core/src/router.ts b/packages/router-core/src/router.ts index cc5776882ef..d7ea010d920 100644 --- a/packages/router-core/src/router.ts +++ b/packages/router-core/src/router.ts @@ -3197,6 +3197,7 @@ interface RouteLike { children?: Array options?: { caseSensitive?: boolean + isVirtualLayout?: boolean } } @@ -3457,6 +3458,8 @@ export function getMatchedRoutes({ | { foundRoute: TRouteLike; routeParams: Record } | undefined = undefined for (const route of flatRoutes) { + if (route.options?.isVirtualLayout) continue + const matchedParams = getMatchedParams(route) if (matchedParams) { diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts index 122976d417a..1e4672525f5 100644 --- a/packages/router-generator/src/generator.ts +++ b/packages/router-generator/src/generator.ts @@ -534,6 +534,23 @@ export class Generator { (d) => d, ]) + // After all nodes have been processed we can safely (re)-evaluate + // whether a virtual `layout` route should be treated as a virtual-layout wrapper + sortedRouteNodes.forEach((node) => { + if ( + node.isVirtual && + node._fsRouteType === 'layout' && + node.children && + !node.children.some((c) => c.cleanedPath === '/') + ) { + node.isVirtualLayout = true + } else { + // If the conditions are not met, ensure the flag is falsy so we + // don't rely on an outdated value that may have been set earlier. + delete node.isVirtualLayout + } + }) + const pluginConfig = plugin.config({ generator: this, rootRouteNode, @@ -592,6 +609,7 @@ export class Generator { `id: '${node.path}'`, !node.isNonPath ? `path: '${node.cleanedPath}'` : undefined, `getParentRoute: () => ${findParent(node, exportName)}`, + node.isVirtualLayout ? `isVirtualLayout: true` : undefined, ] .filter(Boolean) .join(',')} diff --git a/packages/router-generator/src/types.ts b/packages/router-generator/src/types.ts index b64674066d2..f89d0829fd6 100644 --- a/packages/router-generator/src/types.ts +++ b/packages/router-generator/src/types.ts @@ -13,6 +13,7 @@ export type RouteNode = { children?: Array parent?: RouteNode exports?: Array + isVirtualLayout?: boolean } export interface GetRouteNodesResult { diff --git a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts index c76e88e21d9..07f98c1bdc6 100644 --- a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts @@ -42,11 +42,13 @@ const NestedRoute = NestedRouteImport.update({ id: '/nested', path: '/nested', getParentRoute: () => rootRouteImport, + isVirtualLayout: true, } as any) const FooRoute = FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => rootRouteImport, + isVirtualLayout: true, } as any) const LayoutA2Route = LayoutA2RouteImport.update({ id: '/_layout-a2', diff --git a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts index 7eeca506226..787cebf385d 100644 --- a/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts +++ b/packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.snapshot.ts @@ -20,6 +20,7 @@ const FooRoute = FooRouteImport.update({ id: '/foo', path: '/foo', getParentRoute: () => rootRouteImport, + isVirtualLayout: true, } as any) const FooLayoutRouteRoute = FooLayoutRouteRouteImport.update({ id: '/_layout',