From ba116a1b43f66e607a30fa55f9bbfa067b126ca6 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Sun, 11 Aug 2024 03:42:32 +0100 Subject: [PATCH] fix: propagate custom element component prop changes (#12774) * fix: propagate custom element component prop changes * add test --- .changeset/poor-mugs-pay.md | 5 +++ .../client/dom/elements/custom-element.js | 15 +++++++- .../propagate-prop-changes/_config.js | 37 +++++++++++++++++++ .../propagate-prop-changes/main.svelte | 7 ++++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 .changeset/poor-mugs-pay.md create mode 100644 packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/_config.js create mode 100644 packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/main.svelte diff --git a/.changeset/poor-mugs-pay.md b/.changeset/poor-mugs-pay.md new file mode 100644 index 0000000000..01f54e4604 --- /dev/null +++ b/.changeset/poor-mugs-pay.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: propagate custom element component prop changes diff --git a/packages/svelte/src/internal/client/dom/elements/custom-element.js b/packages/svelte/src/internal/client/dom/elements/custom-element.js index 1c31d0a394..a0483e9ea5 100644 --- a/packages/svelte/src/internal/client/dom/elements/custom-element.js +++ b/packages/svelte/src/internal/client/dom/elements/custom-element.js @@ -1,7 +1,7 @@ import { createClassComponent } from '../../../../legacy/legacy-client.js'; import { destroy_effect, render_effect } from '../../reactivity/effects.js'; import { append } from '../template.js'; -import { define_property, object_keys } from '../../../shared/utils.js'; +import { define_property, get_descriptor, object_keys } from '../../../shared/utils.js'; /** * @typedef {Object} CustomElementPropDefinition @@ -305,7 +305,18 @@ export function create_custom_element( set(value) { value = get_custom_element_value(prop, value, props_definition); this.$$d[prop] = value; - this.$$c?.$set({ [prop]: value }); + var component = this.$$c; + + if (component) { + // // If the instance has an accessor, use that instead + var setter = get_descriptor(component, prop)?.get; + + if (setter) { + component[prop] = value; + } else { + component.$set({ [prop]: value }); + } + } } }); }); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/_config.js new file mode 100644 index 0000000000..da451f6230 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/_config.js @@ -0,0 +1,37 @@ +import { flushSync } from 'svelte'; +import { test } from '../../assert'; +const tick = () => Promise.resolve(); + +export default test({ + async test({ assert, target }) { + target.innerHTML = ''; + await tick(); + await tick(); + + /** @type {any} */ + const el = target.querySelector('custom-element'); + const button = el.shadowRoot.querySelector('button'); + + assert.equal(button.textContent, '0'); + assert.equal(el.count, 0); + + button.click(); + + flushSync(); + + assert.equal(button.textContent, '1'); + assert.equal(el.count, 1); + + el.count = 0; + + assert.equal(button.textContent, '0'); + assert.equal(el.count, 0); + + button.click(); + + flushSync(); + + assert.equal(button.textContent, '1'); + assert.equal(el.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/main.svelte b/packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/main.svelte new file mode 100644 index 0000000000..5aafc8eecf --- /dev/null +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/propagate-prop-changes/main.svelte @@ -0,0 +1,7 @@ + + + + +