From 77f91459b61d895ddf8b15600e86f9699eba778d Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti Date: Wed, 22 May 2024 12:33:29 +0200 Subject: [PATCH] fix: update value like attributes in a separate template_effect (#11720) * fix: update value like attributes in a separate template_effect * chore: remove unnecessary commented code * chore: add test for spread values --- .changeset/sour-jeans-collect.md | 5 +++ .../3-transform/client/visitors/template.js | 30 ++++++++++++++-- .../_config.js | 34 +++++++++++++++++++ .../main.svelte | 13 +++++++ .../_config.js | 34 +++++++++++++++++++ .../main.svelte | 17 ++++++++++ .../_config.js | 34 +++++++++++++++++++ .../main.svelte | 13 +++++++ 8 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 .changeset/sour-jeans-collect.md create mode 100644 packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/_config.js create mode 100644 packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/main.svelte diff --git a/.changeset/sour-jeans-collect.md b/.changeset/sour-jeans-collect.md new file mode 100644 index 0000000000..3e39d9ae04 --- /dev/null +++ b/.changeset/sour-jeans-collect.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: update value like attributes in a separate template_effect diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index cf4f3adc73..7b317a1f1b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -467,9 +467,16 @@ function serialize_dynamic_element_attributes(attributes, context, element_id) { * @param {import('estree').Identifier} node_id * @param {import('#compiler').Attribute} attribute * @param {import('../types.js').ComponentContext} context + * @param {boolean} needs_isolation * @returns {boolean} */ -function serialize_element_attribute_update_assignment(element, node_id, attribute, context) { +function serialize_element_attribute_update_assignment( + element, + node_id, + attribute, + context, + needs_isolation +) { const state = context.state; const name = get_attribute_name(element, attribute, context); const is_svg = context.state.metadata.namespace === 'svg'; @@ -514,7 +521,7 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu } if (attribute.metadata.dynamic) { - if (contains_call_expression) { + if (contains_call_expression || needs_isolation) { state.init.push(serialize_update(update)); } else { state.update.push(update); @@ -2065,7 +2072,24 @@ export const template_visitors = { const is = is_custom_element && child_metadata.namespace !== 'foreign' ? serialize_custom_element_attribute_update_assignment(node_id, attribute, context) - : serialize_element_attribute_update_assignment(node, node_id, attribute, context); + : serialize_element_attribute_update_assignment( + node, + node_id, + attribute, + context, + /** + * if the input needs input or content reset we also + * want to isolate the template effect or else every + * unrelated change will reset the value (and the user could) + * change the value outside of the reactivity + * + * + * + * should only be updated when val changes and not when another + * unrelated variable changes. + * */ + needs_content_reset || needs_input_reset + ); if (is) is_attributes_reactive = true; } } diff --git a/packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/_config.js new file mode 100644 index 0000000000..d2a0703301 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/_config.js @@ -0,0 +1,34 @@ +import { test, ok } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client'], + + async test({ assert, target }) { + /** + * @type {HTMLInputElement | null} + */ + const input = target.querySelector('input[type=text]'); + const button = target.querySelector('button'); + /** + * @type {HTMLInputElement | null} + */ + const checkbox = target.querySelector('input[type=checkbox]'); + const textarea = target.querySelector('textarea'); + ok(input); + ok(button); + ok(checkbox); + ok(textarea); + + flushSync(() => { + input.value = 'foo'; + checkbox.click(); + textarea.innerHTML = 'bar'; + button.click(); + }); + + assert.equal(input.value, 'foo'); + assert.equal(checkbox.checked, true); + assert.equal(textarea.innerHTML, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/main.svelte new file mode 100644 index 0000000000..897c141b65 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/value-attribute-isolated-update/main.svelte @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/_config.js b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/_config.js new file mode 100644 index 0000000000..d2a0703301 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/_config.js @@ -0,0 +1,34 @@ +import { test, ok } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client'], + + async test({ assert, target }) { + /** + * @type {HTMLInputElement | null} + */ + const input = target.querySelector('input[type=text]'); + const button = target.querySelector('button'); + /** + * @type {HTMLInputElement | null} + */ + const checkbox = target.querySelector('input[type=checkbox]'); + const textarea = target.querySelector('textarea'); + ok(input); + ok(button); + ok(checkbox); + ok(textarea); + + flushSync(() => { + input.value = 'foo'; + checkbox.click(); + textarea.innerHTML = 'bar'; + button.click(); + }); + + assert.equal(input.value, 'foo'); + assert.equal(checkbox.checked, true); + assert.equal(textarea.innerHTML, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/main.svelte b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/main.svelte new file mode 100644 index 0000000000..b5c47f0131 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update-spread/main.svelte @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/_config.js b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/_config.js new file mode 100644 index 0000000000..d2a0703301 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/_config.js @@ -0,0 +1,34 @@ +import { test, ok } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client'], + + async test({ assert, target }) { + /** + * @type {HTMLInputElement | null} + */ + const input = target.querySelector('input[type=text]'); + const button = target.querySelector('button'); + /** + * @type {HTMLInputElement | null} + */ + const checkbox = target.querySelector('input[type=checkbox]'); + const textarea = target.querySelector('textarea'); + ok(input); + ok(button); + ok(checkbox); + ok(textarea); + + flushSync(() => { + input.value = 'foo'; + checkbox.click(); + textarea.innerHTML = 'bar'; + button.click(); + }); + + assert.equal(input.value, 'foo'); + assert.equal(checkbox.checked, true); + assert.equal(textarea.innerHTML, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/main.svelte b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/main.svelte new file mode 100644 index 0000000000..35bd481a4c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/value-attribute-isolated-update/main.svelte @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file