Adds class directive shortcut

When no expression is used in a class directive the class name will be used to evaluate whether the class should be added/removed.

E.g. the following will add the class "active" when you call `component.set({ active });`.

```html
<div class:active></div>
```
pull/1695/head
Jacob Wright 6 years ago
parent 0f171a5f3e
commit 4ec85bb8cc

@ -855,8 +855,8 @@ export default class Element extends Node {
const { expression } = action; const { expression } = action;
let snippet, dependencies; let snippet, dependencies;
if (expression) { if (expression) {
snippet = action.expression.snippet; snippet = expression.snippet;
dependencies = action.expression.dependencies; dependencies = expression.dependencies;
} }
const name = block.getUniqueName( const name = block.getUniqueName(
@ -889,7 +889,16 @@ export default class Element extends Node {
addClasses(block: Block) { addClasses(block: Block) {
this.classes.forEach(classDir => { this.classes.forEach(classDir => {
const { expression: { snippet, dependencies}, name } = classDir; const { expression, name } = classDir;
let snippet, dependencies;
if (expression) {
snippet = expression.snippet;
dependencies = expression.dependencies;
} else {
const varName = camelCase(name);
snippet = `ctx.${varName}`;
dependencies = [varName];
}
const updater = `@toggleClass(${this.var}, "${name}", ${snippet});`; const updater = `@toggleClass(${this.var}, "${name}", ${snippet});`;
block.builders.hydrate.addLine(updater); block.builders.hydrate.addLine(updater);
@ -978,7 +987,8 @@ export default class Element extends Node {
} }
const classExpr = this.classes.map((classDir: Class) => { const classExpr = this.classes.map((classDir: Class) => {
const { expression: { snippet }, name } = classDir; const { expression, name } = classDir;
const snippet = expression ? expression.snippet : `ctx.${camelCase(name)}`;
return `${snippet} ? "${name}" : ""`; return `${snippet} ? "${name}" : ""`;
}).join(', '); }).join(', ');
@ -1026,7 +1036,7 @@ export default class Element extends Node {
openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }'; openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }';
} else if (attribute.name === 'class' && classExpr) { } else if (attribute.name === 'class' && classExpr) {
addClassAttribute = false; addClassAttribute = false;
openingTag += ` class="\${ [\`${attribute.stringifyForSsr()}\`, ${classExpr} ].join(' ') }"`; openingTag += ` class="\${ [\`${attribute.stringifyForSsr()}\`, ${classExpr} ].join(' ').trim() }"`;
} else { } else {
openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`; openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`;
} }
@ -1034,7 +1044,7 @@ export default class Element extends Node {
} }
if (addClassAttribute) { if (addClassAttribute) {
openingTag += ` class="\${ [${classExpr}].join(' ') }"`; openingTag += ` class="\${ [${classExpr}].join(' ').trim() }"`;
} }
openingTag += '>'; openingTag += '>';
@ -1159,3 +1169,9 @@ const events = [
name === 'volume' name === 'volume'
} }
]; ];
function camelCase(str) {
return str.replace(/(-\w)/g, function (m) {
return m[1].toUpperCase();
});
}

@ -0,0 +1,16 @@
export default {
data: {
isActive: true,
isSelected: true,
myClass: 'one two'
},
html: `<div class="one two is-active isSelected"></div>`,
test ( assert, component, target, window ) {
component.set({ isActive: false });
assert.htmlEqual( target.innerHTML, `
<div class="one two isSelected"></div>
` );
}
};

@ -0,0 +1 @@
<div class="{ myClass }" class:is-active class:isSelected class:not-used></div>
Loading…
Cancel
Save