@snapstrat/switchboard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SnapStrat Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,323 @@
1
+ <div align="center">
2
+ <h1><img alt="SwitchBoard Logo" width="480" src="switchboard-logo.png"/></h1>
3
+ <p><i>A simple, extensible, component-based Svelte 5 SPA router.</i></p>
4
+ <img alt="License" src="https://img.shields.io/github/license/snapstrat/switchboard">
5
+ </div>
6
+
7
+ # Features
8
+
9
+ - A declarative, component-based method to declare routes.
10
+ - A simple API to programmatically navigate between routes.
11
+ - Layouts, nested routes, and route parameters.
12
+ - Svelte 5 compatibility, with TypeScript support.
13
+
14
+ # Why Switchboard?
15
+
16
+ Switchboard is designed to be a simple, extensible router for Svelte 5 applications.
17
+ Using composition and a declarative API, developers are able to quickly create SPA routes without the complexity of larger routing libraries, or dealing with SSR.
18
+
19
+ Switchboard is ideal for applications which:
20
+ - don't require server-side rendering. See [Use with SvelteKit](#use-with-sveltekit) for more info.
21
+ - want a simple, component-based routing solution.
22
+ - want to stray away from strictly file-based routing systems, such as SvelteKit's routing.
23
+ - want more flexibility in defining routes and layouts.
24
+ - want to be able to define routes in a way that fits their application's architecture.
25
+
26
+ # Getting Started
27
+
28
+ To install Switchboard, run:
29
+
30
+ ```sh
31
+ # npm
32
+ npm install @snapstrat/switchboard
33
+ # yarn
34
+ yarn add @snapstrat/switchboard
35
+ # pnpm
36
+ pnpm install @snapstrat/switchboard
37
+ # bun
38
+ bun install @snapstrat/switchboard
39
+ ```
40
+
41
+ # Basic Usage
42
+
43
+ Switchboard exposes several components and functions to help you set up routing in your Svelte application.
44
+
45
+ ## Creating a Router
46
+ Switchboard leaves the router setup to you. You can either use some form of global state management to hold a reference to it,
47
+ or create it directly in your root component.
48
+
49
+ Switchboard includes a `createWebRouter()` function to create a router instance that works with the browser's history API.
50
+
51
+ ### Global Access
52
+ > main.ts
53
+
54
+ ```ts
55
+ import App from './App.svelte';
56
+ import { createWebRouter } from '@snapstrat/switchboard';
57
+
58
+ // now anything can import router from here to access the router!
59
+ export const router = createWebRouter();
60
+
61
+ mount(App, {
62
+ target: document.body,
63
+ });
64
+ ```
65
+
66
+ ### Creation in Root Component
67
+ > App.svelte
68
+ ```svelte
69
+ <script lang="ts">
70
+ import { BrowserRouter, createWebRouter } from '$lib';
71
+ import PersistenceLayout from './PersistenceLayout.svelte';
72
+
73
+ // we can also create the router here!
74
+ const router = createWebRouter()
75
+ </script>
76
+
77
+ <!-- all BrowserRouter needs is a Router instance, constructed from anywhere. -->
78
+ <!-- any component nested in BrowserRouter gets access to getRouter() using Svelte contexts. -->
79
+ <BrowserRouter {router}>
80
+ <!-- Your routes and layouts go here -->
81
+ </BrowserRouter>
82
+ ```
83
+
84
+ ## Defining Routes
85
+ Switchboard is very unopinionated about how you define your routes.
86
+ The main building blocks are the `Route`, `Layout`, `PageInfo` and `Link` components.
87
+
88
+ ```svelte
89
+ <script lang="ts">
90
+ import { BrowserRouter, Route, Link } from '@snapstrat/switchboard'
91
+
92
+ // maybe make a router here? or import one.
93
+ </script>
94
+
95
+ <BrowserRouter router={your_router_instance}>
96
+ <Route path="/">
97
+ <h1>Home Page</h1>
98
+ </Route>
99
+
100
+ <Route path="/users/:id">
101
+ <h1>You're looking for a user with the id: {getRouteParams().id}</h1>
102
+ </Route>
103
+
104
+ <!-- You can use Route404 to catch all unmatched routes -->
105
+ <Route404>
106
+ <h1>404 - Page Not Found</h1>
107
+ </Route404>
108
+ </BrowserRouter>
109
+ ```
110
+
111
+ ### Links
112
+ Links can be created using the `Link` component, which is a very, very thin wrapper around an `<a>` tag.
113
+ Alternatively, you can use the `Router.switchTo()` method to programmatically navigate between routes, or use
114
+ the `{@attach href('my/path')}` attachment to attach hrefs to any element.
115
+
116
+ ```svelte
117
+
118
+ <script lang="ts">
119
+ import { Link } from '@snapstrat/switchboard';
120
+ </script>
121
+
122
+ <!-- both are equivalent: -->
123
+ <Link href="/some/path">Go to Some Path</Link>
124
+ <a {@attach href("/some/path")}>Go to Some Path</a>
125
+
126
+ <!-- not recommended for accessibility, but possible: -->
127
+ <button on:click={() => router.switchTo('/some/path')}>
128
+ Go to Some Path
129
+ </button>
130
+
131
+ <!-- not recommended at all, this will reload the page and lose SPA state: -->
132
+ <a href="/some/path">Go to Some Path</a>
133
+ ```
134
+
135
+ ### PageInfo
136
+
137
+ The `PageInfo` component allows you to declaratively set metadata for the current page, such as the document title and meta tags.
138
+
139
+ ```svelte
140
+ <script lang="ts">
141
+ import { PageInfo, Route } from '@snapstrat/switchboard';
142
+ </script>
143
+
144
+ <Route path="/my-cool-page">
145
+ <PageInfo title="My Page Title" icon="/page-icon.ico" />
146
+ </Route>
147
+ ```
148
+
149
+ ### Layouts
150
+ Layouts can be used to simplify routes that share common structure. State of a layout
151
+ will persist between __nested__ route changes.
152
+ For example, if you start at `/user/1`, modify some state in the layout, then navigate to `/user/1/profile`, the layout state will persist.
153
+ However, if you navigate to `/user/2`, or `/`, or `/any-other-route-outside-of-this-layout` the layout will be re-created and state will be destroyed since the route parameter changed.
154
+
155
+ ```svelte
156
+ <BrowserRouter router={your_router_instance}>
157
+ <!-- Layouts can have parameters too! -->
158
+ <!-- Layouts have two snippets they take in: `routes` and `layout` -->
159
+ <Layout path="/user/:id">
160
+ <!-- layout() holds the common layout structure. -->
161
+ {#snippet layout(route: Snippet)}
162
+ <p>You're looking at something for {getRouteParams().id}!</h1>
163
+ {@render route()}
164
+ {/snippet}
165
+
166
+ <!-- routes() holds all nested routes -->
167
+ {#snippet routes()}
168
+ <Route path="profile">
169
+ <h2>This is the profile page for user {getRouteParams().id}!</h2>
170
+ </Route>
171
+
172
+ <Route path="settings">
173
+ <h2>This is the settings page for user {getRouteParams().id}!</h2>
174
+ </Route>
175
+
176
+ <!-- in this context, / will match for /user/:id/ -->
177
+ <Route path="/">
178
+ <h2>This is the settings page for user {getRouteParams().id}!</h2>
179
+ </Route>
180
+
181
+ <!-- You can also have a Route404 for unmatched nested routes. -->
182
+ <Route404>
183
+ <h1>404 - User Not Found</h1>
184
+ </Route404>
185
+ {/snippet}
186
+ </Layout>
187
+
188
+ <!-- You can use Route404 to catch all unmatched routes. -->
189
+ <Route404>
190
+ <h1>404 - Page Not Found</h1>
191
+ </Route404>
192
+ </BrowserRouter>
193
+ ```
194
+
195
+ ## Use with SvelteKit
196
+ Switchboard is primarily designed for client-side routing in Svelte applications, and does NOT support server-side rendering (SSR), nor do we plan to ever support SSR.
197
+
198
+ However, you can still use Switchboard within a SvelteKit application for client-side routing needs. To do this, you'll need two main things:
199
+ 1. A single, top-level SvelteKit route that will serve as the entry point for your Switchboard-powered SPA.
200
+ 2. SSR disabled for that route.
201
+
202
+ In practice, this looks like:
203
+ ```
204
+ - /src
205
+ - /routes
206
+ - /[...any] <-- catch-all used to route all traffic your only +page.svelte, containing your Switchboard app
207
+ - +page.svelte <-- your Switchboard app goes here
208
+ - +page.ts <-- disable SSR here with `export const ssr = false;`
209
+ ```
210
+
211
+ In a normal Svelte application, you don't need to worry about any of this, and can just place a `BrowserRouter` at the root of your component tree (probably in `App.svelte`).
212
+
213
+ # Advanced Usage
214
+ Advanced usage of Switchboard comes from the natural composition of its components. You can create your own custom route components, layouts, and even
215
+ extend the router itself to add functionality.
216
+
217
+ Any Route or Layout can be declared anywhere that is within a `BrowserRouter`, or a `Layout` component, and will function as expected, no matter how these
218
+ are nested, constructed, composed, or imported.
219
+
220
+ ## Custom Route Component
221
+ You can wrap around the `Route` component to create your own custom route components.
222
+
223
+ For example, you could create an authenticated route component that checks if a user is logged in before rendering the route.
224
+
225
+ > [!CAUTION]
226
+ > Note that this isn't inherently secure, as all routing is done client-side. Make sure that when dealing with sensitive data, you also have server-side checks in place.
227
+
228
+ > AuthenticatedRoute.svelte
229
+ ```svelte
230
+ <script lang="ts">
231
+ import { Route, getRouter } from '@snapstrat/switchboard';
232
+ import { onMount } from 'svelte';
233
+ import { isUserAuthed } from './auth'; // your auth logic here
234
+
235
+ const { children, path } = $props();
236
+ </script>
237
+
238
+ <Route path={path}>
239
+ {#if isUserAuthed()}
240
+ {@render children()}
241
+ {:else}
242
+ <h1>Please log in to access this page.</h1>
243
+ {/if}
244
+ </Route>
245
+ ```
246
+
247
+ > App.svelte
248
+ ```svelte
249
+ <script lang="ts">
250
+ import { BrowserRouter } from '@snapstrat/switchboard';
251
+ import AuthenticatedRoute from './AuthenticatedRoute.svelte';
252
+ </script>
253
+
254
+ <BrowserRouter router={your_router_instance}>
255
+ <AuthenticatedRoute path="/dashboard">
256
+ <h1>Welcome to your dashboard!</h1>
257
+ </AuthenticatedRoute>
258
+ </BrowserRouter>
259
+ ```
260
+
261
+ ## Escaping Layouts
262
+ If you need to escape a layout for a specific route, you can set a custom 'container' on any route.
263
+
264
+ ```svelte
265
+ <script lang="ts">
266
+ import { BrowserRouter, Layout, LayoutData, Route } from '@snapstrat/switchboard';
267
+
268
+ let otherLayout: LayoutData = $state();
269
+ </script>
270
+
271
+ <BrowserRouter router={your_router_instance}>
272
+ <Layout path="/app">
273
+ {#snippet layout(route: Snippet)}
274
+ <div class="app-layout">
275
+ <nav>...navigation...</nav>
276
+ <main>
277
+ {@render route()}
278
+ </main>
279
+ </div>
280
+ {/snippet}
281
+
282
+ {#snippet routes()}
283
+ <Route path="dashboard">
284
+ <h1>Dashboard</h1>
285
+ </Route>
286
+
287
+ <Route path="settings">
288
+ <h1>Settings</h1>
289
+ </Route>
290
+
291
+ <!--
292
+ container can either be a Router instance or another Layout.
293
+ setting to whatever your router instance is completely disables the layout.
294
+ -->
295
+ <Route path="/login" container={your_router_instance}>
296
+ <h1>Login Page</h1>
297
+ </Route>
298
+
299
+
300
+ <!--
301
+ setting container to another layout makes the route use that layout instead
302
+ of the current one.
303
+
304
+ note that this will NOT impact the path; this route still exists
305
+ at /app/landing-page, NOT /other/landing-page.
306
+ -->
307
+ <Route path="/landing-page" container={outerLayout}>
308
+ <h1>Landing Page</h1>
309
+ </Route>
310
+ {/snippet}
311
+ </Layout>
312
+
313
+ <Layout path="/other" bind:ref={otherLayout}>
314
+ <!-- another layout... -->
315
+ </Layout>
316
+ </BrowserRouter>
317
+ ```
318
+
319
+ The same principle can be applied to Layouts nested within other Layouts as well, with the same `container` prop, and
320
+ same rules regarding how paths are resolved.
321
+
322
+ > [!WARNING]
323
+ > When escaping a layout, you **must** have the layout you're referencing defined above the layout you're escaping from.
@@ -0,0 +1,2 @@
1
+ export * from './router';
2
+ export { createWebRouter } from "./router/impl";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // Reexport your entry components here
2
+ export * from './router';
3
+ export { createWebRouter } from "./router/impl";
@@ -0,0 +1,64 @@
1
+ <!--
2
+ @component
3
+ The BrowserRouter component is the main entry point for routing in an application using Switchboard.
4
+ It initializes the routes, listens for changes in the URL to switch routes accordingly,
5
+ and displays the appropriate component based on the current route.
6
+ -->
7
+ <script module lang="ts">
8
+ import type { Router } from './router.svelte';
9
+ import type { Snippet } from 'svelte';
10
+
11
+ export type PageRouterProps = {
12
+ /**
13
+ * The router instance that manages the application's routes.
14
+ *
15
+ * @see {@link Router}
16
+ * @see {@link createWebRouter}
17
+ */
18
+ router: Router;
19
+ children?: Snippet;
20
+ };
21
+ </script>
22
+
23
+ <script lang="ts">
24
+ import { onMount, tick } from 'svelte';
25
+ import { setRouterContext, type LayoutData, getAllLayouts, Route404 } from './index';
26
+ import { parseWindowSearchParams } from './internals/windowUtils';
27
+
28
+ let { router, children }: PageRouterProps = $props();
29
+
30
+ onMount(async () => {
31
+ await tick();
32
+ const params = parseWindowSearchParams();
33
+
34
+ router.switchTo(window.location.pathname, params, false);
35
+ });
36
+
37
+ setRouterContext(router);
38
+
39
+ const currentAppRoute = $derived(router.currentRoute?.route);
40
+ const layouts = $derived(getAllLayouts(currentAppRoute?.layout));
41
+ </script>
42
+
43
+ <Route404>
44
+ <!-- This is blank because it's simply a fallback in case there is no 404 page -->
45
+ <svelte:fragment />
46
+ </Route404>
47
+
48
+ {@render children?.()}
49
+
50
+ {#snippet layoutRender(remaining: LayoutData[])}
51
+ {#if remaining.length === 0}
52
+ {@render currentAppRoute?.component?.()}
53
+ {:else}
54
+ {@const next = remaining[0]}
55
+
56
+ {#snippet renderer()}
57
+ {@render layoutRender(remaining.slice(1))}
58
+ {/snippet}
59
+
60
+ {@render next.renderer(renderer)}
61
+ {/if}
62
+ {/snippet}
63
+
64
+ {@render layoutRender(layouts)}
@@ -0,0 +1,20 @@
1
+ import type { Router } from './router.svelte';
2
+ import type { Snippet } from 'svelte';
3
+ export type PageRouterProps = {
4
+ /**
5
+ * The router instance that manages the application's routes.
6
+ *
7
+ * @see {@link Router}
8
+ * @see {@link createWebRouter}
9
+ */
10
+ router: Router;
11
+ children?: Snippet;
12
+ };
13
+ /**
14
+ * The BrowserRouter component is the main entry point for routing in an application using Switchboard.
15
+ * It initializes the routes, listens for changes in the URL to switch routes accordingly,
16
+ * and displays the appropriate component based on the current route.
17
+ */
18
+ declare const BrowserRouter: import("svelte").Component<PageRouterProps, {}, "">;
19
+ type BrowserRouter = ReturnType<typeof BrowserRouter>;
20
+ export default BrowserRouter;
@@ -0,0 +1,79 @@
1
+ <script lang="ts" module>
2
+
3
+ import type { Snippet } from 'svelte';
4
+ import type { LayoutSnippet, RouteContainer } from './router.svelte';
5
+
6
+ export type LayoutProps = {
7
+ path: string;
8
+ layout: LayoutSnippet;
9
+ container?: RouteContainer;
10
+ routes: Snippet;
11
+ ref?: LayoutData;
12
+ }
13
+ </script>
14
+
15
+ <script lang="ts">
16
+
17
+ import {
18
+ type ApplicationRoute, getAllCanonicalLayouts,
19
+ getLayout,
20
+ getRouter,
21
+ type LayoutData,
22
+ RoutePath,
23
+ type Router
24
+ } from '..';
25
+ import { setLayoutContext } from '..';
26
+ import { onDestroy } from 'svelte';
27
+
28
+ let { path, layout: renderer, container, routes, ref = $bindable() }: LayoutProps = $props();
29
+
30
+ type LayoutInternals = { routes: ApplicationRoute[], _routes: ApplicationRoute[] }
31
+
32
+ let parent: LayoutData | undefined;
33
+ if (!container) {
34
+ parent = getLayout();
35
+ } else {
36
+ parent = container.isRouter() ? undefined : container as LayoutData;
37
+ }
38
+
39
+ const layoutData: LayoutData & LayoutInternals = {
40
+ _routes: [],
41
+ get routes() {
42
+ return this._routes.toReversed();
43
+ },
44
+ path: path ? RoutePath.normalizePath(path) : undefined,
45
+ parent,
46
+ canonicalParent: getLayout(),
47
+ registerRoute(route: ApplicationRoute) {
48
+ getRouter().registerRoute(route);
49
+ this._routes.push(route);
50
+ },
51
+ registerRoute404(route: ApplicationRoute) {
52
+ getRouter().registerRoute404(route);
53
+ this._routes.push(route);
54
+ },
55
+ unregisterRoute(route: ApplicationRoute) {
56
+ getRouter()?.unregisterRoute(route);
57
+ this._routes.splice(this.routes.indexOf(route), 1);
58
+ },
59
+ renderer,
60
+ get joinedPath() {
61
+ return getAllCanonicalLayouts(this)
62
+ .map((l) => l.path)
63
+ .filter((p) => p !== undefined && p !== '')
64
+ .join('/');
65
+ },
66
+ isRouter(): this is Router { return false; }
67
+ }
68
+ ref = layoutData;
69
+
70
+ setLayoutContext(layoutData);
71
+
72
+ onDestroy(() => {
73
+ setLayoutContext(layoutData.parent);
74
+ })
75
+ </script>
76
+
77
+
78
+
79
+ {@render routes()}
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { LayoutSnippet, RouteContainer } from './router.svelte';
3
+ export type LayoutProps = {
4
+ path: string;
5
+ layout: LayoutSnippet;
6
+ container?: RouteContainer;
7
+ routes: Snippet;
8
+ ref?: LayoutData;
9
+ };
10
+ import { type LayoutData } from '..';
11
+ declare const Layout: import("svelte").Component<LayoutProps, {}, "ref">;
12
+ type Layout = ReturnType<typeof Layout>;
13
+ export default Layout;
@@ -0,0 +1,27 @@
1
+ <!--
2
+ @component
3
+ Represents a link that can be used to navigate within the application.
4
+ -->
5
+
6
+ <script module lang="ts">
7
+ import { type Snippet } from 'svelte';
8
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
9
+
10
+ export type LinkProps = {
11
+ /**
12
+ * The content to display inside the link.
13
+ */
14
+ children?: Snippet;
15
+ } & HTMLAnchorAttributes;
16
+ </script>
17
+
18
+
19
+ <script lang="ts">
20
+ import { href } from './router.svelte';
21
+
22
+ const { children, ...attrs }: LinkProps = $props();
23
+ </script>
24
+
25
+ <a {...attrs} {@attach href(attrs.href)}>
26
+ {@render children?.()}
27
+ </a>
@@ -0,0 +1,12 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ export type LinkProps = {
4
+ /**
5
+ * The content to display inside the link.
6
+ */
7
+ children?: Snippet;
8
+ } & HTMLAnchorAttributes;
9
+ /** Represents a link that can be used to navigate within the application. */
10
+ declare const Link: import("svelte").Component<LinkProps, {}, "">;
11
+ type Link = ReturnType<typeof Link>;
12
+ export default Link;
@@ -0,0 +1,23 @@
1
+ <!--
2
+ @component
3
+ Provides a page title and icon for the current route.
4
+ -->
5
+ <script lang="ts" module>
6
+ export type PageInfoProps = {
7
+ title?: string;
8
+ icon?: string;
9
+ };
10
+ </script>
11
+
12
+ <script lang="ts">
13
+ import { getRouter } from '..';
14
+
15
+ const { title, icon }: PageInfoProps = $props();
16
+ </script>
17
+
18
+ <svelte:head>
19
+ <title>{title ?? getRouter().options.defaultTitle}</title>
20
+ {#if icon !== undefined}
21
+ <link rel="icon" href={icon} />
22
+ {/if}
23
+ </svelte:head>
@@ -0,0 +1,8 @@
1
+ export type PageInfoProps = {
2
+ title?: string;
3
+ icon?: string;
4
+ };
5
+ /** Provides a page title and icon for the current route. */
6
+ declare const PageInfo: import("svelte").Component<PageInfoProps, {}, "">;
7
+ type PageInfo = ReturnType<typeof PageInfo>;
8
+ export default PageInfo;
@@ -0,0 +1,59 @@
1
+ <!--
2
+ @component
3
+ The Route component is used to define a route in the application.
4
+ It registers the route with the router when mounted and unregisters it when destroyed.
5
+ Once registered, the route can be navigated to using the router's switchTo method.
6
+
7
+ The children of this component make the content that will be displayed when the route is active.
8
+ -->
9
+ <script lang="ts" module>
10
+ import type { Snippet } from 'svelte';
11
+ import type { RouteContainer } from './router.svelte';
12
+
13
+ export type RouteProps = {
14
+ path: string;
15
+ container?: RouteContainer;
16
+ children?: Snippet;
17
+ }
18
+ </script>
19
+
20
+ <script lang="ts">
21
+ import { onDestroy, onMount } from 'svelte';
22
+ import {
23
+ type ApplicationRoute, getLayout, getRouteContainer, getRouter, type LayoutData, RoutePath
24
+ } from '..';
25
+
26
+ let {
27
+ path,
28
+ container,
29
+ children,
30
+ }: RouteProps = $props();
31
+
32
+ let router = getRouter();
33
+
34
+ let route : ApplicationRoute | undefined;
35
+
36
+ onMount(() => {
37
+ const layout = getLayout();
38
+
39
+ container ??= getRouteContainer();
40
+
41
+ const layoutPath = layout?.joinedPath ?? '';
42
+
43
+ const combinedPath = RoutePath.concatPaths(layoutPath, path);
44
+
45
+ route = {
46
+ path: RoutePath.fromString(combinedPath),
47
+ component: children,
48
+ layout: container.isRouter() ? undefined : container as LayoutData
49
+ };
50
+ container.registerRoute(route);
51
+ });
52
+
53
+ onDestroy(() => {
54
+ if (route) {
55
+ const container = getLayout() ?? router;
56
+ container.unregisterRoute(route);
57
+ }
58
+ })
59
+ </script>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { RouteContainer } from './router.svelte';
3
+ export type RouteProps = {
4
+ path: string;
5
+ container?: RouteContainer;
6
+ children?: Snippet;
7
+ };
8
+ /**
9
+ * The Route component is used to define a route in the application.
10
+ * It registers the route with the router when mounted and unregisters it when destroyed.
11
+ * Once registered, the route can be navigated to using the router's switchTo method.
12
+ *
13
+ * The children of this component make the content that will be displayed when the route is active.
14
+ */
15
+ declare const Route: import("svelte").Component<RouteProps, {}, "">;
16
+ type Route = ReturnType<typeof Route>;
17
+ export default Route;