Skip to content

Commit

Permalink
feat: Add scope id to keyframes name (#43)
Browse files Browse the repository at this point in the history
* refactor: do not include `data-v-` prefix in id

* chore: bump eslint config

* feat: should add scope id to keyframes name
  • Loading branch information
ktsn committed Jan 13, 2018
1 parent 4626b76 commit 63080b1
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 14 deletions.
2 changes: 0 additions & 2 deletions .eslintrc.yml
@@ -1,6 +1,4 @@
---
extends: eslint-config-ktsn
parserOptions:
ecmaVersion: 6
rules:
no-console: 0
38 changes: 35 additions & 3 deletions lib/modules/add-scoped-id.js
Expand Up @@ -46,7 +46,7 @@ const addScopedIdPlugin = postcss.plugin('add-scoped-id', options => {

if (target) {
selector.insertAfter(target, selectorParser.attribute({
attribute: options.id
attribute: 'data-v-' + options.id
}))
}

Expand All @@ -55,8 +55,40 @@ const addScopedIdPlugin = postcss.plugin('add-scoped-id', options => {
})

return root => {
root.walkRules(rule => {
rule.selector = selectorTransformer.process(rule.selector).result
const keyframes = new Map()

root.each(function transformNode (node) {
if (node.type === 'atrule') {
if (/-?keyframes$/.test(node.name)) {
const before = node.params
const after = node.params + '-' + options.id
node.params = after
keyframes.set(before, after)
} else {
node.each(transformNode)
}
} else {
node.selector = selectorTransformer.process(node.selector).result
}
})

keyframes.forEach((after, before) => {
root.walkDecls(decl => {
if (/-?animation-name$/.test(decl.prop)) {
decl.value = decl.value.split(',')
.map(v => v.trim() === before ? after : v)
.join(',')
} else if (/-?animation$/.test(decl.prop)) {
decl.value = decl.value.split(',')
.map(v => {
const [first, ...tail] = v.trim().split(/\s+/)
return first === before
? [after, ...tail].join(' ')
: v
})
.join(',')
}
})
})
}
})
Expand Down
4 changes: 2 additions & 2 deletions lib/template-loader.js
Expand Up @@ -12,7 +12,7 @@ const Builder = require('./builder/builder')
module.exports = function (content) {
this.cacheable()
const isServer = this.options.target === 'node'
const id = `data-v-${genId(this.resourcePath, process.cwd())}`
const id = genId(this.resourcePath, process.cwd())

// Acquire the query of target file
const { style: stylePath } = loaderUtils.parseQuery('?' + this.request.split('?').pop())
Expand Down Expand Up @@ -70,7 +70,7 @@ module.exports = function (content) {
// Set _scopeId if scoped CSS is enabled
if (options.scoped) {
builder.addLine(`
options._scopeId = '${id}'
options._scopeId = 'data-v-${id}'
`)
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -44,7 +44,7 @@
"babel-register": "^6.24.0",
"css-loader": "^0.28.0",
"eslint": "^3.19.0",
"eslint-config-ktsn": "^1.0.0",
"eslint-config-ktsn": "^1.0.3",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1",
"html-webpack-plugin": "^2.28.0",
Expand Down
41 changes: 35 additions & 6 deletions test/modules/add-scoped-id.spec.js
Expand Up @@ -6,31 +6,31 @@ const addScopedId = require('../../lib/modules/add-scoped-id')
describe('add scoped id module', () => {
it('should add scoped id into the last node for each selector', done => {
test(
'data-v-1',
'1',
'h1, h2 .foo {} h3 {}',
'h1[data-v-1], h2 .foo[data-v-1] {} h3[data-v-1] {}'
).then(done)
})

it('should not add scoped id into pseudo element/class', done => {
test(
'data-v-1',
'1',
'p::before {} .test:first-child {}',
'p[data-v-1]::before {} .test[data-v-1]:first-child {}'
).then(done)
})

it('should add scoped id into the selectors in at-rules', done => {
test(
'data-v-1',
'1',
'@media screen { p {} }',
'@media screen { p[data-v-1] {} }'
).then(done)
})

it('should generate source map', done => {
test(
'data-v-1',
'1',
'div p {}',
'div p[data-v-1] {}',
true
Expand Down Expand Up @@ -72,7 +72,7 @@ describe('add scoped id module', () => {
const map = JSON.parse(Base64.decode(m[2]))

test(
'data-v-1',
'1',
css,
[
'div p[data-v-1] {',
Expand All @@ -94,11 +94,40 @@ describe('add scoped id module', () => {

it('should add scope attribute the selector before >>> combinator', done => {
test(
'data-v-1',
'1',
'.foo .bar >>> .baz {}',
'.foo .bar[data-v-1] .baz {}'
).then(done)
})

it('should add scope id to keyframes', done => {
const id = 'abc'
const input = [
'.foo { animation: test 1s; }',
'.bar { animation-name: test; animation-duration: 1s; }',
'@keyframes test {',
' 0% { opacity: 0; }',
' 100% { opacity: 1; }',
'}',
'@-webkit-keyframes test {',
' from { opacity: 0; }',
' to { opacity: 1; }',
'}'
].join('\n')
const expected = [
`.foo[data-v-${id}] { animation: test-${id} 1s; }`,
`.bar[data-v-${id}] { animation-name: test-${id}; animation-duration: 1s; }`,
`@keyframes test-${id} {`,
' 0% { opacity: 0; }',
' 100% { opacity: 1; }',
'}',
`@-webkit-keyframes test-${id} {`,
' from { opacity: 0; }',
' to { opacity: 1; }',
'}'
].join('\n')
test(id, input, expected).then(done)
})
})

function test (id, input, expected, map) {
Expand Down

0 comments on commit 63080b1

Please sign in to comment.