From b6bf735a23b36927d7f3b2414bc0555db5d5c567 Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti Date: Thu, 13 Feb 2025 23:09:56 +0100 Subject: [PATCH 01/14] fix: correctly ssr component in `svelte:head` with `$props.id()` or `css='injected'` (#15291) --- .changeset/thirty-feet-tap.md | 5 +++++ packages/svelte/src/internal/server/index.js | 9 ++++++--- packages/svelte/src/internal/server/types.d.ts | 2 ++ .../samples/head-component-props-id/HeadNested.svelte | 5 +++++ .../samples/head-component-props-id/_config.js | 3 +++ .../samples/head-component-props-id/main.svelte | 8 ++++++++ 6 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 .changeset/thirty-feet-tap.md create mode 100644 packages/svelte/tests/server-side-rendering/samples/head-component-props-id/HeadNested.svelte create mode 100644 packages/svelte/tests/server-side-rendering/samples/head-component-props-id/_config.js create mode 100644 packages/svelte/tests/server-side-rendering/samples/head-component-props-id/main.svelte diff --git a/.changeset/thirty-feet-tap.md b/.changeset/thirty-feet-tap.md new file mode 100644 index 0000000000..5f7e589064 --- /dev/null +++ b/.changeset/thirty-feet-tap.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly ssr component in `svelte:head` with `$props.id()` or `css='injected'` diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index c4e5d318dc..728f2ebc2a 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -34,7 +34,9 @@ export function copy_payload({ out, css, head, uid }) { css: new Set(css), head: { title: head.title, - out: head.out + out: head.out, + css: new Set(head.css), + uid: head.uid }, uid }; @@ -99,12 +101,13 @@ function props_id_generator() { * @returns {RenderOutput} */ export function render(component, options = {}) { + const uid = options.uid ?? props_id_generator(); /** @type {Payload} */ const payload = { out: '', css: new Set(), - head: { title: '', out: '' }, - uid: options.uid ?? props_id_generator() + head: { title: '', out: '', css: new Set(), uid }, + uid }; const prev_on_destroy = on_destroy; diff --git a/packages/svelte/src/internal/server/types.d.ts b/packages/svelte/src/internal/server/types.d.ts index 8a241deecd..2fffdbbdf0 100644 --- a/packages/svelte/src/internal/server/types.d.ts +++ b/packages/svelte/src/internal/server/types.d.ts @@ -17,6 +17,8 @@ export interface Payload { head: { title: string; out: string; + uid: () => string; + css: Set<{ hash: string; code: string }>; }; /** Function that generates a unique ID */ uid: () => string; diff --git a/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/HeadNested.svelte b/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/HeadNested.svelte new file mode 100644 index 0000000000..0784208798 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/HeadNested.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/_config.js b/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/_config.js new file mode 100644 index 0000000000..f47bee71df --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/main.svelte b/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/main.svelte new file mode 100644 index 0000000000..e32b40e9ed --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/head-component-props-id/main.svelte @@ -0,0 +1,8 @@ + + + + + + From 8b977253f3573978f3678ed0d618a6a75f32cb1a Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti Date: Fri, 14 Feb 2025 16:22:52 +0100 Subject: [PATCH 02/14] chore: fix `$props.id` tests (#15294) * chore: fix `$props.id` tests * chore: reset uid between tests --- packages/svelte/src/internal/client/dom/template.js | 4 ++++ packages/svelte/tests/runtime-legacy/shared.ts | 2 ++ .../svelte/tests/runtime-runes/samples/props-id/_config.js | 4 +--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index 6ff3b0fa19..575bf55cf6 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -252,6 +252,10 @@ export function append(anchor, dom) { let uid = 1; +export function reset_props_id() { + uid = 1; +} + /** * Create (or hydrate) an unique UID for the component instance. */ diff --git a/packages/svelte/tests/runtime-legacy/shared.ts b/packages/svelte/tests/runtime-legacy/shared.ts index e6dc0f385b..76036852c2 100644 --- a/packages/svelte/tests/runtime-legacy/shared.ts +++ b/packages/svelte/tests/runtime-legacy/shared.ts @@ -11,6 +11,7 @@ import { setup_html_equal } from '../html_equal.js'; import { raf } from '../animation-helpers.js'; import type { CompileOptions } from '#compiler'; import { suite_with_variants, type BaseTest } from '../suite.js'; +import { reset_props_id } from '../../src/internal/client/dom/template.js'; type Assert = typeof import('vitest').assert & { htmlEqual(a: string, b: string, description?: string): void; @@ -345,6 +346,7 @@ async function run_test_variant( if (runes) { props = proxy({ ...(config.props || {}) }); + reset_props_id(); if (manual_hydrate) { hydrate_fn = () => { instance = hydrate(mod.default, { diff --git a/packages/svelte/tests/runtime-runes/samples/props-id/_config.js b/packages/svelte/tests/runtime-runes/samples/props-id/_config.js index 9d91b98e0f..416ef6cfbe 100644 --- a/packages/svelte/tests/runtime-runes/samples/props-id/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/props-id/_config.js @@ -43,8 +43,6 @@ export default test({ ` ); } else { - // `c6` because this runs after the `dom` tests - // (slightly brittle but good enough for now) assert.htmlEqual( target.innerHTML, ` @@ -53,7 +51,7 @@ export default test({

s2

s3

s4

-

c6

+

c1

` ); } From 7e3253745e3921d5718dce3ee5d5a9e72d471f58 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Sat, 15 Feb 2025 00:03:52 +0100 Subject: [PATCH 03/14] fix: ensure AST analysis on `svelte.js` modules succeeds (#15297) This was the result of a `@ts-expect-error` silencing other type errors, which lead to this creeping in. This changes it so that the object is fully set, so we'll get type errors when new properties need to be added fixes #15284 --- .changeset/good-spiders-own.md | 5 +++++ .../src/compiler/phases/2-analyze/index.js | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 .changeset/good-spiders-own.md diff --git a/.changeset/good-spiders-own.md b/.changeset/good-spiders-own.md new file mode 100644 index 0000000000..aacbda133e --- /dev/null +++ b/.changeset/good-spiders-own.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure AST analysis on `svelte.js` modules succeeds diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 846abcf7df..93c438c852 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -258,8 +258,20 @@ export function analyze_module(ast, options) { { scope, scopes, - // @ts-expect-error TODO - analysis + analysis: /** @type {ComponentAnalysis} */ (analysis), + derived_state: [], + // TODO the following are not needed for modules, but we have to pass them in order to avoid type error, + // and reducing the type would result in a lot of tedious type casts elsewhere - find a good solution one day + ast_type: /** @type {any} */ (null), + component_slots: new Set(), + expression: null, + function_depth: 0, + has_props_rune: false, + instance_scope: /** @type {any} */ (null), + options: /** @type {ValidatedCompileOptions} */ (options), + parent_element: null, + reactive_statement: null, + reactive_statements: new Map() }, visitors ); From 32b78c995422c59ade2359de86f87b0cb5239e53 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 00:05:21 +0100 Subject: [PATCH 04/14] Version Packages (#15279) Co-authored-by: github-actions[bot] --- .changeset/good-spiders-own.md | 5 ----- .changeset/short-fireants-talk.md | 5 ----- .changeset/thirty-feet-tap.md | 5 ----- packages/svelte/CHANGELOG.md | 10 ++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 .changeset/good-spiders-own.md delete mode 100644 .changeset/short-fireants-talk.md delete mode 100644 .changeset/thirty-feet-tap.md diff --git a/.changeset/good-spiders-own.md b/.changeset/good-spiders-own.md deleted file mode 100644 index aacbda133e..0000000000 --- a/.changeset/good-spiders-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: ensure AST analysis on `svelte.js` modules succeeds diff --git a/.changeset/short-fireants-talk.md b/.changeset/short-fireants-talk.md deleted file mode 100644 index c26bdc9c8b..0000000000 --- a/.changeset/short-fireants-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: ignore typescript abstract methods diff --git a/.changeset/thirty-feet-tap.md b/.changeset/thirty-feet-tap.md deleted file mode 100644 index 5f7e589064..0000000000 --- a/.changeset/thirty-feet-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: correctly ssr component in `svelte:head` with `$props.id()` or `css='injected'` diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index ff3b08fe7a..948a914778 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,15 @@ # svelte +## 5.20.1 + +### Patch Changes + +- fix: ensure AST analysis on `svelte.js` modules succeeds ([#15297](https://github.com/sveltejs/svelte/pull/15297)) + +- fix: ignore typescript abstract methods ([#15267](https://github.com/sveltejs/svelte/pull/15267)) + +- fix: correctly ssr component in `svelte:head` with `$props.id()` or `css='injected'` ([#15291](https://github.com/sveltejs/svelte/pull/15291)) + ## 5.20.0 ### Minor Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index bea1efd7b4..3261243832 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.20.0", + "version": "5.20.1", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index b246076156..9f1873efc7 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.20.0'; +export const VERSION = '5.20.1'; export const PUBLIC_VERSION = '5'; From c40392c1e8437ae564737d75cbbc4ef3ebf7b0f0 Mon Sep 17 00:00:00 2001 From: adiGuba Date: Sat, 15 Feb 2025 09:39:44 +0100 Subject: [PATCH 05/14] chore: remove options.uid in render() (#15302) * remove options.uid in render() * changeset * chore: update changeset --------- Co-authored-by: Paolo Ricciuti --- .changeset/kind-kiwis-train.md | 5 +++++ packages/svelte/src/internal/server/index.js | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/kind-kiwis-train.md diff --git a/.changeset/kind-kiwis-train.md b/.changeset/kind-kiwis-train.md new file mode 100644 index 0000000000..c40cf761b2 --- /dev/null +++ b/.changeset/kind-kiwis-train.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: remove unused `options.uid` in `render` diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index 728f2ebc2a..e8ffeed2fe 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -97,11 +97,11 @@ function props_id_generator() { * Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app. * @template {Record} Props * @param {import('svelte').Component | ComponentType>} component - * @param {{ props?: Omit; context?: Map, uid?: () => string }} [options] + * @param {{ props?: Omit; context?: Map }} [options] * @returns {RenderOutput} */ export function render(component, options = {}) { - const uid = options.uid ?? props_id_generator(); + const uid = props_id_generator(); /** @type {Payload} */ const payload = { out: '', From 75f81991c27e9602d4bb3eb44aec8775de0713af Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Sun, 16 Feb 2025 23:29:22 -0800 Subject: [PATCH 06/14] docs(bindable): fix `file:` annotation for App.svelte (#15314) --- documentation/docs/02-runes/06-$bindable.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/06-$bindable.md b/documentation/docs/02-runes/06-$bindable.md index 14bc8ddbec..c12c2bf490 100644 --- a/documentation/docs/02-runes/06-$bindable.md +++ b/documentation/docs/02-runes/06-$bindable.md @@ -33,7 +33,7 @@ Now, a component that uses `` can add the [`bind:`](bind) directive ```svelte -/// App.svelte +/// file: App.svelte + +{#each $array as item} +
+{/each} From 073f4d8911a63164d685152cef973631c3110dc8 Mon Sep 17 00:00:00 2001 From: tomoam <29677552+tomoam@users.noreply.github.com> Date: Mon, 17 Feb 2025 23:52:56 +0900 Subject: [PATCH 09/14] fix: prevent writable store value from becoming a proxy when reassigning using $-prefix (#15283) fixes #15281 --- .changeset/lovely-chairs-compete.md | 5 +++++ .../client/visitors/AssignmentExpression.js | 1 + .../samples/store-reassign-object/_config.js | 7 +++++++ .../samples/store-reassign-object/main.svelte | 11 +++++++++++ 4 files changed, 24 insertions(+) create mode 100644 .changeset/lovely-chairs-compete.md create mode 100644 packages/svelte/tests/runtime-runes/samples/store-reassign-object/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/store-reassign-object/main.svelte diff --git a/.changeset/lovely-chairs-compete.md b/.changeset/lovely-chairs-compete.md new file mode 100644 index 0000000000..d311a3dde6 --- /dev/null +++ b/.changeset/lovely-chairs-compete.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: prevent writable store value from becoming a proxy when reassigning using $-prefix diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js index 0c70f7e00c..a8c615af93 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js @@ -118,6 +118,7 @@ function build_assignment(operator, left, right, context) { binding.kind !== 'prop' && binding.kind !== 'bindable_prop' && binding.kind !== 'raw_state' && + binding.kind !== 'store_sub' && context.state.analysis.runes && should_proxy(right, context.state.scope) && is_non_coercive_operator(operator) diff --git a/packages/svelte/tests/runtime-runes/samples/store-reassign-object/_config.js b/packages/svelte/tests/runtime-runes/samples/store-reassign-object/_config.js new file mode 100644 index 0000000000..f9a329889d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-reassign-object/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ target, assert }) { + assert.htmlEqual(target.innerHTML, `

bar

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/store-reassign-object/main.svelte b/packages/svelte/tests/runtime-runes/samples/store-reassign-object/main.svelte new file mode 100644 index 0000000000..ecffbb2d83 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-reassign-object/main.svelte @@ -0,0 +1,11 @@ + + +

{clone.name}

From 575900de885c84aa6498e3ec121eabf7bba6ae4b Mon Sep 17 00:00:00 2001 From: Ranjan Purbey Date: Mon, 17 Feb 2025 21:42:35 +0530 Subject: [PATCH 10/14] fix: Add more checks to determine if element is non-static (#15259) Fixes #15241 --- .changeset/unlucky-laws-decide.md | 5 +++++ .../3-transform/client/visitors/shared/fragment.js | 11 +++++++++++ .../samples/element-dir-attribute-sibling/_config.js | 9 +++++++++ .../samples/element-dir-attribute-sibling/main.svelte | 1 + .../input-checked-attribute-sibling/_config.js | 9 +++++++++ .../input-checked-attribute-sibling/_expected.html | 1 + .../input-checked-attribute-sibling/main.svelte | 1 + 7 files changed, 37 insertions(+) create mode 100644 .changeset/unlucky-laws-decide.md create mode 100644 packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/_config.js create mode 100644 packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/main.svelte create mode 100644 packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_config.js create mode 100644 packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_expected.html create mode 100644 packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/main.svelte diff --git a/.changeset/unlucky-laws-decide.md b/.changeset/unlucky-laws-decide.md new file mode 100644 index 0000000000..c5fd7c65d9 --- /dev/null +++ b/.changeset/unlucky-laws-decide.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure input elements and elements with `dir` attribute are marked as non-static diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js index 5bc3041ca4..f076d7c11e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js @@ -144,6 +144,17 @@ function is_static_element(node, state) { return false; } + if (attribute.name === 'dir') { + return false; + } + + if ( + ['input', 'textarea'].includes(node.name) && + ['value', 'checked'].includes(attribute.name) + ) { + return false; + } + if (node.name === 'option' && attribute.name === 'value') { return false; } diff --git a/packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/_config.js b/packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/_config.js new file mode 100644 index 0000000000..e3c629aef9 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + test(assert, target) { + const p = target.querySelector('p'); + + assert.equal(p?.dir, 'rtl'); + } +}); diff --git a/packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/main.svelte b/packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/main.svelte new file mode 100644 index 0000000000..802edc0fee --- /dev/null +++ b/packages/svelte/tests/hydration/samples/element-dir-attribute-sibling/main.svelte @@ -0,0 +1 @@ +

text

. diff --git a/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_config.js b/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_config.js new file mode 100644 index 0000000000..31ec66fc88 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + test(assert, target) { + const input = target.querySelector('input'); + + assert.equal(input?.checked, true); + } +}); diff --git a/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_expected.html b/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_expected.html new file mode 100644 index 0000000000..bcd53f8783 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/_expected.html @@ -0,0 +1 @@ +. diff --git a/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/main.svelte b/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/main.svelte new file mode 100644 index 0000000000..db3eae870f --- /dev/null +++ b/packages/svelte/tests/hydration/samples/input-checked-attribute-sibling/main.svelte @@ -0,0 +1 @@ +. From 0d5d9ab76080ecc61c0f9eec6670e5ac29f4d078 Mon Sep 17 00:00:00 2001 From: adiGuba Date: Mon, 17 Feb 2025 22:12:59 +0100 Subject: [PATCH 11/14] docs: fix two element_invalid_self_closing_tag warning in example (#15324) * code is incorrect (warning element_invalid_self_closing_tag) * close canvas --- documentation/docs/03-template-syntax/11-bind.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/docs/03-template-syntax/11-bind.md b/documentation/docs/03-template-syntax/11-bind.md index 119f87ed8e..c23f3b5232 100644 --- a/documentation/docs/03-template-syntax/11-bind.md +++ b/documentation/docs/03-template-syntax/11-bind.md @@ -267,7 +267,7 @@ Elements with the `contenteditable` attribute support the following bindings: ```svelte -
+
``` ## Dimensions @@ -307,7 +307,7 @@ To get a reference to a DOM node, use `bind:this`. The value will be `undefined` }); - + ``` Components also support `bind:this`, allowing you to interact with component instances programmatically. From 9091e7e930a80695ba951bfdb8170791322651fe Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 17 Feb 2025 22:16:09 +0100 Subject: [PATCH 12/14] fix: fire delegated events on target even it was disabled in the meantime (#15319) They DOM could've been updated already by the time the event bubbling logic is reached, so the target element itself could not be notified of the event because it is marked as disabled. But the target could not have been disabled because it emits the event in the first place, so we emit regardless. No test because not reproducible in jsdom environment. Fixes #15256 --- .changeset/wicked-apples-yawn.md | 5 +++++ .../svelte/src/internal/client/dom/elements/events.js | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/wicked-apples-yawn.md diff --git a/.changeset/wicked-apples-yawn.md b/.changeset/wicked-apples-yawn.md new file mode 100644 index 0000000000..3022c34fd0 --- /dev/null +++ b/.changeset/wicked-apples-yawn.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: fire delegated events on target even it was disabled in the meantime diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js index 363b8e1ed5..25ece5f569 100644 --- a/packages/svelte/src/internal/client/dom/elements/events.js +++ b/packages/svelte/src/internal/client/dom/elements/events.js @@ -237,7 +237,13 @@ export function handle_event_propagation(event) { // @ts-expect-error var delegated = current_target['__' + event_name]; - if (delegated !== undefined && !(/** @type {any} */ (current_target).disabled)) { + if ( + delegated !== undefined && + (!(/** @type {any} */ (current_target).disabled) || + // DOM could've been updated already by the time this is reached, so we check this as well + // -> the target could not have been disabled because it emits the event in the first place + event.target === current_target) + ) { if (is_array(delegated)) { var [fn, ...data] = delegated; fn.apply(current_target, [event, ...data]); From d8e78f7f578488d6f8a66b6c6ca15086768d3b34 Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti Date: Tue, 18 Feb 2025 13:33:11 +0100 Subject: [PATCH 13/14] =?UTF-8?q?fix:=20`muted`=20reactive=20without=20`bi?= =?UTF-8?q?nd`=20and=20select/autofocus=20attributes=20=E2=80=A6=20(#15326?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: `muted` reactive without `bind` and select/autofocus attributes working with function calls Co-authored-by: Joel Howse * chore: add comments --------- Co-authored-by: Joel Howse --- .changeset/silver-ties-itch.md | 5 +++ .../client/visitors/RegularElement.js | 38 ++++++++++++++----- .../samples/autofocus-with-call/_config.js | 7 ++++ .../samples/autofocus-with-call/main.svelte | 6 +++ .../muted-without-bind-works/_config.js | 13 +++++++ .../muted-without-bind-works/main.svelte | 13 +++++++ .../samples/select-value-with-call/_config.js | 7 ++++ .../select-value-with-call/main.svelte | 6 +++ 8 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 .changeset/silver-ties-itch.md create mode 100644 packages/svelte/tests/runtime-runes/samples/autofocus-with-call/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/autofocus-with-call/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/select-value-with-call/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/select-value-with-call/main.svelte diff --git a/.changeset/silver-ties-itch.md b/.changeset/silver-ties-itch.md new file mode 100644 index 0000000000..67e33dadfb --- /dev/null +++ b/.changeset/silver-ties-itch.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: `muted` reactive without `bind` and select/autofocus attributes working with function calls diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 98036aa9b6..018bdacc5e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -29,7 +29,8 @@ import { build_render_statement, build_template_chunk, build_update_assignment, - get_expression_id + get_expression_id, + memoize_expression } from './shared/utils.js'; import { visit_event_attribute } from './shared/events.js'; @@ -532,18 +533,30 @@ function build_element_attribute_update_assignment( const is_svg = context.state.metadata.namespace === 'svg' || element.name === 'svg'; const is_mathml = context.state.metadata.namespace === 'mathml'; + const is_autofocus = name === 'autofocus'; + let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) => - metadata.has_call ? get_expression_id(state, value) : value + metadata.has_call + ? // if it's autofocus we will not add this to a template effect so we don't want to get the expression id + // but separately memoize the expression + is_autofocus + ? memoize_expression(state, value) + : get_expression_id(state, value) + : value ); - if (name === 'autofocus') { + if (is_autofocus) { state.init.push(b.stmt(b.call('$.autofocus', node_id, value))); return false; } // Special case for Firefox who needs it set as a property in order to work if (name === 'muted') { - state.init.push(b.stmt(b.assignment('=', b.member(node_id, b.id('muted')), value))); + if (!has_state) { + state.init.push(b.stmt(b.assignment('=', b.member(node_id, b.id('muted')), value))); + return false; + } + state.update.push(b.stmt(b.assignment('=', b.member(node_id, b.id('muted')), value))); return false; } @@ -660,8 +673,18 @@ function build_custom_element_attribute_update_assignment(node_id, attribute, co */ function build_element_special_value_attribute(element, node_id, attribute, context) { const state = context.state; + const is_select_with_value = + // attribute.metadata.dynamic would give false negatives because even if the value does not change, + // the inner options could still change, so we need to always treat it as reactive + element === 'select' && attribute.value !== true && !is_text_attribute(attribute); + const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) => - metadata.has_call ? get_expression_id(state, value) : value + metadata.has_call + ? // if is a select with value we will also invoke `init_select` which need a reference before the template effect so we memoize separately + is_select_with_value + ? memoize_expression(context.state, value) + : get_expression_id(state, value) + : value ); const inner_assignment = b.assignment( @@ -674,11 +697,6 @@ function build_element_special_value_attribute(element, node_id, attribute, cont ) ); - const is_select_with_value = - // attribute.metadata.dynamic would give false negatives because even if the value does not change, - // the inner options could still change, so we need to always treat it as reactive - element === 'select' && attribute.value !== true && !is_text_attribute(attribute); - const update = b.stmt( is_select_with_value ? b.sequence([ diff --git a/packages/svelte/tests/runtime-runes/samples/autofocus-with-call/_config.js b/packages/svelte/tests/runtime-runes/samples/autofocus-with-call/_config.js new file mode 100644 index 0000000000..0597c2fda8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/autofocus-with-call/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, errors }) { + assert.deepEqual(errors, []); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/autofocus-with-call/main.svelte b/packages/svelte/tests/runtime-runes/samples/autofocus-with-call/main.svelte new file mode 100644 index 0000000000..cb3804af34 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/autofocus-with-call/main.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/_config.js b/packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/_config.js new file mode 100644 index 0000000000..cc4dfb37f0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + const btn = target.querySelector('button'); + ok(btn); + flushSync(() => { + btn.click(); + }); + assert.deepEqual(logs, [true]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/main.svelte b/packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/main.svelte new file mode 100644 index 0000000000..646334c1ec --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/muted-without-bind-works/main.svelte @@ -0,0 +1,13 @@ + + + + + diff --git a/packages/svelte/tests/runtime-runes/samples/select-value-with-call/_config.js b/packages/svelte/tests/runtime-runes/samples/select-value-with-call/_config.js new file mode 100644 index 0000000000..0597c2fda8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/select-value-with-call/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, errors }) { + assert.deepEqual(errors, []); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/select-value-with-call/main.svelte b/packages/svelte/tests/runtime-runes/samples/select-value-with-call/main.svelte new file mode 100644 index 0000000000..b1d60ecf6d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/select-value-with-call/main.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From 98734433376e99909fb6f2f141d9e66d0531ff4e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 17:19:18 +0100 Subject: [PATCH 14/14] Version Packages (#15304) Co-authored-by: github-actions[bot] --- .changeset/kind-kiwis-train.md | 5 ----- .changeset/little-laws-sit.md | 5 ----- .changeset/lovely-chairs-compete.md | 5 ----- .changeset/silver-ties-itch.md | 5 ----- .changeset/unlucky-laws-decide.md | 5 ----- .changeset/wicked-apples-yawn.md | 5 ----- packages/svelte/CHANGELOG.md | 16 ++++++++++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 9 files changed, 18 insertions(+), 32 deletions(-) delete mode 100644 .changeset/kind-kiwis-train.md delete mode 100644 .changeset/little-laws-sit.md delete mode 100644 .changeset/lovely-chairs-compete.md delete mode 100644 .changeset/silver-ties-itch.md delete mode 100644 .changeset/unlucky-laws-decide.md delete mode 100644 .changeset/wicked-apples-yawn.md diff --git a/.changeset/kind-kiwis-train.md b/.changeset/kind-kiwis-train.md deleted file mode 100644 index c40cf761b2..0000000000 --- a/.changeset/kind-kiwis-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -chore: remove unused `options.uid` in `render` diff --git a/.changeset/little-laws-sit.md b/.changeset/little-laws-sit.md deleted file mode 100644 index a395ea6213..0000000000 --- a/.changeset/little-laws-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: do not warn for `binding_property_non_reactive` if binding is a store in an each diff --git a/.changeset/lovely-chairs-compete.md b/.changeset/lovely-chairs-compete.md deleted file mode 100644 index d311a3dde6..0000000000 --- a/.changeset/lovely-chairs-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: prevent writable store value from becoming a proxy when reassigning using $-prefix diff --git a/.changeset/silver-ties-itch.md b/.changeset/silver-ties-itch.md deleted file mode 100644 index 67e33dadfb..0000000000 --- a/.changeset/silver-ties-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: `muted` reactive without `bind` and select/autofocus attributes working with function calls diff --git a/.changeset/unlucky-laws-decide.md b/.changeset/unlucky-laws-decide.md deleted file mode 100644 index c5fd7c65d9..0000000000 --- a/.changeset/unlucky-laws-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: ensure input elements and elements with `dir` attribute are marked as non-static diff --git a/.changeset/wicked-apples-yawn.md b/.changeset/wicked-apples-yawn.md deleted file mode 100644 index 3022c34fd0..0000000000 --- a/.changeset/wicked-apples-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: fire delegated events on target even it was disabled in the meantime diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 948a914778..ab190e1cc2 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,21 @@ # svelte +## 5.20.2 + +### Patch Changes + +- chore: remove unused `options.uid` in `render` ([#15302](https://github.com/sveltejs/svelte/pull/15302)) + +- fix: do not warn for `binding_property_non_reactive` if binding is a store in an each ([#15318](https://github.com/sveltejs/svelte/pull/15318)) + +- fix: prevent writable store value from becoming a proxy when reassigning using $-prefix ([#15283](https://github.com/sveltejs/svelte/pull/15283)) + +- fix: `muted` reactive without `bind` and select/autofocus attributes working with function calls ([#15326](https://github.com/sveltejs/svelte/pull/15326)) + +- fix: ensure input elements and elements with `dir` attribute are marked as non-static ([#15259](https://github.com/sveltejs/svelte/pull/15259)) + +- fix: fire delegated events on target even it was disabled in the meantime ([#15319](https://github.com/sveltejs/svelte/pull/15319)) + ## 5.20.1 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 3261243832..579660f9d7 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.20.1", + "version": "5.20.2", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 9f1873efc7..0803fae736 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.20.1'; +export const VERSION = '5.20.2'; export const PUBLIC_VERSION = '5';