Skip to content

Commit

Permalink
support ref:foo as a CSS selector (#693)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Jul 30, 2017
1 parent a7876c7 commit 82559c3
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 14 deletions.
24 changes: 22 additions & 2 deletions src/css/Selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default class Selector {
});
}

transform(code: MagicString, attr: string) {
transform(code: MagicString, attr: string, id: string) {
function encapsulateBlock(block: Block) {
let i = block.selectors.length;
while (i--) {
Expand All @@ -64,7 +64,19 @@ export default class Selector {
code.appendLeft(selector.end, attr);
}

return;
break;
}

i = block.selectors.length;
while (i--) {
const selector = block.selectors[i];

if (selector.type === 'RefSelector') {
code.overwrite(selector.start, selector.end, `[svelte-ref-${selector.name}]`, {
contentOnly: true,
storeName: false
});
}
}
}

Expand Down Expand Up @@ -154,6 +166,14 @@ function selectorAppliesTo(blocks: Block[], node: Node, stack: Node[]): boolean
if (node.name !== selector.name && selector.name !== '*') return false;
}

else if (selector.type === 'RefSelector') {
if (node.attributes.some((attr: Node) => attr.type === 'Ref' && attr.name === selector.name)) {
node._cssRefAttribute = selector.name;
return true;
}
return;
}

else {
// bail. TODO figure out what these could be
return true;
Expand Down
6 changes: 6 additions & 0 deletions src/generators/dom/visitors/Element/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ export default function visitElement(
block.builders.hydrate.addLine(
`@encapsulateStyles( ${name} );`
);

if (node._cssRefAttribute) {
block.builders.hydrate.addLine(
`@setAttribute( ${name}, 'svelte-ref-${node._cssRefAttribute}', '' );`
)
}
}

function visitAttributesAndAddProps() {
Expand Down
4 changes: 4 additions & 0 deletions src/generators/server-side-rendering/visitors/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export default function visitElement(

if (node._needsCssAttribute) {
openingTag += ` ${generator.stylesheet.id}`;

if (node._cssRefAttribute) {
openingTag += ` svelte-ref-${node._cssRefAttribute}`;
}
}

openingTag += '>';
Expand Down
45 changes: 38 additions & 7 deletions src/parse/read/style.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import parse from 'css-tree/lib/parser/index.js';
import walk from 'css-tree/lib/utils/walk.js';
import { walk } from 'estree-walker';
import { Parser } from '../index';
import { Node } from '../../interfaces';

Expand All @@ -23,12 +23,33 @@ export default function readStyle(parser: Parser, start: number, attributes: Nod
}
}

ast = JSON.parse(JSON.stringify(ast));

// tidy up AST
walk.all(ast, (node: Node) => {
if (node.loc) {
node.start = node.loc.start.offset;
node.end = node.loc.end.offset;
delete node.loc;
walk(ast, {
enter: (node: Node) => {
// replace `ref:a` nodes
if (node.type === 'Selector') {
for (let i = 0; i < node.children.length; i += 1) {
const a = node.children[i];
const b = node.children[i + 1];

if (isRefSelector(a, b)) {
node.children.splice(i, 2, {
type: 'RefSelector',
start: a.loc.start.offset,
end: b.loc.end.offset,
name: b.name
});
}
}
}

if (node.loc) {
node.start = node.loc.start.offset;
node.end = node.loc.end.offset;
delete node.loc;
}
}
});

Expand All @@ -39,11 +60,21 @@ export default function readStyle(parser: Parser, start: number, attributes: Nod
start,
end,
attributes,
children: JSON.parse(JSON.stringify(ast.children)),
children: ast.children,
content: {
start: contentStart,
end: contentEnd,
styles,
},
};
}

function isRefSelector(a: Node, b: Node) {
if (!b) return false;

return (
a.type === 'TypeSelector' &&
a.name === 'ref' &&
b.type === 'PseudoClassSelector'
);
}
4 changes: 2 additions & 2 deletions test/css/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ describe("css", () => {

// dom
assert.equal(
normalizeHtml(window, html).replace(/svelte-\d+/g, 'svelte-xyz'),
normalizeHtml(window, html.replace(/svelte-\d+/g, 'svelte-xyz')),
normalizeHtml(window, expected.html)
);

// ssr
const component = eval(`(function () { ${ssr.code}; return SvelteComponent; }())`);

assert.equal(
normalizeHtml(window, component.render(config.data)).replace(/svelte-\d+/g, 'svelte-xyz'),
normalizeHtml(window, component.render(config.data).replace(/svelte-\d+/g, 'svelte-xyz')),
normalizeHtml(window, expected.html)
);
});
Expand Down
23 changes: 23 additions & 0 deletions test/css/samples/refs-qualified/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export default {
cascade: false,

data: {
active: true
},

warnings: [{
message: 'Unused CSS selector',
loc: {
column: 1,
line: 12
},
pos: 174,
frame: `
10: }
11:
12: ref:button.inactive {
^
13: color: green;
14: }`
}]
};
1 change: 1 addition & 0 deletions test/css/samples/refs-qualified/expected.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[svelte-ref-button].active[svelte-xyz]{color:red}
1 change: 1 addition & 0 deletions test/css/samples/refs-qualified/expected.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="active" svelte-ref-button="" svelte-xyz="">deactivate</button>
15 changes: 15 additions & 0 deletions test/css/samples/refs-qualified/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{#if active}}
<button ref:button class='active'>deactivate</button>
{{else}}
<button ref:button>activate</button>
{{/if}}

<style>
ref:button.active {
color: red;
}

ref:button.inactive {
color: green;
}
</style>
19 changes: 19 additions & 0 deletions test/css/samples/refs/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default {
cascade: false,

warnings: [{
message: 'Unused CSS selector',
loc: {
column: 1,
line: 14
},
pos: 120,
frame: `
12: }
13:
14: ref:d {
^
15: color: blue;
16: }`
}]
};
1 change: 1 addition & 0 deletions test/css/samples/refs/expected.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[svelte-ref-a][svelte-xyz]{color:red}[svelte-ref-b][svelte-xyz]{color:green}
3 changes: 3 additions & 0 deletions test/css/samples/refs/expected.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div svelte-xyz='' svelte-ref-a=''></div>
<div svelte-xyz='' svelte-ref-b=''></div>
<div></div>
17 changes: 17 additions & 0 deletions test/css/samples/refs/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div ref:a></div>
<div ref:b></div>
<div ref:c></div>

<style>
ref:a {
color: red;
}

ref:b {
color: green;
}

ref:d {
color: blue;
}
</style>
7 changes: 7 additions & 0 deletions test/parser/samples/css-ref-selector/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div ref:foo/>

<style>
ref:foo {
color: red;
}
</style>
96 changes: 96 additions & 0 deletions test/parser/samples/css-ref-selector/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"hash": 1104014177,
"html": {
"start": 0,
"end": 14,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 14,
"type": "Element",
"name": "div",
"attributes": [
{
"start": 5,
"end": 12,
"type": "Ref",
"name": "foo"
}
],
"children": []
},
{
"start": 14,
"end": 16,
"type": "Text",
"data": "\n\n"
}
]
},
"css": {
"start": 16,
"end": 60,
"attributes": [],
"children": [
{
"type": "Rule",
"selector": {
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "RefSelector",
"start": 25,
"end": 32,
"name": "foo"
}
],
"start": 25,
"end": 32
}
],
"start": 25,
"end": 32
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "red",
"start": 44,
"end": 47
}
],
"start": 43,
"end": 47
},
"start": 37,
"end": 47
}
],
"start": 33,
"end": 51
},
"start": 25,
"end": 51
}
],
"content": {
"start": 23,
"end": 52,
"styles": "\n\tref:foo {\n\t\tcolor: red;\n\t}\n"
}
},
"js": null
}
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1976,9 +1976,9 @@ magic-string@^0.19.0, magic-string@~0.19.0:
dependencies:
vlq "^0.2.1"

magic-string@^0.22.1:
version "0.22.1"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.1.tgz#a1bda64dfd4ae6c63797a45a67ee473b1f8d0e0f"
magic-string@^0.22.3:
version "0.22.3"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.3.tgz#047989d99bfc7cbdefba1604adc8912551cd7ef1"
dependencies:
vlq "^0.2.1"

Expand Down

0 comments on commit 82559c3

Please sign in to comment.