diff --git a/.changeset/blue-lemons-wait.md b/.changeset/blue-lemons-wait.md new file mode 100644 index 000000000000..d6c7004678d6 --- /dev/null +++ b/.changeset/blue-lemons-wait.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: collect all necessary setters of html elements when spreading attributes diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 05ccba12e077..5e39228f2b11 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -1,6 +1,6 @@ import { DEV } from 'esm-env'; import { hydrating } from '../hydration.js'; -import { get_descriptors, map_get, map_set, object_assign } from '../../utils.js'; +import { get_descriptors, get_prototype_of, map_get, map_set } from '../../utils.js'; import { AttributeAliases, DelegatedEvents, namespace_svg } from '../../../../constants.js'; import { delegate } from './events.js'; import { autofocus } from './misc.js'; @@ -241,14 +241,20 @@ var setters_cache = new Map(); function get_setters(element) { /** @type {string[]} */ var setters = []; + var descriptors; + var proto = get_prototype_of(element); - // @ts-expect-error - var descriptors = get_descriptors(element.__proto__); + // Stop at Element, from there on there's only unnecessary setters we're not interested in + while (proto.constructor.name !== 'Element') { + descriptors = get_descriptors(proto); - for (var key in descriptors) { - if (descriptors[key].set && !always_set_through_set_attribute.includes(key)) { - setters.push(key); + for (var key in descriptors) { + if (descriptors[key].set && !always_set_through_set_attribute.includes(key)) { + setters.push(key); + } } + + proto = get_prototype_of(proto); } return setters; diff --git a/packages/svelte/tests/runtime-browser/test-ssr.ts b/packages/svelte/tests/runtime-browser/test-ssr.ts index 698ae382abe0..6a92373c936a 100644 --- a/packages/svelte/tests/runtime-browser/test-ssr.ts +++ b/packages/svelte/tests/runtime-browser/test-ssr.ts @@ -17,10 +17,7 @@ export async function run_ssr_test( test_dir: string ) { try { - await compile_directory(test_dir, 'server', { - ...config.compileOptions, - runes: test_dir.includes('runtime-runes') - }); + await compile_directory(test_dir, 'server', config.compileOptions); const Component = (await import(`${test_dir}/_output/server/main.svelte.js`)).default; const { html } = render(Component, { props: config.props || {} }); diff --git a/packages/svelte/tests/runtime-runes/samples/attribute-spread-hidden/_config.js b/packages/svelte/tests/runtime-runes/samples/attribute-spread-hidden/_config.js new file mode 100644 index 000000000000..c3ed351465bb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/attribute-spread-hidden/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + async test({ target, assert }) { + const div = target.querySelector('div'); + const btn = target.querySelector('button'); + + assert.equal(div?.hidden, true); + + await btn?.click(); + assert.equal(div?.hidden, false); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/attribute-spread-hidden/main.svelte b/packages/svelte/tests/runtime-runes/samples/attribute-spread-hidden/main.svelte new file mode 100644 index 000000000000..10bec8b6f5a7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/attribute-spread-hidden/main.svelte @@ -0,0 +1,15 @@ + + + + +