[fix] call attribute bindings for custom element if <svelte:element> render custom element (#7766)

* call attr bindings if tag is custom element

* add test
pull/7869/head
Yuichiro Yamashita 2 years ago committed by GitHub
parent c113d9d978
commit 5adac302c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -803,15 +803,31 @@ export default class ElementWrapper extends Wrapper {
const fn = this.node.namespace === namespaces.svg ? x`@set_svg_attributes` : x`@set_attributes`;
block.chunks.hydrate.push(
b`${fn}(${this.var}, ${data});`
);
if (this.node.is_dynamic_element) {
// call attribute bindings for custom element if tag is custom element
const tag = this.node.tag_expr.manipulate(block);
const attr_update = b`
if (/-/.test(${tag})) {
@set_custom_element_data_map(${this.var}, ${data});
} else {
${fn}(${this.var}, ${data});
}`;
block.chunks.hydrate.push(attr_update);
block.chunks.update.push(b`
${data} = @get_spread_update(${levels}, [${updates}]);
${attr_update}`
);
} else {
block.chunks.hydrate.push(
b`${fn}(${this.var}, ${data});`
);
block.chunks.update.push(b`
${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [
${updates}
]));
`);
block.chunks.update.push(b`
${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [
${updates}
]));
`);
}
// handle edge cases for elements
if (this.node.name === 'select') {

@ -316,6 +316,12 @@ export function set_svg_attributes(node: Element & ElementCSSInlineStyle, attrib
}
}
export function set_custom_element_data_map(node, data_map: Record<string, unknown>) {
Object.keys(data_map).forEach((key) => {
set_custom_element_data(node, key, data_map[key]);
});
}
export function set_custom_element_data(node, prop, value) {
if (prop in node) {
node[prop] = typeof node[prop] === 'boolean' && value === '' ? true : value;

@ -0,0 +1,47 @@
export default {
skip_if_ssr: true,
props: {
tag: 'my-custom-element',
name: null
},
html: `
<my-custom-element id="a">Hello null!</my-custom-element>
<my-custom-element id="b">Hello null!</my-custom-element>
`,
test({ assert, component, target }) {
component.name = undefined;
assert.htmlEqual(
target.innerHTML,
`<my-custom-element id="a">Hello undefined!</my-custom-element>
<my-custom-element id="b">Hello undefined!</my-custom-element>`
);
component.name = 'foo';
assert.htmlEqual(
target.innerHTML,
`<my-custom-element id="a">Hello foo!</my-custom-element>
<my-custom-element id="b">Hello foo!</my-custom-element>`
);
component.tag = null;
assert.htmlEqual(
target.innerHTML,
'<my-custom-element id="b">Hello foo!</my-custom-element>'
);
component.tag = 'div';
assert.htmlEqual(
target.innerHTML,
`<div name="foo" id="a"></div>
<my-custom-element id="b">Hello foo!</my-custom-element>`
);
component.tag = 'my-custom-element';
assert.htmlEqual(
target.innerHTML,
`<my-custom-element id="a">Hello foo!</my-custom-element>
<my-custom-element id="b">Hello foo!</my-custom-element>`
);
}
};

@ -0,0 +1,32 @@
<script>
class MyCustomElement extends HTMLElement {
constructor() {
super();
this._name = null;
}
/**
* @param {string} name
*/
set name(name) {
this._name = name;
this.render();
}
connectedCallback() {
this.render();
}
render() {
this.innerHTML = "Hello " + this._name + "!";
}
}
window.customElements.define("my-custom-element", MyCustomElement);
export let tag;
export let name;
</script>
<svelte:element this="{tag}" {name} id="a" />
<my-custom-element {name} id="b" />
Loading…
Cancel
Save