Skip to content

Commit

Permalink
Merge pull request #2869 from ractivejs/gh-2854
Browse files Browse the repository at this point in the history
Better CSS at-rules handling (fixes #2854)
  • Loading branch information
MartinKolarik authored Feb 10, 2017
2 parents a692565 + 52192c5 commit b526d7c
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 25 deletions.
48 changes: 24 additions & 24 deletions src/Ractive/config/custom/css/transform.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import cleanCss from '../../../../utils/cleanCss';

const selectorsPattern = /(?:^|\})?\s*([^\{\}]+)\s*\{/g;
const commentsPattern = /\/\*[\s\S]*?\*\//g;
const selectorsPattern = /(?:^|\}|\{)\s*([^\{\}\0]+)\s*(?=\{)/g;
const keyframesDeclarationPattern = /@keyframes\s+[^\{\}]+\s*\{(?:[^{}]+|\{[^{}]+})*}/gi;
const selectorUnitPattern = /((?:(?:\[[^\]]+\])|(?:[^\s\+\>~:]))+)((?:::?[^\s\+\>\~\(:]+(?:\([^\)]+\))?)*\s*[\s\+\>\~]?)\s*/g;
const excludePattern = /^(?:@|\d+%)/;
const dataRvcGuidPattern = /\[data-ractive-css~="\{[a-z0-9-]+\}"]/g;
Expand All @@ -18,15 +18,13 @@ function transformSelector ( selector, parent ) {
const selectorUnits = [];
let match;

cleanCss( selector, ( selector, reconstruct ) => {
while ( match = selectorUnitPattern.exec( selector ) ) {
selectorUnits.push({
str: reconstruct( match[0] ),
base: reconstruct( match[1] ),
modifiers: reconstruct( match[2] )
});
}
});
while ( match = selectorUnitPattern.exec( selector ) ) {
selectorUnits.push({
str: match[0],
base: match[1],
modifiers: match[2]
});
}

// For each simple selector within the selector, we need to create a version
// that a) combines with the id, and b) is inside the id
Expand Down Expand Up @@ -59,19 +57,21 @@ export default function transformCss ( css, id ) {
if ( dataRvcGuidPattern.test( css ) ) {
transformed = css.replace( dataRvcGuidPattern, dataAttr );
} else {
transformed = css
.replace( commentsPattern, '' )
.replace( selectorsPattern, ( match, $1 ) => {
// don't transform at-rules and keyframe declarations
if ( excludePattern.test( $1 ) ) return match;

const selectors = $1.split( ',' ).map( trim );
const transformed = selectors
.map( selector => transformSelector( selector, dataAttr ) )
.join( ', ' ) + ' ';

return match.replace( $1, transformed );
});
transformed = cleanCss( css, ( css, reconstruct ) => {
css = css.replace( selectorsPattern, ( match, $1 ) => {
// don't transform at-rules and keyframe declarations
if ( excludePattern.test( $1 ) ) return match;

const selectors = $1.split( ',' ).map( trim );
const transformed = selectors
.map( selector => transformSelector( selector, dataAttr ) )
.join( ', ' ) + ' ';

return match.replace( $1, transformed );
});

return reconstruct( css );
}, [ keyframesDeclarationPattern ]);
}

return transformed;
Expand Down
6 changes: 5 additions & 1 deletion src/utils/cleanCss.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ const value = /\0(\d+)/g;
// Removes comments and strings from the given CSS to make it easier to parse.
// Callback receives the cleaned CSS and a function which can be used to put
// the removed strings back in place after parsing is done.
export default function ( css, callback ) {
export default function ( css, callback, additionalReplaceRules = [] ) {
const values = [];
const reconstruct = css => css.replace( value, ( match, n ) => values[ n ] );
css = css.replace( escape, match => `\0${values.push( match ) - 1}`).replace( remove, '' );

additionalReplaceRules.forEach( ( pattern ) => {
css = css.replace( pattern, match => `\0${values.push( match ) - 1}` );
});

return callback( css, reconstruct );
}
12 changes: 12 additions & 0 deletions test/browser-tests/render/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,16 @@ export default function() {
t.equal( cmp.toHTML(), '<div data-ractive-css="{my-nifty-cmp}"></div>' );
t.ok( ~cmp.toCSS().indexOf( 'my-nifty-cmp' ) );
});

test( `using 'from' and 'to' in keyframe declarations works (#2854)`, t => {
const cmp = new (Ractive.extend({
el: fixture,
template: '<p class="blue">foo</p><p class="red">bar</p>',
css: '.blue { color: blue } @keyframes someAnimation { from { transform: scale3d(1.5,1.5,1) rotate(0deg); } } .red { color: red }'
}));

t.equal( getHexColor( cmp.find( '.blue' ) ), hexCodes.blue );
t.equal( getHexColor( cmp.find( '.red' ) ), hexCodes.red );
t.ok( ~cmp.toCSS().indexOf( 'someAnimation { from { transform: scale3d(1.5,1.5,1) rotate(0deg); } }' ) );
});
}

0 comments on commit b526d7c

Please sign in to comment.