postcss-rem-to-rem-multiplier
Version:
multiply the rem (root em) units with a multiplier using PostCSS. Based on postcss-rem-to-pixel.
126 lines (107 loc) • 4.21 kB
JavaScript
;
var postcss = require('postcss');
var objectAssign = require('object-assign');
var remRegex = require('./lib/rem-unit-regex');
var filterPropList = require('./lib/filter-prop-list');
var defaults = {
multiplier: 0.625,
unitPrecision: 5,
selectorBlackList: [],
propList: ['font', 'font-size', 'line-height', 'letter-spacing'],
mediaQuery: false,
multiplierCssVarName: null
};
module.exports = postcss.plugin('postcss-rem-to-rem-multiplier', function (options) {
var opts = objectAssign({}, defaults, options);
var remReplace = createRemReplace(opts.multiplier, opts.unitPrecision, opts.multiplierCssVarName);
var satisfyPropList = createPropListMatcher(opts.propList);
return function (css) {
css.walkDecls(function (decl, i) {
// This should be the fastest test and will remove most declarations
if (decl.value.indexOf('rem') === -1) return;
if (!satisfyPropList(decl.prop)) return;
if (blacklistedSelector(opts.selectorBlackList, decl.parent.selector)) return;
var value = decl.value.replace(remRegex, remReplace);
decl.value = value;
});
if (opts.mediaQuery) {
css.walkAtRules('media', function (rule) {
if (rule.params.indexOf('rem') === -1) return;
rule.params = rule.params.replace(remRegex, remReplace);
});
}
};
});
function createRemReplace(multiplier, unitPrecision, multiplierCssVarName) {
return function (m, $1) {
if (!$1) return m;
var rems = parseFloat($1);
if (multiplierCssVarName) {
return 'calc('+rems+'rem * var('+ multiplierCssVarName +'))'
} else {
var fixedVal = toFixed((rems * multiplier), unitPrecision);
return (fixedVal === 0) ? '0' : fixedVal + 'rem';
}
};
}
function toFixed(number, precision) {
var multiplier = Math.pow(10, precision + 1),
wholeNumber = Math.floor(number * multiplier);
return Math.round(wholeNumber / 10) * 10 / multiplier;
}
function declarationExists(decls, prop, value) {
return decls.some(function (decl) {
return (decl.prop === prop && decl.value === value);
});
}
function blacklistedSelector(blacklist, selector) {
if (typeof selector !== 'string') return;
return blacklist.some(function (regex) {
if (typeof regex === 'string') return selector.indexOf(regex) !== -1;
return selector.match(regex);
});
}
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;
})
)
);
};
}