diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index ad72bfabb03a..4f1be5e299fd 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.35.3 + +### Patch Changes + +- fix: account for mounting when `select_option` in `attribute_effect` ([#16309](https://github.com/sveltejs/svelte/pull/16309)) + +- fix: do not proxify the value assigned to a derived ([#16302](https://github.com/sveltejs/svelte/pull/16302)) + ## 5.35.2 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 872c21a1794e..30a8f8833af1 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.35.2", + "version": "5.35.3", "type": "module", "types": "./types/index.d.ts", "engines": { 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 ce190814f8d8..7d64d60bca5a 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 @@ -137,6 +137,7 @@ function build_assignment(operator, left, right, context) { binding.kind !== 'prop' && binding.kind !== 'bindable_prop' && binding.kind !== 'raw_state' && + binding.kind !== 'derived' && binding.kind !== 'store_sub' && context.state.analysis.runes && should_proxy(right, context.state.scope) && diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 5db685cf3e90..66f484a59ace 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -491,7 +491,7 @@ export function attribute_effect( var current = set_attributes(element, prev, next, css_hash, skip_warning); if (inited && is_select && 'value' in next) { - select_option(/** @type {HTMLSelectElement} */ (element), next.value, false); + select_option(/** @type {HTMLSelectElement} */ (element), next.value); } for (let symbol of Object.getOwnPropertySymbols(effects)) { @@ -516,7 +516,7 @@ export function attribute_effect( var select = /** @type {HTMLSelectElement} */ (element); effect(() => { - select_option(select, /** @type {Record} */ (prev).value); + select_option(select, /** @type {Record} */ (prev).value, true); init_select(select); }); } diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/select.js b/packages/svelte/src/internal/client/dom/elements/bindings/select.js index 5e89686d8654..e39fb865cdf5 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/select.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/select.js @@ -9,9 +9,9 @@ import * as w from '../../../warnings.js'; * @template V * @param {HTMLSelectElement} select * @param {V} value - * @param {boolean} [mounting] + * @param {boolean} mounting */ -export function select_option(select, value, mounting) { +export function select_option(select, value, mounting = false) { if (select.multiple) { // If value is null or undefined, keep the selection as is if (value == undefined) { diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 0db353023257..a86ccfee4ff4 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -11,7 +11,7 @@ import { untrack, increment_write_version, update_effect, - reaction_sources, + source_ownership, check_dirtiness, untracking, is_destroying_effect, @@ -140,7 +140,7 @@ export function set(source, value, should_proxy = false) { (!untracking || (active_reaction.f & INSPECT_EFFECT) !== 0) && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT | INSPECT_EFFECT)) !== 0 && - !(reaction_sources?.[1].includes(source) && reaction_sources[0] === active_reaction) + !(source_ownership?.reaction === active_reaction && source_ownership.sources.includes(source)) ) { e.state_unsafe_mutation(); } diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 8e6242447e73..fce6c78b56e4 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -86,17 +86,17 @@ export function set_active_effect(effect) { /** * When sources are created within a reaction, reading and writing * them within that reaction should not cause a re-run - * @type {null | [active_reaction: Reaction, sources: Source[]]} + * @type {null | { reaction: Reaction, sources: Source[] }} */ -export let reaction_sources = null; +export let source_ownership = null; /** @param {Value} value */ export function push_reaction_value(value) { if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) { - if (reaction_sources === null) { - reaction_sources = [active_reaction, [value]]; + if (source_ownership === null) { + source_ownership = { reaction: active_reaction, sources: [value] }; } else { - reaction_sources[1].push(value); + source_ownership.sources.push(value); } } } @@ -235,7 +235,12 @@ function schedule_possible_effect_self_invalidation(signal, effect, root = true) for (var i = 0; i < reactions.length; i++) { var reaction = reactions[i]; - if (reaction_sources?.[1].includes(signal) && reaction_sources[0] === active_reaction) continue; + if ( + source_ownership?.reaction === active_reaction && + source_ownership.sources.includes(signal) + ) { + continue; + } if ((reaction.f & DERIVED) !== 0) { schedule_possible_effect_self_invalidation(/** @type {Derived} */ (reaction), effect, false); @@ -257,7 +262,7 @@ export function update_reaction(reaction) { var previous_untracked_writes = untracked_writes; var previous_reaction = active_reaction; var previous_skip_reaction = skip_reaction; - var previous_reaction_sources = reaction_sources; + var previous_reaction_sources = source_ownership; var previous_component_context = component_context; var previous_untracking = untracking; @@ -270,7 +275,7 @@ export function update_reaction(reaction) { (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null); active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; - reaction_sources = null; + source_ownership = null; set_component_context(reaction.ctx); untracking = false; read_version++; @@ -358,7 +363,7 @@ export function update_reaction(reaction) { untracked_writes = previous_untracked_writes; active_reaction = previous_reaction; skip_reaction = previous_skip_reaction; - reaction_sources = previous_reaction_sources; + source_ownership = previous_reaction_sources; set_component_context(previous_component_context); untracking = previous_untracking; @@ -739,7 +744,10 @@ export function get(signal) { // Register the dependency on the current reaction signal. if (active_reaction !== null && !untracking) { - if (!reaction_sources?.[1].includes(signal) || reaction_sources[0] !== active_reaction) { + if ( + source_ownership?.reaction !== active_reaction || + !source_ownership?.sources.includes(signal) + ) { var deps = active_reaction.deps; if (signal.rv < read_version) { signal.rv = read_version; diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 47c354c7a21e..d98b62290805 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.35.2'; +export const VERSION = '5.35.3'; export const PUBLIC_VERSION = '5'; diff --git a/packages/svelte/tests/runtime-runes/samples/select-spread-option-selected/_config.js b/packages/svelte/tests/runtime-runes/samples/select-spread-option-selected/_config.js new file mode 100644 index 000000000000..50da3ac09567 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/select-spread-option-selected/_config.js @@ -0,0 +1,9 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, instance }) { + const select = target.querySelector('select'); + ok(select); + assert.equal(select.selectedIndex, 1); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/select-spread-option-selected/main.svelte b/packages/svelte/tests/runtime-runes/samples/select-spread-option-selected/main.svelte new file mode 100644 index 000000000000..e5fc6c553538 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/select-spread-option-selected/main.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/writable-derived-4/_config.js b/packages/svelte/tests/runtime-runes/samples/writable-derived-4/_config.js new file mode 100644 index 000000000000..8d312ca73ae5 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/writable-derived-4/_config.js @@ -0,0 +1,23 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const [btn1, btn2, btn3] = target.getElementsByTagName('button'); + const [div] = target.getElementsByTagName('div'); + + flushSync(() => btn1.click()); + assert.equal(div.textContent, '1'); + flushSync(() => btn2.click()); + assert.equal(div.textContent, '1'); + flushSync(() => btn3.click()); + assert.equal(div.textContent, '2'); + + flushSync(() => btn1.click()); + assert.equal(div.textContent, '2'); + flushSync(() => btn2.click()); + assert.equal(div.textContent, '2'); + flushSync(() => btn3.click()); + assert.equal(div.textContent, '3'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/writable-derived-4/main.svelte b/packages/svelte/tests/runtime-runes/samples/writable-derived-4/main.svelte new file mode 100644 index 000000000000..a24f69ba772d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/writable-derived-4/main.svelte @@ -0,0 +1,9 @@ + + + + + + +
{count.value}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy