Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@snapstrat/switchboard",
"version": "1.0.0",
"version": "1.0.1",
"scripts": {
"dev": "vite dev",
"build": "vite build && npm run package",
Expand Down
18 changes: 14 additions & 4 deletions src/lib/router/BrowserRouter.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ and displays the appropriate component based on the current route.
setRouterContext(router);

const currentAppRoute = $derived(router.currentRoute?.route);
const allRoutes = $derived(router.getAllRoutes());
const layouts = $derived(getAllLayouts(currentAppRoute?.layout));
const lastLayout = $derived(
layouts.length > 0 ? layouts[layouts.length - 1] : undefined
);
</script>

<Route404>
Expand All @@ -49,16 +53,22 @@ and displays the appropriate component based on the current route.

{#snippet layoutRender(remaining: LayoutData[])}
{#if remaining.length === 0}
{@render currentAppRoute?.component?.()}
<!-- We need to render all of these to ensure transitions and lifecycle hooks work correctly -->
{#each allRoutes.filter(it => it.layout === lastLayout) as route (route)}
{@render route?.component?.()}
{/each}
{:else}
{@const next = remaining[0]}

{#snippet renderer()}
{@render layoutRender(remaining.slice(1))}
{/snippet}

{@render next.renderer(renderer)}
{#each remaining as next (next)}
{#if next === remaining[0]}
{@render next.renderer(renderer)}
{/if}
{/each}
{/if}
{/snippet}

{@render layoutRender(layouts)}
{@render layoutRender(layouts)}
4 changes: 1 addition & 3 deletions src/lib/router/Layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<script lang="ts">

import {
type ApplicationRoute, getAllCanonicalLayouts,
type ApplicationRoute, getAllCanonicalLayouts, getAllLayouts,
getLayout,
getRouter,
type LayoutData,
Expand Down Expand Up @@ -74,6 +74,4 @@
})
</script>



{@render routes()}
16 changes: 12 additions & 4 deletions src/lib/router/Route.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The children of this component make the content that will be displayed when the
<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import {
type ApplicationRoute, getLayout, getRouteContainer, getRouter, type LayoutData, RoutePath
type ApplicationRoute, getAllLayouts, getLayout, getRouteContainer, getRouter, type LayoutData, RoutePath
} from '$lib';

let {
Expand All @@ -31,7 +31,7 @@ The children of this component make the content that will be displayed when the

let router = getRouter();

let route : ApplicationRoute | undefined;
let route : ApplicationRoute | undefined = $state.raw();

onMount(() => {
const layout = getLayout();
Expand All @@ -44,16 +44,24 @@ The children of this component make the content that will be displayed when the

route = {
path: RoutePath.fromString(combinedPath),
component: children,
component: conditionalRender,
layout: container.isRouter() ? undefined : container as LayoutData
};
container.registerRoute(route);
});

onDestroy(() => {
onDestroy(async () => {
if (route) {
const container = getLayout() ?? router;
container.unregisterRoute(route);
}
})

const currentAppRoute = $derived(router.currentRoute?.route);
</script>

{#snippet conditionalRender()}
{#if currentAppRoute === route}
{@render children?.()}
{/if}
{/snippet}
24 changes: 20 additions & 4 deletions src/lib/router/Route404.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@

<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import { type ApplicationRoute, getLayout, getRouteContainer, getRouter, type LayoutData, RoutePath } from '$lib';
import {
type ApplicationRoute,
getAllLayouts,
getLayout,
getRouteContainer,
getRouter,
type LayoutData,
RoutePath
} from '$lib';

let { children, container }: Route404Props = $props();

let router = getRouter();

let route : ApplicationRoute | undefined;
let route : ApplicationRoute | undefined = $state.raw();

onMount(() => {
const layout = getLayout();
Expand All @@ -28,7 +36,7 @@

route = {
path: RoutePath.fromString(layoutPath, true),
component: children,
component: conditionalRender,
layout: container.isRouter() ? undefined : container as LayoutData
};
container.registerRoute404(route);
Expand All @@ -40,4 +48,12 @@
container.unregisterRoute(route);
}
})
</script>

const currentAppRoute = $derived(router.currentRoute?.route);
</script>

{#snippet conditionalRender()}
{#if currentAppRoute === route}
{@render children?.()}
{/if}
{/snippet}
12 changes: 7 additions & 5 deletions src/lib/router/impl/webRouter.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type HistoryState = {
* A router used for an entire application on the web.
*/
class WebRouter implements Router {
private readonly _routes: ApplicationRoute[] = [];
private readonly _routes404: ApplicationRoute[] = [];
private _routes: ApplicationRoute[] = $state.raw([]);
private _routes404: ApplicationRoute[] = $state.raw([]);

// routes are stored in reverse order for easier matching
// the most recently added routes are matched first
Expand Down Expand Up @@ -59,6 +59,7 @@ class WebRouter implements Router {
public get params(): RouteParams {
return this.currentRoute?.queryParams ?? {};
}

public get queryParams(): RouteParams {
return this.currentRoute?.queryParams ?? {};
}
Expand Down Expand Up @@ -127,11 +128,12 @@ class WebRouter implements Router {
}

public registerRoute(route: ApplicationRoute): void {
this._routes.push(route);
this._routes = [...this._routes, route];
}

public registerRoute404(route: ApplicationRoute): void {
this._routes404.push(route);
this._routes404 = [...this._routes404, route];


// switch to the new route if it's a 404 route and the current route is undefined
if (this.currentRoute?.route == undefined) {
Expand Down Expand Up @@ -209,7 +211,7 @@ class WebRouter implements Router {
}

public getAllRoutes(): ApplicationRoute[] {
return [...this.routes];
return [...this.routes, ...this.routes404];
}

isRouter(): this is Router { return true; }
Expand Down
13 changes: 13 additions & 0 deletions src/routes/[...any]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { PageInfo } from '$lib';
import PersistenceLayout from './PersistenceLayout.svelte';
import EscapingLayouts from './EscapingLayouts.svelte';
import { fly } from 'svelte/transition';

const router = createWebRouter()

Expand Down Expand Up @@ -49,6 +50,18 @@ As such, it has some pretty esoteric routes and components for the sake of testi
{@render linkTo("/route-params/foo/bar")}
</Route>

<Route path="/transition-1">
<div transition:fly|global={{ y: 20, duration: 300 }}>
helo <Link href="/transition-2">go to 2</Link>
</div>
</Route>

<Route path="/transition-2">
<div transition:fly|global={{ y: 20, duration: 300 }}>
helo from 2 <Link href="/transition-1">go to 1</Link>
</div>
</Route>

<Route path="/links/component/start">
{@render identify('links-component-start')}
<Link href="/links/component/finish" id="go-to-finish">Go to /links/component/finish</Link>
Expand Down