@keenmate/svelte-spa-router 1.0.1
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.md +21 -0
- package/README.md +507 -0
- package/Router.d.ts +221 -0
- package/Router.svelte +644 -0
- package/active.d.ts +23 -0
- package/active.js +119 -0
- package/constants.js +1 -0
- package/helpers/url-helpers.js +29 -0
- package/nightwatch.conf.cjs +52 -0
- package/package.json +70 -0
- package/wrap.d.ts +41 -0
- package/wrap.js +93 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019, Alessandro Segala
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
# svelte-spa-router
|
|
2
|
+
> This is a fork of [ItalyPaleAle/svelte-spa-router](https://github.com/ItalyPaleAle/svelte-spa-router).
|
|
3
|
+
> This fork adds option to not use hash-based routing and instead leverage `History`'s `pushState`/`replaceState`
|
|
4
|
+
|
|
5
|
+
## No hash routing
|
|
6
|
+
To configure library to not use hash routing, you need to set config before App initializes (in `main.js/ts`):
|
|
7
|
+
|
|
8
|
+
### Config preparation
|
|
9
|
+
```javascript
|
|
10
|
+
import {HashRoutingEnabled, BasePath} from "@keenmate/svelte-spa-router"
|
|
11
|
+
|
|
12
|
+
HashRoutingEnabled.set(false)
|
|
13
|
+
BasePath.set(import.meta.env.BASE_URL)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Usage
|
|
17
|
+
The trick is in a mandatory use of `use:link` on HTML links to augment these links to call `pushState`/`replaceState` instead of actual navigation
|
|
18
|
+
As a bonus, it automatically prepends `BasePath` value to these links if it is not already present
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<a href="/home" use:link>
|
|
22
|
+
Link to home
|
|
23
|
+
</a>
|
|
24
|
+
|
|
25
|
+
<a href="/about" use:link>
|
|
26
|
+
Link to about
|
|
27
|
+
</a>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Original README
|
|
31
|
+
|
|
32
|
+
This module is a router for [Svelte 3 and 4](https://github.com/sveltejs/svelte) applications, specifically optimized
|
|
33
|
+
for Single Page Applications (SPA).
|
|
34
|
+
|
|
35
|
+
Main features:
|
|
36
|
+
|
|
37
|
+
- Leverages **hash-based routing**, which is optimal for SPAs and doesn't require any server-side processing
|
|
38
|
+
- Insanely simple to use, and has a minimal footprint
|
|
39
|
+
- Uses the tiny [regexparam](https://github.com/lukeed/regexparam) for parsing routes, with support for parameters (e.g.
|
|
40
|
+
`/book/:id?`) and more
|
|
41
|
+
|
|
42
|
+
This module is released under MIT license.
|
|
43
|
+
|
|
44
|
+
## Video
|
|
45
|
+
|
|
46
|
+
["So you want to pick a router?"]((https://www.youtube.com/watch?v=EL1qM0cv0eA)) talk by @ItalyPaleAle at Svelte Summit
|
|
47
|
+
2020. Includes an explanation of the two kinds of routers and a demo of svelte-spa-router.
|
|
48
|
+
_(Click on the cover image to play the video on YouTube)_
|
|
49
|
+
|
|
50
|
+
[](https://www.youtube.com/watch?v=EL1qM0cv0eA)
|
|
51
|
+
|
|
52
|
+
## Hash-based routing
|
|
53
|
+
|
|
54
|
+
With hash-based routing, navigation is possible thanks to storing the current view in the part of the URL after `#`,
|
|
55
|
+
called "hash" or "fragment".
|
|
56
|
+
|
|
57
|
+
For example, if your SPA is in a static file called `index.html`, your URLs for navigating within the app look something
|
|
58
|
+
like `index.html#/profile`, `index.html#/book/42`, etc. (The `index.html` part can usually be omitted for the index
|
|
59
|
+
file, so you can just create URLs that look like `http://example.com/#/profile`).
|
|
60
|
+
|
|
61
|
+
When I created this component, other routers for Svelte 3+ implemented navigation using the HTML5 history API. While
|
|
62
|
+
those URLs look nicer (e.g. you can actually navigate to `http://example.com/profile`), they are not ideal for static
|
|
63
|
+
Single Page Applications. In order for users to be able to share links or even just refresh the page, you are required
|
|
64
|
+
to have a server on the backend processing the request, and building fully-static apps is much harder as a consequence.
|
|
65
|
+
|
|
66
|
+
Hash-based routing is simpler, works well even without a server, and it's generally better suited for static SPAs,
|
|
67
|
+
especially when SEO isn't a concern, as is the case when the app requires authentication. Many popular apps use
|
|
68
|
+
hash-based routing, including GMail!
|
|
69
|
+
|
|
70
|
+
## Sample code
|
|
71
|
+
|
|
72
|
+
Check out the code in the [examples](/examples) folder for some usage examples.
|
|
73
|
+
|
|
74
|
+
To run the samples, clone the repository, install the dependencies, then build each sample using Rollup:
|
|
75
|
+
|
|
76
|
+
````sh
|
|
77
|
+
git clone https://github.com/ItalyPaleAle/svelte-spa-router
|
|
78
|
+
cd svelte-spa-router
|
|
79
|
+
npm install
|
|
80
|
+
|
|
81
|
+
# Navigate to a sample
|
|
82
|
+
cd examples/…
|
|
83
|
+
# For example
|
|
84
|
+
cd examples/basic-routing
|
|
85
|
+
|
|
86
|
+
# Build and run (in the folder of a sample)
|
|
87
|
+
npx rollup -c
|
|
88
|
+
npx serve -n -l 5050 dist
|
|
89
|
+
````
|
|
90
|
+
|
|
91
|
+
The sample will be running at http://localhost:5050
|
|
92
|
+
|
|
93
|
+
## Starter template
|
|
94
|
+
|
|
95
|
+
You can find a starter template with Svelte 4 and svelte-spa-router
|
|
96
|
+
at [italypaleale/svelte-spa-router-template](https://github.com/italypaleale/svelte-spa-router-template).
|
|
97
|
+
|
|
98
|
+
To use the template:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
npx degit italypaleale/svelte-spa-router-template svelte-app
|
|
102
|
+
cd svelte-app
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
More information can be found on the [template's repo](https://github.com/italypaleale/svelte-spa-router-template).
|
|
106
|
+
|
|
107
|
+
## Using svelte-spa-router
|
|
108
|
+
|
|
109
|
+
You can include the router in any project using Svelte 3 or 4.
|
|
110
|
+
|
|
111
|
+
### Install from NPM
|
|
112
|
+
|
|
113
|
+
To add svelte-spa-router to your project:
|
|
114
|
+
|
|
115
|
+
````sh
|
|
116
|
+
npm install svelte-spa-router
|
|
117
|
+
````
|
|
118
|
+
|
|
119
|
+
### Supported browsers
|
|
120
|
+
|
|
121
|
+
svelte-spa-router aims to support modern browsers, including recent versions of:
|
|
122
|
+
|
|
123
|
+
- Chrome
|
|
124
|
+
- Edge ("traditional" and Chromium-based)
|
|
125
|
+
- Firefox
|
|
126
|
+
- Safari
|
|
127
|
+
|
|
128
|
+
Support for Internet Explorer is not a goal for this project. Some users have reportedly been able to use
|
|
129
|
+
svelte-spa-router with IE11 after transpilation (e.g. with Babel), but this is not guaranteed.
|
|
130
|
+
|
|
131
|
+
### Define your routes
|
|
132
|
+
|
|
133
|
+
Each route is a normal Svelte component, with the markup, scripts, bindings, etc. Any Svelte component can be a route.
|
|
134
|
+
|
|
135
|
+
The route definition is just a JavaScript dictionary (object) where the key is a string with the path (including
|
|
136
|
+
parameters, etc), and the value is the route object.
|
|
137
|
+
|
|
138
|
+
For example:
|
|
139
|
+
|
|
140
|
+
````js
|
|
141
|
+
import Home from './routes/Home.svelte'
|
|
142
|
+
import Author from './routes/Author.svelte'
|
|
143
|
+
import Book from './routes/Book.svelte'
|
|
144
|
+
import NotFound from './routes/NotFound.svelte'
|
|
145
|
+
|
|
146
|
+
const routes = {
|
|
147
|
+
// Exact path
|
|
148
|
+
'/': Home,
|
|
149
|
+
|
|
150
|
+
// Using named parameters, with last being optional
|
|
151
|
+
'/author/:first/:last?': Author,
|
|
152
|
+
|
|
153
|
+
// Wildcard parameter
|
|
154
|
+
'/book/*': Book,
|
|
155
|
+
|
|
156
|
+
// Catch-all
|
|
157
|
+
// This is optional, but if present it must be the last
|
|
158
|
+
'*': NotFound,
|
|
159
|
+
}
|
|
160
|
+
````
|
|
161
|
+
|
|
162
|
+
Routes must begin with `/` (or `*` for the catch-all route).
|
|
163
|
+
|
|
164
|
+
Alternatively, you can also define your routes using custom regular expressions, as explained below.
|
|
165
|
+
|
|
166
|
+
Note that the order matters! When your users navigate inside the app, the first matching path will determine which route
|
|
167
|
+
to load. It's important that you leave any "catch-all" route (e.g. a "Page not found" one) at the end.
|
|
168
|
+
|
|
169
|
+
### Include the router view
|
|
170
|
+
|
|
171
|
+
To display the router, in a Svelte component (usually `App.svelte`), first import the router component:
|
|
172
|
+
|
|
173
|
+
````js
|
|
174
|
+
import Router from 'svelte-spa-router'
|
|
175
|
+
````
|
|
176
|
+
|
|
177
|
+
Then, display the router anywhere you'd like by placing the component in the markup. For example:
|
|
178
|
+
|
|
179
|
+
````svelte
|
|
180
|
+
<body>
|
|
181
|
+
<Router {routes}/>
|
|
182
|
+
</body>
|
|
183
|
+
````
|
|
184
|
+
|
|
185
|
+
The `routes` prop is the dictionary defined above.
|
|
186
|
+
|
|
187
|
+
That's it! You already have all that you need for a fully-functional routing experience.
|
|
188
|
+
|
|
189
|
+
### Dynamically-imported components and code-splitting
|
|
190
|
+
|
|
191
|
+
Starting with version 3.0, svelte-spa-router supports dynamically-imported components (via the `import()` construct).
|
|
192
|
+
The advantage of using dynamic imports is that, if your bundler supports that, you can enable code-splitting and reduce
|
|
193
|
+
the size of the bundle you send to your users. This has been tested with bundlers including Rollup and Webpack.
|
|
194
|
+
|
|
195
|
+
To use dynamically-imported components, you need to leverage the `wrap` method (which can be used for a variety of
|
|
196
|
+
actions, as per the docs on [route wrapping](/Advanced%20Usage.md#route-wrapping)). First, import the `wrap` method:
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
import {wrap} from 'svelte-spa-router/wrap'
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Then, in your route definition, wrap your routes using the `wrap` method, passing a function that returns the
|
|
203
|
+
dynamically-imported component to the `asyncComponent` property:
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
wrap({
|
|
207
|
+
asyncComponent: () => import('./Foo.svelte')
|
|
208
|
+
})
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
> Note: the value of `asyncComponent` must be the **definition of a function** returning a dynamically-imported
|
|
212
|
+
> component, such as `asyncComponent: () => import('./Foo.svelte')`.
|
|
213
|
+
> Do **not** use `asyncComponent: import('./Foo.svelte')`, which is a function invocation instead.
|
|
214
|
+
|
|
215
|
+
For example, to make the Author and Book routes from the first example dynamically-imported, we'd update the code to:
|
|
216
|
+
|
|
217
|
+
````js
|
|
218
|
+
// Import the wrap method
|
|
219
|
+
import {wrap} from 'svelte-spa-router/wrap'
|
|
220
|
+
|
|
221
|
+
// Note that Author and Book are not imported here anymore, so they can be imported at runtime
|
|
222
|
+
import Home from './routes/Home.svelte'
|
|
223
|
+
import NotFound from './routes/NotFound.svelte'
|
|
224
|
+
|
|
225
|
+
const routes = {
|
|
226
|
+
'/': Home,
|
|
227
|
+
|
|
228
|
+
// Wrapping the Author component
|
|
229
|
+
'/author/:first/:last?': wrap({
|
|
230
|
+
asyncComponent: () => import('./routes/Author.svelte')
|
|
231
|
+
}),
|
|
232
|
+
|
|
233
|
+
// Wrapping the Book component
|
|
234
|
+
'/book/*': wrap({
|
|
235
|
+
asyncComponent: () => import('./routes/Book.svelte')
|
|
236
|
+
}),
|
|
237
|
+
|
|
238
|
+
// Catch-all route last
|
|
239
|
+
'*': NotFound,
|
|
240
|
+
}
|
|
241
|
+
````
|
|
242
|
+
|
|
243
|
+
The `wrap` method accepts an object with multiple properties and enables other features, including: setting a "loading"
|
|
244
|
+
component that is shown while a dynamically-imported component is being requested, adding pre-conditions (route guards),
|
|
245
|
+
passing static props, and adding custom user data.
|
|
246
|
+
|
|
247
|
+
You can learn more about all the features of `wrap` in the documentation
|
|
248
|
+
for [route wrapping](/Advanced%20Usage.md#route-wrapping).
|
|
249
|
+
|
|
250
|
+
### Navigating between pages
|
|
251
|
+
|
|
252
|
+
You can navigate between pages with normal anchor (`<a>`) tags. For example:
|
|
253
|
+
|
|
254
|
+
````svelte
|
|
255
|
+
<a href="#/book/123">Thus Spoke Zarathustra</a>
|
|
256
|
+
````
|
|
257
|
+
|
|
258
|
+
#### The `use:link` action
|
|
259
|
+
|
|
260
|
+
Rather than having to type `#` before each link, you can also use the `use:link` action:
|
|
261
|
+
|
|
262
|
+
````svelte
|
|
263
|
+
<script>
|
|
264
|
+
import {link} from 'svelte-spa-router'
|
|
265
|
+
</script>
|
|
266
|
+
<a href="/book/321" use:link>The Little Prince</a>
|
|
267
|
+
````
|
|
268
|
+
|
|
269
|
+
The `use:link` action accepts an optional parameter `opts`, which can be one of:
|
|
270
|
+
|
|
271
|
+
- A dictionary `{href: '/foo', disabled: false}` where both keys are optional:
|
|
272
|
+
- If you set a value for `href`, your link will be updated to point to that address, reactively (this will always take
|
|
273
|
+
precedence over `href` attributes, if present)
|
|
274
|
+
- Setting `disabled: true` disables the link, so clicking on that would have no effect
|
|
275
|
+
- A string with a destination (e.g. `/foo`), which is a shorthand to setting `{href: '/foo'}`.
|
|
276
|
+
|
|
277
|
+
For example:
|
|
278
|
+
|
|
279
|
+
````svelte
|
|
280
|
+
<script>
|
|
281
|
+
import {link} from 'svelte-spa-router'
|
|
282
|
+
let myLink = "/book/456"
|
|
283
|
+
</script>
|
|
284
|
+
<!-- Note the {{...}} notation because we're passing an object as parameter for a Svelte action -->
|
|
285
|
+
<a use:link={{href: myLink, disabled: false}}>The Biggest Princess</a>
|
|
286
|
+
````
|
|
287
|
+
|
|
288
|
+
The above is equivalent to:
|
|
289
|
+
|
|
290
|
+
````svelte
|
|
291
|
+
<script>
|
|
292
|
+
import {link} from 'svelte-spa-router'
|
|
293
|
+
let myLink = "/book/456"
|
|
294
|
+
</script>
|
|
295
|
+
<a use:link={myLink}>The Biggest Princess</a>
|
|
296
|
+
````
|
|
297
|
+
|
|
298
|
+
Changing the value of `myLink` will reactively update the link's `href` attribute.
|
|
299
|
+
|
|
300
|
+
#### Navigating programmatically
|
|
301
|
+
|
|
302
|
+
You can navigate between pages programmatically too:
|
|
303
|
+
|
|
304
|
+
````js
|
|
305
|
+
import {push, pop, replace} from 'svelte-spa-router'
|
|
306
|
+
|
|
307
|
+
// The push(url) method navigates to another page, just like clicking on a link
|
|
308
|
+
push('/book/42')
|
|
309
|
+
|
|
310
|
+
// The pop() method is equivalent to hitting the back button in the browser
|
|
311
|
+
pop()
|
|
312
|
+
|
|
313
|
+
// The replace(url) method navigates to a new page, but without adding a new entry in the browser's history stack
|
|
314
|
+
// So, clicking on the back button in the browser would not lead to the page users were visiting before the call to replace()
|
|
315
|
+
replace('/book/3')
|
|
316
|
+
````
|
|
317
|
+
|
|
318
|
+
These methods can be used inside Svelte markup too, for example:
|
|
319
|
+
|
|
320
|
+
````svelte
|
|
321
|
+
<button on:click={() => push('/page')}>Go somewhere</button>
|
|
322
|
+
````
|
|
323
|
+
|
|
324
|
+
The `push`, `pop` and `replace` methods perform navigation actions only in the next iteration ("tick") of the JavaScript
|
|
325
|
+
event loop. This makes it safe to use them also inside `onMount` callbacks within Svelte components.
|
|
326
|
+
|
|
327
|
+
These functions return a Promise that resolves with no value once the navigation has been triggered (in the next tick of
|
|
328
|
+
the event loop); however, please note that this will likely be before the new page has rendered.
|
|
329
|
+
|
|
330
|
+
### Parameters from routes
|
|
331
|
+
|
|
332
|
+
svelte-spa-router uses [regexparam](https://github.com/lukeed/regexparam) to parse routes, so you can add optional
|
|
333
|
+
parameters to the route. Basic syntax is:
|
|
334
|
+
|
|
335
|
+
- `/path` matches `/path` exactly (and only that)
|
|
336
|
+
- `/path/:id` matches `/path/` followed by any string, which is a named argument `id`
|
|
337
|
+
- `/path/:id/:version?` allows for an optional second named argument `version`
|
|
338
|
+
- `/path/*` matches `/path/` followed by anything, using a non-named argument
|
|
339
|
+
|
|
340
|
+
_Please refer to the documentation of regexparam for more details._
|
|
341
|
+
|
|
342
|
+
If your route contains any parameter, they will be made available to your component inside the `params` dictionary.
|
|
343
|
+
|
|
344
|
+
For example, for a route `/name/:first/:last?`, you can create this Svelte component:
|
|
345
|
+
|
|
346
|
+
````svelte
|
|
347
|
+
<p>Your name is: <b>{params.first}</b> <b>{#if params.last}{params.last}{/if}</b></p>
|
|
348
|
+
<script>
|
|
349
|
+
// You need to define the component prop "params"
|
|
350
|
+
export let params = {}
|
|
351
|
+
</script>
|
|
352
|
+
````
|
|
353
|
+
|
|
354
|
+
Non-named arguments are returned as `params.wild`.
|
|
355
|
+
|
|
356
|
+
### Getting the current page
|
|
357
|
+
|
|
358
|
+
You can get the current page from the `$location` readable store. This is a Svelte store, so it can be used reactively
|
|
359
|
+
too.
|
|
360
|
+
|
|
361
|
+
````svelte
|
|
362
|
+
<script>
|
|
363
|
+
import {location} from 'svelte-spa-router'
|
|
364
|
+
</script>
|
|
365
|
+
<p>The current page is: {$location}</p>
|
|
366
|
+
````
|
|
367
|
+
|
|
368
|
+
### Querystring parameters
|
|
369
|
+
|
|
370
|
+
You can also extract "querystring" parameters from the hash of the page. This isn't the _real_ querystring, as it's
|
|
371
|
+
located after the `#` character in the URL, but it can be used in a similar way. For example:
|
|
372
|
+
`#/books?show=authors,titles&order=1`.
|
|
373
|
+
|
|
374
|
+
When svelte-spa-router finds a "querystring" in the hash, it separates that from the location and returns it as a string
|
|
375
|
+
in the Svelte store `$querystring`. For example:
|
|
376
|
+
|
|
377
|
+
````svelte
|
|
378
|
+
<script>
|
|
379
|
+
import {location, querystring} from 'svelte-spa-router'
|
|
380
|
+
</script>
|
|
381
|
+
<p>The current page is: {$location}</p>
|
|
382
|
+
<p>The querystring is: {$querystring}</p>
|
|
383
|
+
````
|
|
384
|
+
|
|
385
|
+
With the example above, this would print:
|
|
386
|
+
|
|
387
|
+
````text
|
|
388
|
+
The current page is: /books
|
|
389
|
+
The querystring is: show=authors,titles&order=1
|
|
390
|
+
````
|
|
391
|
+
|
|
392
|
+
It's important to note that, to keep this component lightweight, svelte-spa-router **does not parse** the "querystring".
|
|
393
|
+
If you want to parse the value of `$querystring`, you can
|
|
394
|
+
use [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) available in all modern
|
|
395
|
+
browsers, or third-party modules such as [qs](https://www.npmjs.com/package/qs).
|
|
396
|
+
|
|
397
|
+
### Highlight active links
|
|
398
|
+
|
|
399
|
+
svelte-spa-router has built-in support for automatically marking links as "active", with the `use:active` action.
|
|
400
|
+
|
|
401
|
+
For example, you can use the code below to add the CSS class `active` to links that are active:
|
|
402
|
+
|
|
403
|
+
````svelte
|
|
404
|
+
<script>
|
|
405
|
+
import {link} from 'svelte-spa-router'
|
|
406
|
+
import active from 'svelte-spa-router/active'
|
|
407
|
+
</script>
|
|
408
|
+
|
|
409
|
+
<style>
|
|
410
|
+
/* Style for "active" links; need to mark this :global because the router adds the class directly */
|
|
411
|
+
:global(a.active) {
|
|
412
|
+
color: red;
|
|
413
|
+
}
|
|
414
|
+
</style>
|
|
415
|
+
|
|
416
|
+
<a href="/hello/user" use:link use:active={{path: '/hello/*', className: 'active', inactiveClassName: 'inactive'}}>Say hi!</a>
|
|
417
|
+
<a href="/hello/user" use:link use:active={'/hello/*'}>Say hi with a default className!</a>
|
|
418
|
+
<a href="/hello/user" use:link use:active>Say hi with all default options!</a>
|
|
419
|
+
````
|
|
420
|
+
|
|
421
|
+
The `active` action accepts a dictionary `options` as argument:
|
|
422
|
+
|
|
423
|
+
- `options.path`: the path that, when matched, makes the link active. In the first example above, we want the link to be
|
|
424
|
+
active when the route is `/hello/*` (the asterisk matches anything after that). As you can see, this doesn't have to
|
|
425
|
+
be the same as the path the link points to. When `options.path` is omitted or false-y, it defaults to the path
|
|
426
|
+
specified in the link's `href` attribute. This parameter can also be a regular expression that will mark the link as
|
|
427
|
+
active when it matches: for example, setting to the regular expression `/^\/*\/hi$/` will make the link active when it
|
|
428
|
+
starts with `/` and ends with `/hi`, regardless of what's in between.
|
|
429
|
+
- `options.className`: the name of the CSS class to add. This is optional, and it defaults to `active` if not present.
|
|
430
|
+
- `options.inactiveClassName`: the name of the CSS class to add when the link is _not_ active. This is optional, and it
|
|
431
|
+
defaults to nothing if not present.
|
|
432
|
+
|
|
433
|
+
As a shorthand, instead of passing a dictionary as `options`, you can pass a single string or regular expression that
|
|
434
|
+
will be interpreted as `options.path`.
|
|
435
|
+
|
|
436
|
+
### Define routes with custom regular expressions
|
|
437
|
+
|
|
438
|
+
Since version 1.2 of svelte-spa-router, it's possible to define routes using custom regular expressions too, allowing
|
|
439
|
+
for greater flexibility. However, this requires defining routes using a JavaScript Map rather than an object:
|
|
440
|
+
|
|
441
|
+
````js
|
|
442
|
+
import Home from './routes/Home.svelte'
|
|
443
|
+
import Name from './routes/Name.svelte'
|
|
444
|
+
import NotFound from './routes/NotFound.svelte'
|
|
445
|
+
|
|
446
|
+
const routes = new Map()
|
|
447
|
+
|
|
448
|
+
// You can still use strings to define routes
|
|
449
|
+
routes.set('/', Home)
|
|
450
|
+
routes.set('/hello/:first/:last?', Name)
|
|
451
|
+
|
|
452
|
+
// The keys for the next routes are regular expressions
|
|
453
|
+
// You will very likely always want to start the regular expression with ^
|
|
454
|
+
routes.set(/^\/hola\/(.*)/i, Name)
|
|
455
|
+
routes.set(/^\/buongiorno(\/([a-z]+))/i, Name)
|
|
456
|
+
|
|
457
|
+
// Catch-all, must be last
|
|
458
|
+
routes.set('*', NotFound)
|
|
459
|
+
````
|
|
460
|
+
|
|
461
|
+
When you define routes as regular expressions, the `params` prop is populated with an array with the result of the
|
|
462
|
+
matches from the regular expression.
|
|
463
|
+
|
|
464
|
+
For example, with this `Name.svelte` route:
|
|
465
|
+
|
|
466
|
+
````svelte
|
|
467
|
+
<p>Params is: <code>{JSON.stringify(params)}</code></p>
|
|
468
|
+
<script>
|
|
469
|
+
// You need to define the component prop "params"
|
|
470
|
+
export let params = {}
|
|
471
|
+
</script>
|
|
472
|
+
````
|
|
473
|
+
|
|
474
|
+
When visiting `#/hola/amigos`, the params prop will be `["/hola/amigos","amigos"]`.
|
|
475
|
+
|
|
476
|
+
This is consistent with the results of [
|
|
477
|
+
`RegExp.prototype.exec()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec).
|
|
478
|
+
|
|
479
|
+
> When defining a route using a regular expression, you can optionally
|
|
480
|
+
> use [named capturing groups](https://2ality.com/2017/05/regexp-named-capture-groups.html). When using those, in addition
|
|
481
|
+
> to finding your matches in the `params` prop, you can find the matches for named capturing groups in `params.group`.
|
|
482
|
+
> For example, consider the route:
|
|
483
|
+
>
|
|
484
|
+
> ```js
|
|
485
|
+
> routes.set(/^\/book\/(?<title>[a-z]+)$/, Book)
|
|
486
|
+
> ```
|
|
487
|
+
>
|
|
488
|
+
> When visiting `/#/book/mytitle`, the `params` prop will be an array with `["/book/mytitle", "mytitle"]`, and
|
|
489
|
+
`params.groups` will be a dictionary with `{"title": "mytitle"}`.
|
|
490
|
+
|
|
491
|
+
## Advanced usage
|
|
492
|
+
|
|
493
|
+
Check out the [Advanced Usage](/Advanced%20Usage.md) documentation for using:
|
|
494
|
+
|
|
495
|
+
- [Route wrapping](/Advanced%20Usage.md#route-wrapping), including:
|
|
496
|
+
- [Dynamically-imported routes and placeholders](/Advanced%20Usage.md#async-routes-and-loading-placeholders)
|
|
497
|
+
- [Route pre-conditions](/Advanced%20Usage.md#route-pre-conditions) ("route guards")
|
|
498
|
+
- [Adding user data to routes](/Advanced%20Usage.md#user-data)
|
|
499
|
+
- [Static props](/Advanced%20Usage.md#static-props)
|
|
500
|
+
- [`routeEvent` event](/Advanced%20Usage.md#routeevent-event)
|
|
501
|
+
- [`routeLoading` and `routeLoaded` events](/Advanced%20Usage.md#routeloading-and-routeloaded-events)
|
|
502
|
+
- [Querystring parsing](/Advanced%20Usage.md#querystring-parsing)
|
|
503
|
+
- [Static props](/Advanced%20Usage.md#static-props)
|
|
504
|
+
- [Route transitions](/Advanced%20Usage.md#route-transitions)
|
|
505
|
+
- [Nested routers](/Advanced%20Usage.md#nested-routers)
|
|
506
|
+
- [Route groups](/Advanced%20Usage.md#route-groups)
|
|
507
|
+
- [Restore scroll position](/Advanced%20Usage.md#restore-scroll-position)
|