fix: reflect all custom element prop updates back to attribute (#8898)

fixes #8879
pull/8877/head
Simon H 1 year ago committed by GitHub
parent 4b3eb72346
commit 0aa03df086
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: reflect all custom element prop updates back to attribute

@ -269,6 +269,31 @@ if (typeof HTMLElement === 'function') {
}
}
});
// Reflect component props as attributes
const reflect_attributes = () => {
this.$$r = true;
for (const key in this.$$p_d) {
this.$$d[key] = this.$$c.$$.ctx[this.$$c.$$.props[key]];
if (this.$$p_d[key].reflect) {
const attribute_value = get_custom_element_value(
key,
this.$$d[key],
this.$$p_d,
'toAttribute'
);
if (attribute_value == null) {
this.removeAttribute(key);
} else {
this.setAttribute(this.$$p_d[key].attribute || key, attribute_value);
}
}
}
this.$$r = false;
};
this.$$c.$$.after_update.push(reflect_attributes);
reflect_attributes(); // once initially because after_update is added too late for first render
for (const type in this.$$l) {
for (const listener of this.$$l[type]) {
const unsub = this.$$c.$on(type, listener);
@ -386,21 +411,6 @@ export function create_custom_element(
value = get_custom_element_value(prop, value, props_definition);
this.$$d[prop] = value;
this.$$c?.$set({ [prop]: value });
if (props_definition[prop].reflect) {
this.$$r = true;
const attribute_value = get_custom_element_value(
prop,
value,
props_definition,
'toAttribute'
);
if (attribute_value == null) {
this.removeAttribute(prop);
} else {
this.setAttribute(props_definition[prop].attribute || prop, attribute_value);
}
this.$$r = false;
}
}
});
});

@ -1,19 +1,20 @@
<svelte:options
customElement={{
tag: "custom-element",
props: { red: { reflect: true, type: "Boolean" } },
tag: 'custom-element',
props: { red: { reflect: true, type: 'Boolean' } }
}}
/>
<script>
import "./my-widget.svelte";
import './my-widget.svelte';
export let red;
red;
</script>
<div>hi</div>
<p>hi</p>
<my-widget red white />
<button on:click={() => (red = false)}>off</button>
<my-widget {red} white />
<style>
:host([red]) div {

@ -9,6 +9,7 @@ export default async function (target) {
const ceRoot = target.querySelector('custom-element').shadowRoot;
const div = ceRoot.querySelector('div');
const p = ceRoot.querySelector('p');
const button = ceRoot.querySelector('button');
assert.equal(getComputedStyle(div).color, 'rgb(255, 0, 0)');
assert.equal(getComputedStyle(p).color, 'rgb(255, 255, 255)');
@ -19,4 +20,11 @@ export default async function (target) {
assert.equal(getComputedStyle(innerDiv).color, 'rgb(255, 0, 0)');
assert.equal(getComputedStyle(innerP).color, 'rgb(255, 255, 255)');
button.click();
await tick();
await tick();
assert.equal(getComputedStyle(div).color, 'rgb(0, 0, 0)');
assert.equal(getComputedStyle(innerDiv).color, 'rgb(0, 0, 0)');
}

Loading…
Cancel
Save