[feat] Support hyphenated attributes in custom elements

pull/7638/head
Tobias Trumm 4 years ago
parent d7557e11a2
commit c5b94ddd3c

@ -558,7 +558,7 @@ export default function dom(
computed: false,
key: { type: 'Identifier', name: 'observedAttributes' },
value: x`function() {
return [${props.map(prop => x`"${prop.export_name}"`)}];
return [${props.map(prop => x`"${prop.export_name.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`)}"`)}];
}` as FunctionExpression
});
}

@ -198,7 +198,8 @@ if (typeof HTMLElement === 'function') {
}
attributeChangedCallback(attr, _oldValue, newValue) {
this[attr] = newValue;
const camelCase = attr.replace(/-./g, c => c[1].toUpperCase());
this[camelCase] = newValue;
}
disconnectedCallback() {

@ -315,9 +315,14 @@ export function set_svg_attributes(node: Element & ElementCSSInlineStyle, attrib
}
}
function kebab_case_to_camel_case(str: string): string {
return str.replace(/-./g, c => c[1].toUpperCase());
}
export function set_custom_element_data(node, prop, value) {
if (prop in node) {
node[prop] = typeof node[prop] === 'boolean' && value === '' ? true : value;
const camelCaseProp = kebab_case_to_camel_case(prop);
if (camelCaseProp in node) {
node[camelCaseProp] = typeof node[camelCaseProp] === 'boolean' && value === '' ? true : value;
} else {
attr(node, prop, value);
}
@ -728,7 +733,8 @@ export class HtmlTagHydration extends HtmlTag {
export function attribute_to_object(attributes: NamedNodeMap) {
const result = {};
for (const attribute of attributes) {
result[attribute.name] = attribute.value;
const name = kebab_case_to_camel_case(attribute.name);
result[name] = attribute.value;
}
return result;
}

@ -2,9 +2,11 @@
<script>
export let name;
export let hyphenatedAttr;
</script>
<p>name: {name}</p>
<p>hyphenated attribute: {hyphenatedAttr}</p>
<p>$$props: {JSON.stringify($$props)}</p>
<p>$$restProps: {JSON.stringify($$restProps)}</p>

@ -2,12 +2,13 @@ import * as assert from 'assert';
import './main.svelte';
export default function (target) {
target.innerHTML = '<custom-element name="world" answer="42" test="svelte"></custom-element>';
target.innerHTML = '<custom-element name="world" answer="42" test="svelte" hyphenated-attr="galaxy" rest-attr="universe"></custom-element>';
const el = target.querySelector('custom-element');
assert.htmlEqual(el.shadowRoot.innerHTML, `
<p>name: world</p>
<p>$$props: {"name":"world","answer":"42","test":"svelte"}</p>
<p>$$restProps: {"answer":"42","test":"svelte"}</p>
<p>hyphenated attribute: galaxy</p>
<p>$$props: {"name":"world","answer":"42","test":"svelte","hyphenatedAttr":"galaxy","restAttr":"universe"}</p>
<p>$$restProps: {"answer":"42","test":"svelte","restAttr":"universe"}</p>
`);
}

@ -5,6 +5,7 @@
export let items = ['a', 'b', 'c'];
export let flagged = false;
export let flaggedWithHyphen = false;
</script>
<my-widget class="foo" {items} flag1={flagged} flag2 />
<my-widget class="foo" {items} flag1={flagged} flag2 flag-with-hyphen1={flaggedWithHyphen} flag-with-hyphen2 />

@ -4,9 +4,13 @@
export let items = [];
export let flag1 = false;
export let flag2 = false;
export let flagWithHyphen1 = false;
export let flagWithHyphen2 = false;
</script>
<p>{items.length} items</p>
<p>{items.join(', ')}</p>
<p>{flag1 ? 'flagged (dynamic attribute)' : 'not flagged'}</p>
<p>{flag2 ? 'flagged (static attribute)' : 'not flagged'}</p>
<p>{flagWithHyphen1 ? 'flagged with hyphen (dynamic attribute)' : 'not flagged'}</p>
<p>{flagWithHyphen2 ? 'flagged with hyphen (static attribute)' : 'not flagged'}</p>

@ -11,17 +11,21 @@ export default function (target) {
const el = target.querySelector('custom-element');
const widget = el.shadowRoot.querySelector('my-widget');
const [p1, p2, p3, p4] = widget.shadowRoot.querySelectorAll('p');
const [p1, p2, p3, p4, p5, p6] = widget.shadowRoot.querySelectorAll('p');
assert.equal(p1.textContent, '3 items');
assert.equal(p2.textContent, 'a, b, c');
assert.equal(p3.textContent, 'not flagged');
assert.equal(p4.textContent, 'flagged (static attribute)');
assert.equal(p5.textContent, 'not flagged');
assert.equal(p6.textContent, 'flagged with hyphen (static attribute)');
el.items = ['d', 'e', 'f', 'g', 'h'];
el.flagged = true;
el.flaggedWithHyphen = true;
assert.equal(p1.textContent, '5 items');
assert.equal(p2.textContent, 'd, e, f, g, h');
assert.equal(p3.textContent, 'flagged (dynamic attribute)');
assert.equal(p5.textContent, 'flagged with hyphen (dynamic attribute)');
}

Loading…
Cancel
Save