Skip to content

Commit ed82781

Browse files
committed
merge main
2 parents 13b5ef5 + 1a0b822 commit ed82781

File tree

282 files changed

+5483
-917
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

282 files changed

+5483
-917
lines changed

.changeset/big-hats-wonder.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/rare-cheetahs-laugh.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: always run `if` block code the first time

documentation/docs/02-runes/02-$state.md

Lines changed: 135 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,7 @@ let todos = $state([
3636
...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property:
3737

3838
```js
39-
// @filename: ambient.d.ts
40-
declare global {
41-
const todos: Array<{ done: boolean, text: string }>
42-
}
43-
44-
// @filename: index.js
39+
let todos = [{ done: false, text: 'add more todos' }];
4540
// ---cut---
4641
todos[0].done = !todos[0].done;
4742
```
@@ -64,6 +59,17 @@ todos.push({
6459

6560
> [!NOTE] When you update properties of proxies, the original object is _not_ mutated.
6661
62+
Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring:
63+
64+
```js
65+
let todos = [{ done: false, text: 'add more todos' }];
66+
// ---cut---
67+
let { done, text } = todos[0];
68+
69+
// this will not affect the value of `done`
70+
todos[0].done = !todos[0].done;
71+
```
72+
6773
### Classes
6874

6975
You can also use `$state` in class fields (whether public or private):
@@ -85,7 +91,42 @@ class Todo {
8591
}
8692
```
8793

88-
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields.
94+
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable.
95+
96+
When calling methods in JavaScript, the value of [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) matters. This won't work, because `this` inside the `reset` method will be the `<button>` rather than the `Todo`:
97+
98+
```svelte
99+
<button onclick={todo.reset}>
100+
reset
101+
</button>
102+
```
103+
104+
You can either use an inline function...
105+
106+
```svelte
107+
<button onclick=+++{() => todo.reset()}>+++
108+
reset
109+
</button>
110+
```
111+
112+
...or use an arrow function in the class definition:
113+
114+
```js
115+
// @errors: 7006 2554
116+
class Todo {
117+
done = $state(false);
118+
text = $state();
119+
120+
constructor(text) {
121+
this.text = text;
122+
}
123+
124+
+++reset = () => {+++
125+
this.text = '';
126+
this.done = false;
127+
}
128+
}
129+
```
89130

90131
## `$state.raw`
91132

@@ -127,3 +168,90 @@ To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snaps
127168
```
128169

129170
This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`.
171+
172+
## Passing state into functions
173+
174+
JavaScript is a _pass-by-value_ language — when you call a function, the arguments are the _values_ rather than the _variables_. In other words:
175+
176+
```js
177+
/// file: index.js
178+
// @filename: index.js
179+
// ---cut---
180+
/**
181+
* @param {number} a
182+
* @param {number} b
183+
*/
184+
function add(a, b) {
185+
return a + b;
186+
}
187+
188+
let a = 1;
189+
let b = 2;
190+
let total = add(a, b);
191+
console.log(total); // 3
192+
193+
a = 3;
194+
b = 4;
195+
console.log(total); // still 3!
196+
```
197+
198+
If `add` wanted to have access to the _current_ values of `a` and `b`, and to return the current `total` value, you would need to use functions instead:
199+
200+
```js
201+
/// file: index.js
202+
// @filename: index.js
203+
// ---cut---
204+
/**
205+
* @param {() => number} getA
206+
* @param {() => number} getB
207+
*/
208+
function add(+++getA, getB+++) {
209+
return +++() => getA() + getB()+++;
210+
}
211+
212+
let a = 1;
213+
let b = 2;
214+
let total = add+++(() => a, () => b)+++;
215+
console.log(+++total()+++); // 3
216+
217+
a = 3;
218+
b = 4;
219+
console.log(+++total()+++); // 7
220+
```
221+
222+
State in Svelte is no different — when you reference something declared with the `$state` rune...
223+
224+
```js
225+
let a = +++$state(1)+++;
226+
let b = +++$state(2)+++;
227+
```
228+
229+
...you're accessing its _current value_.
230+
231+
Note that 'functions' is broad — it encompasses properties of proxies and [`get`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) properties...
232+
233+
```js
234+
/// file: index.js
235+
// @filename: index.js
236+
// ---cut---
237+
/**
238+
* @param {{ a: number, b: number }} input
239+
*/
240+
function add(input) {
241+
return {
242+
get value() {
243+
return input.a + input.b;
244+
}
245+
};
246+
}
247+
248+
let input = $state({ a: 1, b: 2 });
249+
let total = add(input);
250+
console.log(total.value); // 3
251+
252+
input.a = 3;
253+
input.b = 4;
254+
console.log(total.value); // 7
255+
```
256+
257+
...though if you find yourself writing code like that, consider using [classes](#Classes) instead.

documentation/docs/03-template-syntax/03-each.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,30 @@ You can freely use destructuring and rest patterns in each blocks.
7474
{/each}
7575
```
7676

77+
## Each blocks without an item
78+
79+
```svelte
80+
<!--- copy: false --->
81+
{#each expression}...{/each}
82+
```
83+
84+
```svelte
85+
<!--- copy: false --->
86+
{#each expression, index}...{/each}
87+
```
88+
89+
In case you just want to render something `n` times, you can omit the `as` part ([demo](/playground/untitled#H4sIAAAAAAAAE3WR0W7CMAxFf8XKNAk0WsSeUEaRpn3Guoc0MbQiJFHiMlDVf18SOrZJ48259_jaVgZmxBEZZ28thgCNFV6xBdt1GgPj7wOji0t2EqI-wa_OleGEmpLWiID_6dIaQkMxhm1UdwKpRQhVzWSaVORJNdvWpqbhAYVsYQCNZk8thzWMC_DCHMZk3wPSThNQ088I3mghD9UwSwHwlLE5PMIzVFUFq3G7WUZ2OyUvU3JOuZU332wCXTRmtPy1NgzXZtUFp8WFw9536uWqpbIgPEaDsJBW90cTOHh0KGi2XsBq5-cT6-3nPauxXqHnsHJnCFZ3CvJVkyuCQ0mFF9TZyCQ162WGvteLKfG197Y3iv_pz_fmS68Hxt8iPBPj5HscP8YvCNX7uhYCAAA=)):
90+
91+
```svelte
92+
<div class="chess-board">
93+
{#each { length: 8 }, rank}
94+
{#each { length: 8 }, file}
95+
<div class:black={(rank + file) % 2 === 1}></div>
96+
{/each}
97+
{/each}
98+
</div>
99+
```
100+
77101
## Else blocks
78102

79103
```svelte

documentation/docs/03-template-syntax/06-snippet.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,23 @@ We can tighten things up further by declaring a generic, so that `data` and `row
246246
</script>
247247
```
248248

249+
## Exporting snippets
250+
251+
Snippets declared at the top level of a `.svelte` file can be exported from a `<script module>` for use in other components, provided they don't reference any declarations in a non-module `<script>` (whether directly or indirectly, via other snippets) ([demo](/playground/untitled#H4sIAAAAAAAAE3WPwY7CMAxEf8UyB1hRgdhjl13Bga8gHFJipEqtGyUGFUX5dxJUtEB3b9bYM_MckHVLWOKut50TMuC5tpbEY4GnuiGP5T6gXG0-ykLSB8vW2oW_UCNZq7Snv_Rjx0Kc4kpc-6OrrfwoVlK3uQ4CaGMgwsl1LUwXy0f54J9-KV4vf20cNo7YkMu22aqAz4-oOLUI9YKluDPF4h_at-hX5PFyzA1tZ84N3fGpf8YfUU6GvDumLqDKmEqCjjCHUEX4hqDTWCU5PJ6Or38c4g1cPu9tnAEAAA==)):
252+
253+
```svelte
254+
<script module>
255+
export { add };
256+
</script>
257+
258+
{#snippet add(a, b)}
259+
{a} + {b} = {a + b}
260+
{/snippet}
261+
```
262+
263+
> [!NOTE]
264+
> This requires Svelte 5.5.0 or newer
265+
249266
## Programmatic snippets
250267

251268
Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases.

documentation/docs/03-template-syntax/11-bind.md

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@ In the case of a numeric input (`type="number"` or `type="range"`), the value wi
5353

5454
If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.
5555

56+
Since 5.6.0, if an `<input>` has a `defaultValue` and is part of a form, it will revert to that value instead of the empty string when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`.
57+
58+
```svelte
59+
<script>
60+
let value = $state('');
61+
</script>
62+
63+
<form>
64+
<input bind:value defaultValue="not the empty string">
65+
<input type="reset" value="Reset">
66+
</form>
67+
```
68+
69+
> [!NOTE]
70+
> Use reset buttons sparingly, and ensure that users won't accidentally click them while trying to submit the form.
71+
5672
## `<input bind:checked>`
5773

5874
Checkbox and radio inputs can be bound with `bind:checked`:
@@ -64,16 +80,29 @@ Checkbox and radio inputs can be bound with `bind:checked`:
6480
</label>
6581
```
6682

83+
Since 5.6.0, if an `<input>` has a `defaultChecked` attribute and is part of a form, it will revert to that value instead of `false` when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`.
84+
85+
```svelte
86+
<script>
87+
let checked = $state(true);
88+
</script>
89+
90+
<form>
91+
<input type="checkbox" bind:checked defaultChecked={true}>
92+
<input type="reset" value="Reset">
93+
</form>
94+
```
95+
6796
## `<input bind:group>`
6897

6998
Inputs that work together can use `bind:group`.
7099

71100
```svelte
72101
<script>
73-
let tortilla = 'Plain';
102+
let tortilla = $state('Plain');
74103
75104
/** @type {Array<string>} */
76-
let fillings = [];
105+
let fillings = $state([]);
77106
</script>
78107
79108
<!-- grouped radio inputs are mutually exclusive -->
@@ -146,6 +175,16 @@ When the value of an `<option>` matches its text content, the attribute can be o
146175
</select>
147176
```
148177

178+
You can give the `<select>` a default value by adding a `selected` attribute to the`<option>` (or options, in the case of `<select multiple>`) that should be initially selected. If the `<select>` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`.
179+
180+
```svelte
181+
<select bind:value={selected}>
182+
<option value={a}>a</option>
183+
<option value={b} selected>b</option>
184+
<option value={c}>c</option>
185+
</select>
186+
```
187+
149188
## `<audio>`
150189

151190
`<audio>` elements have their own set of bindings — five two-way ones...
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: <svelte:boundary>
3+
---
4+
5+
```svelte
6+
<svelte:boundary onerror={handler}>...</svelte:boundary>
7+
```
8+
9+
> [!NOTE]
10+
> This feature was added in 5.3.0
11+
12+
Boundaries allow you to guard against errors in part of your app from breaking the app as a whole, and to recover from those errors.
13+
14+
If an error occurs while rendering or updating the children of a `<svelte:boundary>`, or running any [`$effect`]($effect) functions contained therein, the contents will be removed.
15+
16+
Errors occurring outside the rendering process (for example, in event handlers) are _not_ caught by error boundaries.
17+
18+
## Properties
19+
20+
For the boundary to do anything, one or both of `failed` and `onerror` must be provided.
21+
22+
### `failed`
23+
24+
If a `failed` snippet is provided, it will be rendered with the error that was thrown, and a `reset` function that recreates the contents ([demo](/playground/hello-world#H4sIAAAAAAAAE3VRy26DMBD8lS2tFCIh6JkAUlWp39Cq9EBg06CAbdlLArL87zWGKk8ORnhmd3ZnrD1WtOjFXqKO2BDGW96xqpBD5gXerm5QefG39mgQY9EIWHxueRMinLosti0UPsJLzggZKTeilLWgLGc51a3gkuCjKQ7DO7cXZotgJ3kLqzC6hmex1SZnSXTWYHcrj8LJjWTk0PHoZ8VqIdCOKayPykcpuQxAokJaG1dGybYj4gw4K5u6PKTasSbjXKgnIDlA8VvUdo-pzonraBY2bsH7HAl78mKSHZpgIcuHjq9jXSpZSLixRlveKYQUXhQVhL6GPobXAAb7BbNeyvNUs4qfRg3OnELLj5hqH9eQZqCnoBwR9lYcQxuVXeBzc8kMF8yXY4yNJ5oGiUzP_aaf_waTRGJib5_Ad3P_vbCuaYxzeNpbU0eUMPAOKh7Yw1YErgtoXyuYlPLzc10_xo_5A91zkQL_AgAA)):
25+
26+
```svelte
27+
<svelte:boundary>
28+
<FlakyComponent />
29+
30+
{#snippet failed(error, reset)}
31+
<button onclick={reset}>oops! try again</button>
32+
{/snippet}
33+
</svelte:boundary>
34+
```
35+
36+
> [!NOTE]
37+
> As with [snippets passed to components](snippet#Passing-snippets-to-components), the `failed` snippet can be passed explicitly as a property...
38+
>
39+
> ```svelte
40+
> <svelte:boundary {failed}>...</svelte:boundary>
41+
> ```
42+
>
43+
> ...or implicitly by declaring it directly inside the boundary, as in the example above.
44+
45+
### `onerror`
46+
47+
If an `onerror` function is provided, it will be called with the same two `error` and `reset` arguments. This is useful for tracking the error with an error reporting service...
48+
49+
```svelte
50+
<svelte:boundary onerror={(e) => report(e)}>
51+
...
52+
</svelte:boundary>
53+
```
54+
55+
...or using `error` and `reset` outside the boundary itself:
56+
57+
```svelte
58+
<script>
59+
let error = $state(null);
60+
let reset = $state(() => {});
61+
62+
function onerror(e, r) {
63+
error = e;
64+
reset = r;
65+
}
66+
</script>
67+
68+
<svelte:boundary {onerror}>
69+
<FlakyComponent />
70+
</svelte:boundary>
71+
72+
{#if error}
73+
<button onclick={() => {
74+
error = null;
75+
reset();
76+
}}>
77+
oops! try again
78+
</button>
79+
{/if}
80+
```
81+
82+
If an error occurs inside the `onerror` function (or if you rethrow the error), it will be handled by a parent boundary if such exists.

documentation/docs/06-runtime/01-stores.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const userState = $state({
4949
```svelte
5050
<!--- file: App.svelte --->
5151
<script>
52-
import { userState } from './state.svelte';
52+
import { userState } from './state.svelte.js';
5353
</script>
5454
5555
<p>User name: {userState.name}</p>

0 commit comments

Comments
 (0)