diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd7bbb476e..f7d15f905e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,8 +62,6 @@ When [opening a new issue](https://github.com/sveltejs/svelte/issues/new/choose) ## Pull requests -> HEADS UP: Svelte 5 will likely change a lot on the compiler. For that reason, please don't open PRs that are large in scope, touch more than a couple of files etc. In other words, bug fixes are fine, but big feature PRs will likely not be merged. - ### Proposing a change If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, you can also file an issue with [feature template](https://github.com/sveltejs/svelte/issues/new?template=feature_request.yml). diff --git a/LICENSE.md b/LICENSE.md index e2a8b89fa4..abbace7bfe 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2016-24 [these people](https://github.com/sveltejs/svelte/graphs/contributors) +Copyright (c) 2016-2025 [these people](https://github.com/sveltejs/svelte/graphs/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index be94cba63c..cfb1328495 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,6 @@ You may view [our roadmap](https://svelte.dev/roadmap) if you'd like to see what Please see the [Contributing Guide](CONTRIBUTING.md) and the [`svelte`](packages/svelte) package for information on contributing to Svelte. -### svelte.dev - -The source code for https://svelte.dev lives in the [sites](https://github.com/sveltejs/svelte/tree/master/sites/svelte.dev) folder, with all the documentation right [here](https://github.com/sveltejs/svelte/tree/master/documentation). The site is built with [SvelteKit](https://svelte.dev/docs/kit). - ## Is svelte.dev down? Probably not, but it's possible. If you can't seem to access any `.dev` sites, check out [this SuperUser question and answer](https://superuser.com/q/1413402). diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js b/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js index 1237547ebe..6b058cdc3c 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js @@ -45,7 +45,7 @@ export async function kairo_avoidable_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -74,7 +74,7 @@ export async function kairo_avoidable_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js b/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js index 8148a743ea..d1cde5958e 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js @@ -51,7 +51,7 @@ export async function kairo_broad_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -80,7 +80,7 @@ export async function kairo_broad_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js b/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js index 806042cc72..149457ede1 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js @@ -51,7 +51,7 @@ export async function kairo_deep_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -80,7 +80,7 @@ export async function kairo_deep_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js b/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js index deb9482de9..958a1bcd78 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js @@ -55,7 +55,7 @@ export async function kairo_diamond_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -84,7 +84,7 @@ export async function kairo_diamond_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js b/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js index 8eafacc9eb..b645051c09 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js @@ -48,7 +48,7 @@ export async function kairo_mux_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -77,7 +77,7 @@ export async function kairo_mux_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js b/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js index 2bddf879c9..53b85acd37 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js @@ -52,7 +52,7 @@ export async function kairo_repeated_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -81,7 +81,7 @@ export async function kairo_repeated_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js b/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js index 9d99b7815b..b9e2ad9fa4 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js @@ -65,7 +65,7 @@ export async function kairo_triangle_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -94,7 +94,7 @@ export async function kairo_triangle_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js b/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js index c30c007561..0e783732dc 100644 --- a/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js @@ -51,7 +51,7 @@ export async function kairo_unstable_unowned() { const { run, destroy } = setup(); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); @@ -80,7 +80,7 @@ export async function kairo_unstable_owned() { }); const { timing } = await fastest_test(10, () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 1000; i++) { run(); } }); diff --git a/documentation/docs/02-runes/02-$state.md b/documentation/docs/02-runes/02-$state.md index 77140dc690..49e17cd08f 100644 --- a/documentation/docs/02-runes/02-$state.md +++ b/documentation/docs/02-runes/02-$state.md @@ -44,12 +44,7 @@ todos[0].done = !todos[0].done; If you push a new object to the array, it will also be proxified: ```js -// @filename: ambient.d.ts -declare global { - const todos: Array<{ done: boolean, text: string }> -} - -// @filename: index.js +let todos = [{ done: false, text: 'add more todos' }]; // ---cut--- todos.push({ done: false, diff --git a/documentation/docs/02-runes/03-$derived.md b/documentation/docs/02-runes/03-$derived.md index 6b38f99746..24ab643b68 100644 --- a/documentation/docs/02-runes/03-$derived.md +++ b/documentation/docs/02-runes/03-$derived.md @@ -51,3 +51,20 @@ In essence, `$derived(expression)` is equivalent to `$derived.by(() => expressio Anything read synchronously inside the `$derived` expression (or `$derived.by` function body) is considered a _dependency_ of the derived state. When the state changes, the derived will be marked as _dirty_ and recalculated when it is next read. To exempt a piece of state from being treated as a dependency, use [`untrack`](svelte#untrack). + +## Update propagation + +Svelte uses something called _push-pull reactivity_ — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the 'push'), but derived values are not re-evaluated until they are actually read (the 'pull'). + +If the new value of a derived is referentially identical to its previous value, downstream updates will be skipped. In other words, Svelte will only update the text inside the button when `large` changes, not when `count` changes, even though `large` depends on `count`: + +```svelte + + + +``` diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index b338795220..1ea960de70 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -125,7 +125,11 @@ An effect only reruns when the object it reads changes, not when a property insi

{state.value} doubled is {derived.value}

``` -An effect only depends on the values that it read the last time it ran. If `a` is true, changes to `b` will [not cause this effect to rerun](/playground/untitled#H4sIAAAAAAAAE3WQ0WrDMAxFf0U1hTow1vcsMfQ7lj3YjlxEXTvEymC4_vfFC6Ewtidxde8RkrJw5DGJ9j2LoO8oWnGZJvEi-GuqIn2iZ1x1istsa6dLdqaJ1RAG9sigoYdjYs0onfYJm7fdMX85q3dE59CylA30CnJtDWxjSNHjq49XeZqXEChcT9usLUAOpIbHA0yzM78oColGhDVofLS3neZSS6mqOz-XD51ZmGOAGKwne-vztk-956CL0kAJsi7decupf4l658EUZX4I8yTWt93jSI5wFC3PC5aP8g0Aje5DcQEAAA==): +An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code. + +For instance, if `a` is `true` in the code snippet below, the code inside the `if` block will run and `b` will be evaluated. As such, changes to either `a` or `b` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE3VQzWrDMAx-FdUU4kBp71li6EPstOxge0ox8-QQK2PD-N1nLy2F0Z2Evj9_chKkP1B04pnYscc3cRCT8xhF95IEf8-Vq0DBr8rzPB_jJ3qumNERH-E2ECNxiRF9tIubWY00lgcYNAywj6wZJS8rtk83wjwgCrXHaULLUrYwKEgVGrnkx-Dx6MNFNstK5OjSbFGbwE0gdXuT_zGYrjmAuco515Hr1p_uXak3K3MgCGS9s-9D2grU-judlQYXIencnzad-tdR79qZrMyvw9wd5Z8Yv1h09dz8mn8AkM7Pfo0BAAA=). + +Conversely, if `a` is `false`, `b` will not be evaluated, and the effect will _only_ re-run when `a` changes. ```ts let a = false; @@ -134,8 +138,8 @@ let b = false; $effect(() => { console.log('running'); - if (a || b) { - console.log('inside if block'); + if (a) { + console.log('b:', b); } }); ``` @@ -193,53 +197,7 @@ The `$effect.tracking` rune is an advanced feature that tells you whether or not

in template: {$effect.tracking()}

``` -This allows you to (for example) add things like subscriptions without causing memory leaks, by putting them in child effects. Here's a `readable` function that listens to changes from a callback function as long as it's inside a tracking context: - -```ts -import { tick } from 'svelte'; - -export default function readable( - initial_value: T, - start: (callback: (update: (v: T) => T) => T) => () => void -) { - let value = $state(initial_value); - - let subscribers = 0; - let stop: null | (() => void) = null; - - return { - get value() { - // If in a tracking context ... - if ($effect.tracking()) { - $effect(() => { - // ...and there's no subscribers yet... - if (subscribers === 0) { - // ...invoke the function and listen to changes to update state - stop = start((fn) => (value = fn(value))); - } - - subscribers++; - - // The return callback is called once a listener unlistens - return () => { - tick().then(() => { - subscribers--; - // If it was the last subscriber... - if (subscribers === 0) { - // ...stop listening to changes - stop?.(); - stop = null; - } - }); - }; - }); - } - - return value; - } - }; -} -``` +It is used to implement abstractions like [`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber), which will create listeners to update reactive values but _only_ if those values are being tracked (rather than, for example, read inside an event handler). ## `$effect.root` diff --git a/documentation/docs/02-runes/05-$props.md b/documentation/docs/02-runes/05-$props.md index 58e9b36f8e..4b1775bf5a 100644 --- a/documentation/docs/02-runes/05-$props.md +++ b/documentation/docs/02-runes/05-$props.md @@ -196,4 +196,6 @@ You can, of course, separate the type declaration from the annotation: ``` +> [!NOTE] Interfaces for native DOM elements are provided in the `svelte/elements` module (see [Typing wrapper components](typescript#Typing-wrapper-components)) + Adding types is recommended, as it ensures that people using your component can easily discover which props they should provide. diff --git a/documentation/docs/03-template-syntax/12-use.md b/documentation/docs/03-template-syntax/12-use.md index f3db72a772..45de023578 100644 --- a/documentation/docs/03-template-syntax/12-use.md +++ b/documentation/docs/03-template-syntax/12-use.md @@ -50,17 +50,16 @@ The `Action` interface receives three optional type arguments — a node type (w ```svelte + + +
...
+``` + +If the value is an array, the truthy values are combined: + +```svelte + +
...
+``` + +Note that whether we're using the array or object form, we can set multiple classes simultaneously with a single condition, which is particularly useful if you're using things like Tailwind. + +Arrays can contain arrays and objects, and clsx will flatten them. This is useful for combining local classes with props, for example: + +```svelte + + + + +``` + +The user of this component has the same flexibility to use a mixture of objects, arrays and strings: + +```svelte + + + + +``` + +## The `class:` directive + +Prior to Svelte 5.16, the `class:` directive was the most convenient way to set classes on elements conditionally. + +```svelte + +
...
+
...
+``` + +As with other directives, we can use a shorthand when the name of the class coincides with the value: + +```svelte +
...
+``` + +> [!NOTE] Unless you're using an older version of Svelte, consider avoiding `class:`, since the attribute is more powerful and composable. diff --git a/documentation/docs/07-misc/02-testing.md b/documentation/docs/07-misc/02-testing.md index c8774e341f..0842019039 100644 --- a/documentation/docs/07-misc/02-testing.md +++ b/documentation/docs/07-misc/02-testing.md @@ -40,7 +40,7 @@ You can now write unit tests for code inside your `.js/.ts` files: /// file: multiplier.svelte.test.js import { flushSync } from 'svelte'; import { expect, test } from 'vitest'; -import { multiplier } from './multiplier.js'; +import { multiplier } from './multiplier.svelte.js'; test('Multiplier', () => { let double = multiplier(0, 2); @@ -53,9 +53,30 @@ test('Multiplier', () => { }); ``` +```js +/// file: multiplier.svelte.js +/** + * @param {number} initial + * @param {number} k + */ +export function multiplier(initial, k) { + let count = $state(initial); + + return { + get value() { + return count * k; + }, + /** @param {number} c */ + set: (c) => { + count = c; + } + }; +} +``` + ### Using runes inside your test files -It is possible to use runes inside your test files. First ensure your bundler knows to route the file through the Svelte compiler before running the test by adding `.svelte` to the filename (e.g `multiplier.svelte.test.js`). After that, you can use runes inside your tests. +Since Vitest processes your test files the same way as your source files, you can use runes inside your tests as long as the filename includes `.svelte`: ```js /// file: multiplier.svelte.test.js @@ -75,6 +96,21 @@ test('Multiplier', () => { }); ``` +```js +/// file: multiplier.svelte.js +/** + * @param {() => number} getCount + * @param {number} k + */ +export function multiplier(getCount, k) { + return { + get value() { + return getCount() * k; + } + }; +} +``` + If the code being tested uses effects, you need to wrap the test inside `$effect.root`: ```js @@ -105,6 +141,27 @@ test('Effect', () => { }); ``` +```js +/// file: logger.svelte.js +/** + * @param {() => any} getValue + */ +export function logger(getValue) { + /** @type {any[]} */ + let log = $state([]); + + $effect(() => { + log.push(getValue()); + }); + + return { + get value() { + return log; + } + }; +} +``` + ### Component testing It is possible to test your components in isolation using Vitest. diff --git a/documentation/docs/07-misc/04-custom-elements.md b/documentation/docs/07-misc/04-custom-elements.md index 71c66f7edc..a8e0c81763 100644 --- a/documentation/docs/07-misc/04-custom-elements.md +++ b/documentation/docs/07-misc/04-custom-elements.md @@ -125,3 +125,4 @@ Custom elements can be a useful way to package components for consumption in a n - The deprecated `let:` directive has no effect, because custom elements do not have a way to pass data to the parent component that fills the slot - Polyfills are required to support older browsers - You can use Svelte's context feature between regular Svelte components within a custom element, but you can't use them across custom elements. In other words, you can't use `setContext` on a parent custom element and read that with `getContext` in a child custom element. +- Don't declare properties or attributes starting with `on`, as their usage will be interpreted as an event listener. In other words, Svelte treats `` as `customElement.addEventListener('eworld', true)` (and not as `customElement.oneworld = true`) diff --git a/documentation/docs/07-misc/07-v5-migration-guide.md b/documentation/docs/07-misc/07-v5-migration-guide.md index 09ea84f26c..ce95bf6ac7 100644 --- a/documentation/docs/07-misc/07-v5-migration-guide.md +++ b/documentation/docs/07-misc/07-v5-migration-guide.md @@ -339,7 +339,31 @@ When spreading props, local event handlers must go _after_ the spread, or they r In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets which are more powerful and flexible, and as such slots are deprecated in Svelte 5. -They continue to work, however, and you can mix and match snippets and slots in your components. +They continue to work, however, and you can pass snippets to a component that uses slots: + +```svelte + + +
+ +``` + +```svelte + + + + + default child content + + {#snippet foo({ message })} + message from child: {message} + {/snippet} + +``` + +(The reverse is not true — you cannot pass slotted content to a component that uses [`{@render ...}`](/docs/svelte/@render) tags.) When using custom elements, you should still use `` like before. In a future version, when Svelte removes its internal version of slots, it will leave those slots as-is, i.e. output a regular DOM tag instead of transforming it. @@ -597,28 +621,57 @@ export declare const MyComponent: Component<{ To declare that a component of a certain type is required: +```js +import { ComponentA, ComponentB } from 'component-library'; +---import type { SvelteComponent } from 'svelte';--- ++++import type { Component } from 'svelte';+++ + +---let C: typeof SvelteComponent<{ foo: string }> = $state(--- ++++let C: Component<{ foo: string }> = $state(+++ + Math.random() ? ComponentA : ComponentB +); +``` + +The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (i.e. `ComponentType>` is equivalent to `Component<{ prop: string }>`). + +### bind:this changes + +Because components are no longer classes, using `bind:this` no longer returns a class instance with `$set`, `$on` and `$destroy` methods on it. It only returns the instance exports (`export function/const`) and, if you're using the `accessors` option, a getter/setter-pair for each property. + +## `` is no longer necessary + +In Svelte 4, components are _static_ — if you render ``, and the value of `Thing` changes, [nothing happens](/playground/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you had to use ``. + +This is no longer true in Svelte 5: + ```svelte - - + + + + + ``` +While migrating, keep in mind that your component's name should be capitalized (`Thing`) to distinguish it from elements, unless using dot notation. -The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (e.g. `ComponentType>` == `Component<{ prop: string }>`). +### Dot notation indicates a component -### bind:this changes +In Svelte 4, `` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks: -Because components are no longer classes, using `bind:this` no longer returns a class instance with `$set`, `$on` and `$destroy` methods on it. It only returns the instance exports (`export function/const`) and, if you're using the `accessors` option, a getter/setter-pair for each property. +```svelte +{#each items as item} + +{/each} +``` ## Whitespace handling changed @@ -653,16 +706,6 @@ The `legacy` compiler option, which generated bulkier but IE-friendly code, no l Content inside component tags becomes a snippet prop called `children`. You cannot have a separate prop by that name. -## Dot notation indicates a component - -In Svelte 4, `` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks: - -```svelte -{#each items as item} - -{/each} -``` - ## Breaking changes in runes mode Some breaking changes only apply once your component is in runes mode. @@ -700,30 +743,6 @@ In Svelte 4, doing the following triggered reactivity: This is because the Svelte compiler treated the assignment to `foo.value` as an instruction to update anything that referenced `foo`. In Svelte 5, reactivity is determined at runtime rather than compile time, so you should define `value` as a reactive `$state` field on the `Foo` class. Wrapping `new Foo()` with `$state(...)` will have no effect — only vanilla objects and arrays are made deeply reactive. -### `` is no longer necessary - -In Svelte 4, components are _static_ — if you render ``, and the value of `Thing` changes, [nothing happens](/playground/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you must use ``. - -This is no longer true in Svelte 5: - -```svelte - - - - - - - -``` - ### Touch and wheel events are passive When using `onwheel`, `onmousewheel`, `ontouchstart` and `ontouchmove` event attributes, the handlers are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) to align with browser defaults. This greatly improves responsiveness by allowing the browser to scroll the document immediately, rather than waiting to see if the event handler calls `event.preventDefault()`. diff --git a/documentation/docs/98-reference/.generated/client-errors.md b/documentation/docs/98-reference/.generated/client-errors.md index 90c9c1f9d1..2c2e0707ea 100644 --- a/documentation/docs/98-reference/.generated/client-errors.md +++ b/documentation/docs/98-reference/.generated/client-errors.md @@ -21,15 +21,19 @@ A component is attempting to bind to a non-bindable property `%key%` belonging t ### component_api_changed ``` -%parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information +%parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5 ``` +See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information. + ### component_api_invalid_new ``` -Attempted to instantiate %component% with `new %name%`, which is no longer valid in Svelte 5. If this component is not under your control, set the `compatibility.componentApi` compiler option to `4` to keep it working. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information +Attempted to instantiate %component% with `new %name%`, which is no longer valid in Svelte 5. If this component is not under your control, set the `compatibility.componentApi` compiler option to `4` to keep it working. ``` +See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information. + ### derived_references_self ``` diff --git a/documentation/docs/98-reference/.generated/client-warnings.md b/documentation/docs/98-reference/.generated/client-warnings.md index 06ca578b76..284e9a7c3e 100644 --- a/documentation/docs/98-reference/.generated/client-warnings.md +++ b/documentation/docs/98-reference/.generated/client-warnings.md @@ -52,7 +52,7 @@ Your `console.%method%` contained `$state` proxies. Consider using `$inspect(... When logging a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), browser devtools will log the proxy itself rather than the value it represents. In the case of Svelte, the 'target' of a `$state` proxy might not resemble its current value, which can be confusing. -The easiest way to log a value as it changes over time is to use the [`$inspect`](https://svelte.dev/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](https://svelte.dev/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value. +The easiest way to log a value as it changes over time is to use the [`$inspect`](/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value. ### event_handler_invalid @@ -222,3 +222,15 @@ Reactive `$state(...)` proxies and the values they proxy have different identiti ``` To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy. + +### transition_slide_display + +``` +The `slide` transition does not work correctly for elements with `display: %value%` +``` + +The [slide](/docs/svelte/svelte-transition#slide) transition works by animating the `height` of the element, which requires a `display` style like `block`, `flex` or `grid`. It does not work for: + +- `display: inline` (which is the default for elements like ``), and its variants like `inline-block`, `inline-flex` and `inline-grid` +- `display: table` and `table-[name]`, which are the defaults for elements like `` and `` +- `display: contents` diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index 298363f78d..a867cfe88c 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -331,7 +331,39 @@ The $ prefix is reserved, and cannot be used for variables and imports ### each_item_invalid_assignment ``` -Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`) +Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`) +``` + +In legacy mode, it was possible to reassign or bind to the each block argument itself: + +```svelte + + +{#each array as entry} + + + + + +{/each} +``` + +This turned out to be buggy and unpredictable, particularly when working with derived values (such as `array.map(...)`), and as such is forbidden in runes mode. You can achieve the same outcome by using the index instead: + +```svelte + + +{#each array as entry, i} + + + + + +{/each} ``` ### effect_invalid_placement @@ -1012,6 +1044,12 @@ Unexpected end of input '%word%' is a reserved word in JavaScript and cannot be used here ``` +### unterminated_string_constant + +``` +Unterminated string constant +``` + ### void_element_invalid_content ``` diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md index 3d515305fe..57396bd7fd 100644 --- a/documentation/docs/98-reference/.generated/compile-warnings.md +++ b/documentation/docs/98-reference/.generated/compile-warnings.md @@ -62,7 +62,7 @@ Enforce that `autofocus` is not used on elements. Autofocusing elements can caus ### a11y_click_events_have_key_events ``` -Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as ``; + $$payload.out += ` `; } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js index a4bbea582b..2270005ee0 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js @@ -1,8 +1,8 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; export default function Svelte_element($$anchor, $$props) { - let tag = $.prop($$props, "tag", 3, 'hr'); + let tag = $.prop($$props, 'tag', 3, 'hr'); var fragment = $.comment(); var node = $.first_child(fragment); diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js index 4a766f7de5..4426ad1164 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Svelte_element($$payload, $$props) { let { tag = 'hr' } = $$props; diff --git a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js index 8ba14526aa..8e343fcf36 100644 --- a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/client/index.svelte.js @@ -1,5 +1,5 @@ -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal/client"; +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; var root = $.template(`

`); @@ -16,8 +16,8 @@ export default function Text_nodes_deriveds($$anchor) { } var p = root(); - const stringified_text = $.derived(() => text1() ?? ""); - const stringified_text_1 = $.derived(() => text2() ?? ""); + const stringified_text = $.derived(() => text1() ?? ''); + const stringified_text_1 = $.derived(() => text2() ?? ''); var text = $.child(p); $.template_effect(() => $.set_text(text, `${$.get(stringified_text)}${$.get(stringified_text_1)}`)); diff --git a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js index f7dc4176e4..6f019647f5 100644 --- a/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/text-nodes-deriveds/_expected/server/index.svelte.js @@ -1,4 +1,4 @@ -import * as $ from "svelte/internal/server"; +import * as $ from 'svelte/internal/server'; export default function Text_nodes_deriveds($$payload) { let count1 = 0; diff --git a/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js b/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js index 74a2185076..c2b2fe766a 100644 --- a/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js +++ b/packages/svelte/tests/sourcemaps/samples/css-injected-map/_config.js @@ -30,7 +30,7 @@ export default test({ async test({ assert, code_client }) { // Check that the css source map embedded in the js is accurate const match = code_client.match( - /code: "(.*?)(?:\\n\/\*# sourceMappingURL=data:(.*?);charset=(.*?);base64,(.*?) \*\/)?"/ + /code: '(.*?)(?:\\n\/\*# sourceMappingURL=data:(.*?);charset=(.*?);base64,(.*?) \*\/)?'/ ); assert.ok(match); diff --git a/packages/svelte/tests/validator/samples/a11y-click-events-have-key-events/warnings.json b/packages/svelte/tests/validator/samples/a11y-click-events-have-key-events/warnings.json index a1628842fb..0a759da957 100644 --- a/packages/svelte/tests/validator/samples/a11y-click-events-have-key-events/warnings.json +++ b/packages/svelte/tests/validator/samples/a11y-click-events-have-key-events/warnings.json @@ -1,7 +1,7 @@ [ { "code": "a11y_click_events_have_key_events", - "message": "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as `