Browse Source

Merge pull request #20 from evrone/add-prop-list

add prop list
pull/23/head
Ivan 7 years ago
committed by GitHub
parent
commit
6f44bd0948
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      README.md
  2. 16
      index.js
  3. 84
      spec/px-to-viewport.spec.js
  4. 106
      src/prop-list-matcher.js

9
README.md

@ -96,6 +96,7 @@ Default:
viewportWidth: 320,
viewportHeight: 568, // not now used; TODO: need for different units and math for different properties
unitPrecision: 5,
propList: ['*'],
viewportUnit: 'vw',
fontViewportUnit: 'vw', // vmin is more suitable.
selectorBlackList: [],
@ -108,7 +109,13 @@ Default:
- `unitToConvert` (String) unit to convert, by default, it is px.
- `viewportWidth` (Number) The width of the viewport.
- `viewportHeight` (Number) The height of the viewport.
- `unitPrecision` (Number) The decimal numbers to allow the REM units to grow to.
- `unitPrecision` (Number) The decimal numbers to allow the vw units to grow to.
- `propList` (Array) The properties that can change from px to vw.
- Values need to be exact matches.
- Use wildcard * to enable all properties. Example: ['*']
- Use * at the start or end of a word. (['*position*'] will match background-position-y)
- Use ! to not match a property. Example: ['*', '!letter-spacing']
- Combine the "not" prefix with the other prefixes. Example: ['*', '!font*']
- `viewportUnit` (String) Expected units.
- `fontViewportUnit` (String) Expected units for font.
- `selectorBlackList` (Array) The selectors to ignore and leave as px.

16
index.js

@ -2,6 +2,7 @@
var postcss = require('postcss');
var objectAssign = require('object-assign');
var { createPropListMatcher } = require('./src/prop-list-matcher');
var defaults = {
unitToConvert: 'px',
@ -11,13 +12,14 @@ var defaults = {
viewportUnit: 'vw',
fontViewportUnit: 'vw', // vmin is more suitable.
selectorBlackList: [],
propList: ['*'],
minPixelValue: 1,
mediaQuery: false,
replace: true
};
module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
var opts = objectAssign({}, defaults, options);
var pxReplace = createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, opts.viewportUnit);
@ -27,7 +29,8 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
// Not anything inside url()
// Any digit followed by px
// !singlequotes|!doublequotes|!url()|pixelunit
var pxRegex = new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + opts.unitToConvert, 'g')
var pxRegex = new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + opts.unitToConvert, 'g');
var satisfyPropList = createPropListMatcher(opts.propList);
return function (css) {
@ -45,11 +48,12 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
throw new Error('options.exclude should be RegExp or Array!');
}
}
// This should be the fastest test and will remove most declarations
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
if (blacklistedSelector(opts.selectorBlackList, decl.parent.selector)) return;
if (
decl.value.indexOf(opts.unitToConvert) === -1 ||
!satisfyPropList(decl.prop) ||
blacklistedSelector(opts.selectorBlackList, decl.parent.selector)
) return;
var unit = getUnit(decl.prop, opts);
var value = decl.value.replace(pxRegex, createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, unit));

84
spec/px-to-viewport.spec.js

