-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: correctly set custom element props (#14508)
fixes #14391 In #13337 the "when to set as a property" logic for custom elements was adjusted. A bug was introduced during this, and it consists of several parts, of which the latter I'm not sure what's the best solution, hence opening this to discuss. The problem is that during set_custom_element_data, get_setters is the only check done to differentiate between setting the value as a prop (has a setter) or as an attribute (doesn't have a setter). The solution is to take into account whether or not the custom element is already registered, and defer getting (and caching) its setters until then. Instead, fall back to a "an object is always set as a prop" heuristic.
- Loading branch information
1 parent
cb5734a
commit a2539cf
Showing
4 changed files
with
77 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'svelte': patch | ||
--- | ||
|
||
fix: take into account registration state when setting custom element props |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
packages/svelte/tests/runtime-browser/custom-elements-samples/late-ce-mount/_config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { flushSync } from 'svelte'; | ||
import { test } from '../../assert'; | ||
|
||
const tick = () => Promise.resolve(); | ||
|
||
// Check that rendering a custom element and setting a property before it is registered | ||
// does not break the "when to set this as a property" logic | ||
export default test({ | ||
async test({ assert, target }) { | ||
target.innerHTML = '<custom-element></custom-element>'; | ||
await tick(); | ||
await tick(); | ||
|
||
const ce_root = target.querySelector('custom-element').shadowRoot; | ||
|
||
ce_root.querySelector('button')?.click(); | ||
flushSync(); | ||
await tick(); | ||
await tick(); | ||
|
||
const inner_ce_root = ce_root.querySelectorAll('set-property-before-mounted'); | ||
assert.htmlEqual(inner_ce_root[0].shadowRoot.innerHTML, 'object|{"foo":"bar"}'); | ||
assert.htmlEqual(inner_ce_root[1].shadowRoot.innerHTML, 'object|{"foo":"bar"}'); | ||
} | ||
}); |
31 changes: 31 additions & 0 deletions
31
packages/svelte/tests/runtime-browser/custom-elements-samples/late-ce-mount/main.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<svelte:options customElement="custom-element" /> | ||
|
||
<script lang="ts"> | ||
import { onMount } from 'svelte'; | ||
class CustomElement extends HTMLElement { | ||
constructor() { | ||
super(); | ||
this.attachShadow({ mode: 'open' }); | ||
Object.defineProperty(this, 'property', { | ||
set: (value) => { | ||
this.shadowRoot.innerHTML = typeof value + '|' + JSON.stringify(value); | ||
} | ||
}); | ||
} | ||
} | ||
onMount(async () => { | ||
customElements.define('set-property-before-mounted', CustomElement); | ||
}); | ||
let property = $state(); | ||
</script> | ||
|
||
<button onclick={() => (property = { foo: 'bar' })}>Update</button> | ||
<!-- one that's there before it's registered --> | ||
<set-property-before-mounted {property}></set-property-before-mounted> | ||
<!-- and one that's after registration but sets property to an object right away --> | ||
{#if property} | ||
<set-property-before-mounted {property}></set-property-before-mounted> | ||
{/if} |