forked from evrone/postcss-px-to-viewport
-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
executable file
·81 lines (63 loc) · 2.66 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
'use strict';
var postcss = require('postcss');
var objectAssign = require('object-assign');
var defaults = {
unitToConvert: 'px',
viewportWidth: 320,
viewportHeight: 568, // not now used; TODO: need for different units and math for different properties
unitPrecision: 5,
viewportUnit: 'vw',
fontViewportUnit: 'vw', // vmin is more suitable.
filePathBlackList: [],
minPixelValue: 1,
mediaQuery: false
};
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);
// excluding regex trick: http://www.rexegg.com/regex-best-trick.html
// Not anything inside double quotes
// Not anything inside single quotes
// Not anything inside url()
// Any digit followed by px
// !singlequotes|!doublequotes|!url()|pixelunit
var pxRegex = new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + opts.unitToConvert, 'ig')
return function (css) {
css.walkDecls(function (decl, i) {
// This should be the fastest test and will remove most declarations
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
if (blacklistedFilePathSelector(opts.filePathBlackList, decl.parent.source.input.file)) {
return;
}
var unit = getUnit(decl.prop, opts)
decl.value = decl.value.replace(pxRegex, createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, unit));
});
if (opts.mediaQuery) {
css.walkAtRules('media', function (rule) {
if (rule.params.indexOf(opts.unitToConvert) === -1) return;
rule.params = rule.params.replace(pxRegex, pxReplace);
});
}
};
});
function getUnit(prop, opts) {
return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit;
}
function createPxReplace(viewportSize, minPixelValue, unitPrecision, viewportUnit) {
return function (m, $1) {
if (!$1) return m;
var pixels = parseFloat($1);
if (pixels <= minPixelValue) return m;
return toFixed((pixels / viewportSize * 100), unitPrecision) + viewportUnit;
};
}
function toFixed(number, precision) {
var multiplier = Math.pow(10, precision + 1),
wholeNumber = Math.floor(number * multiplier);
return Math.round(wholeNumber / 10) * 10 / multiplier;
}
function blacklistedFilePathSelector(blacklist, fileName) {
return blacklist.some(function (regex) {
return fileName.indexOf(regex) > 0;
});
}