@ -9,6 +9,7 @@
var postcss = require('postcss');
var pxToViewport = require('..');
var basicCSS = '.rule { font-size: 15px }';
var { filterPropList } = require('../src/prop-list-matcher');
describe('px-to-viewport', function() {
it('should work on the readme example', function () {
@ -205,6 +206,38 @@ describe('mediaQuery', function () {
});
});
describe('propList', function () {
it('should only replace properties in the prop list', function () {
var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }';
var expected = '.rule { font-size: 5vw; margin: 5vw; margin-left: 5px; padding: 5px; padding-right: 5vw }';
var options = {
propList: ['*font*', 'margin*', '!margin-left', '*-right', 'pad']
};
var processed = postcss(pxToViewport(options)).process(css).css;
expect(processed).toBe(expected);
});
it('should only replace properties in the prop list with wildcard', function () {
var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }';
var expected = '.rule { font-size: 16px; margin: 5vw; margin-left: 5px; padding: 5px; padding-right: 16px }';
var options = {
propList: ['*', '!margin-left', '!*padding*', '!font*']
};
var processed = postcss(pxToViewport(options)).process(css).css;
expect(processed).toBe(expected);
});
it('should replace all properties when prop list is not given', function () {
var rules = '.rule { margin: 16px; font-size: 15px }';
var expected = '.rule { margin: 5vw; font-size: 4.6875vw }';
var processed = postcss(pxToViewport()).process(rules).css;
expect(processed).toBe(expected);
});
});
describe('minPixelValue', function () {
it('should not replace values below minPixelValue', function () {
var options = {
@ -278,3 +311,54 @@ describe('replace', function () {
expect(processed).toBe(expected);
});
});
describe('filter-prop-list', function () {
it('should find "exact" matches from propList', function () {
var propList = ['font-size', 'margin', '!padding', '*border*', '*', '*y', '!*font*'];
var expected = 'font-size,margin';
expect(filterPropList.exact(propList).join()).toBe(expected);
});
it('should find "contain" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', '*border*', '*', '*y', '!*font*'];
var expected = 'margin,border';
expect(filterPropList.contain(propList).join()).toBe(expected);
});
it('should find "start" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', 'border*', '*', '*y', '!*font*'];
var expected = 'border';
expect(filterPropList.startWith(propList).join()).toBe(expected);
});
it('should find "end" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', 'border*', '*', '*y', '!*font*'];
var expected = 'y';
expect(filterPropList.endWith(propList).join()).toBe(expected);
});
it('should find "not" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', 'border*', '*', '*y', '!*font*'];
var expected = 'padding';
expect(filterPropList.notExact(propList).join()).toBe(expected);
});
it('should find "not contain" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', '!border*', '*', '*y', '!*font*'];
var expected = 'font';
expect(filterPropList.notContain(propList).join()).toBe(expected);
});
it('should find "not start" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', '!border*', '*', '*y', '!*font*'];
var expected = 'border';
expect(filterPropList.notStartWith(propList).join()).toBe(expected);
});
it('should find "not end" matches from propList and reduce to string', function () {
var propList = ['font-size', '*margin*', '!padding', '!border*', '*', '!*y', '!*font*'];
var expected = 'y';
expect(filterPropList.notEndWith(propList).join()).toBe(expected);
});
});

106
src/prop-list-matcher.js

@ -0,0 +1,106 @@
var filterPropList = {
exact: function (list) {
return list.filter(function (m) {
return m.match(/^[^\*\!]+$/);
});
},
contain: function (list) {
return list.filter(function (m) {
return m.match(/^\*.+\*$/);
}).map(function (m) {
return m.substr(1, m.length - 2);
});
},
endWith: function (list) {
return list.filter(function (m) {
return m.match(/^\*[^\*]+$/);
}).map(function (m) {
return m.substr(1);
});
},
startWith: function (list) {
return list.filter(function (m) {
return m.match(/^[^\*\!]+\*$/);
}).map(function (m) {
return m.substr(0, m.length - 1);
});
},
notExact: function (list) {
return list.filter(function (m) {
return m.match(/^\![^\*].*$/);
}).map(function (m) {
return m.substr(1);
});
},
notContain: function (list) {
return list.filter(function (m) {
return m.match(/^\!\*.+\*$/);
}).map(function (m) {
return m.substr(2, m.length - 3);
});
},
notEndWith: function (list) {
return list.filter(function (m) {
return m.match(/^\!\*[^\*]+$/);
}).map(function (m) {
return m.substr(2);
});
},
notStartWith: function (list) {
return list.filter(function (m) {
return m.match(/^\![^\*]+\*$/);
}).map(function (m) {
return m.substr(1, m.length - 2);
});
}
};
function createPropListMatcher(propList) {
var hasWild = propList.indexOf('*') > -1;
var matchAll = (hasWild && propList.length === 1);
var lists = {
exact: filterPropList.exact(propList),
contain: filterPropList.contain(propList),
startWith: filterPropList.startWith(propList),
endWith: filterPropList.endWith(propList),
notExact: filterPropList.notExact(propList),
notContain: filterPropList.notContain(propList),
notStartWith: filterPropList.notStartWith(propList),
notEndWith: filterPropList.notEndWith(propList)
};
return function (prop) {
if (matchAll) return true;
return (
(
hasWild ||
lists.exact.indexOf(prop) > -1 ||
lists.contain.some(function (m) {
return prop.indexOf(m) > -1;
}) ||
lists.startWith.some(function (m) {
return prop.indexOf(m) === 0;
}) ||
lists.endWith.some(function (m) {
return prop.indexOf(m) === prop.length - m.length;
})
) &&
!(
lists.notExact.indexOf(prop) > -1 ||
lists.notContain.some(function (m) {
return prop.indexOf(m) > -1;
}) ||
lists.notStartWith.some(function (m) {
return prop.indexOf(m) === 0;
}) ||
lists.notEndWith.some(function (m) {
return prop.indexOf(m) === prop.length - m.length;
})
)
);
};
}
module.exports = {
filterPropList,
createPropListMatcher
};
Loading…
Cancel
Save