Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support array format for unitToConvert option #122

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Default Options:
landscapeWidth: 568
}
```
- `unitToConvert` (String) unit to convert, by default, it is px.
- `unitToConvert` (String) unit to convert, by default, it is px.Support Array, e.g: ["px","PX"]
- `viewportWidth` (Number) The width of the viewport.
- `unitPrecision` (Number) The decimal numbers to allow the vw units to grow to.
- `propList` (Array) The properties that can change from px to vw.
Expand Down
2 changes: 1 addition & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ $ yarn add -D postcss-px-to-viewport
landscapeWidth: 568
}
```
- `unitToConvert` (String) 需要转换的单位,默认为"px"
- `unitToConvert` (String) 需要转换的单位,默认为"px",支持Array, e.g: ["px","PX"]
- `viewportWidth` (Number) 设计稿的视口宽度
- `unitPrecision` (Number) 单位转换后保留的精度
- `propList` (Array) 能转化为vw的属性列表
Expand Down
143 changes: 97 additions & 46 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,48 @@
'use strict';
"use strict";

var postcss = require('postcss');
var objectAssign = require('object-assign');
var { createPropListMatcher } = require('./src/prop-list-matcher');
var { getUnitRegexp } = require('./src/pixel-unit-regexp');
var postcss = require("postcss");
var objectAssign = require("object-assign");
var { createPropListMatcher } = require("./src/prop-list-matcher");
var { getUnitRegexp } = require("./src/pixel-unit-regexp");

var defaults = {
unitToConvert: 'px',
unitToConvert: "px", // support array and string
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.
viewportUnit: "vw",
fontViewportUnit: "vw", // vmin is more suitable.
selectorBlackList: [],
propList: ['*'],
propList: ["*"],
minPixelValue: 1,
mediaQuery: false,
replace: true,
landscape: false,
landscapeUnit: 'vw',
landscapeWidth: 568
landscapeUnit: "vw",
landscapeWidth: 568,
};

var ignoreNextComment = 'px-to-viewport-ignore-next';
var ignorePrevComment = 'px-to-viewport-ignore';
var ignoreNextComment = "px-to-viewport-ignore-next";
var ignorePrevComment = "px-to-viewport-ignore";

function isValueIncludeUnitToConvert(strValue, unitToConvert) {
var unitList =
typeof unitToConvert === "string" ? [unitToConvert] : unitToConvert;
var i = 0,
len = unitList.length;
for (; i < len; i++) {
if (strValue.indexOf(unitList[i]) !== -1) {
return true;
}
}
return false;
}

module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
module.exports = postcss.plugin("postcss-px-to-viewport", function (options) {
var opts = objectAssign({}, defaults, options);

checkRegExpOrArray(opts, 'exclude');
checkRegExpOrArray(opts, 'include');
checkRegExpOrArray(opts, "exclude");
checkRegExpOrArray(opts, "include");

var pxRegex = getUnitRegexp(opts.unitToConvert);
var satisfyPropList = createPropListMatcher(opts.propList);
Expand All @@ -41,9 +54,13 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
var file = rule.source && rule.source.input.file;

if (opts.include && file) {
if (Object.prototype.toString.call(opts.include) === '[object RegExp]') {
if (
Object.prototype.toString.call(opts.include) === "[object RegExp]"
) {
if (!opts.include.test(file)) return;
} else if (Object.prototype.toString.call(opts.include) === '[object Array]') {
} else if (
Object.prototype.toString.call(opts.include) === "[object Array]"
) {
var flag = false;
for (var i = 0; i < opts.include.length; i++) {
if (opts.include[i].test(file)) {
Expand All @@ -56,9 +73,13 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
}

if (opts.exclude && file) {
if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') {
if (
Object.prototype.toString.call(opts.exclude) === "[object RegExp]"
) {
if (opts.exclude.test(file)) return;
} else if (Object.prototype.toString.call(opts.exclude) === '[object Array]') {
} else if (
Object.prototype.toString.call(opts.exclude) === "[object Array]"
) {
for (var i = 0; i < opts.exclude.length; i++) {
if (opts.exclude[i].test(file)) return;
}
Expand All @@ -70,13 +91,19 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
if (opts.landscape && !rule.parent.params) {
var landscapeRule = rule.clone().removeAll();

rule.walkDecls(function(decl) {
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
rule.walkDecls(function (decl) {
if (!isValueIncludeUnitToConvert(decl.value, opts.unitToConvert))
return;
if (!satisfyPropList(decl.prop)) return;

landscapeRule.append(decl.clone({
value: decl.value.replace(pxRegex, createPxReplace(opts, opts.landscapeUnit, opts.landscapeWidth))
}));
landscapeRule.append(
decl.clone({
value: decl.value.replace(
pxRegex,
createPxReplace(opts, opts.landscapeUnit, opts.landscapeWidth)
),
})
);
});

if (landscapeRule.nodes.length > 0) {
Expand All @@ -86,22 +113,36 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {

if (!validateParams(rule.parent.params, opts.mediaQuery)) return;

rule.walkDecls(function(decl, i) {
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
rule.walkDecls(function (decl, i) {
if (!isValueIncludeUnitToConvert(decl.value, opts.unitToConvert))
return;
if (!satisfyPropList(decl.prop)) return;

var prev = decl.prev();
// prev declaration is ignore conversion comment at same line
if (prev && prev.type === 'comment' && prev.text === ignoreNextComment) {
if (
prev &&
prev.type === "comment" &&
prev.text === ignoreNextComment
) {
// remove comment
prev.remove();
return;
}
var next = decl.next();
// next declaration is ignore conversion comment at same line
if (next && next.type === 'comment' && next.text === ignorePrevComment) {
if (
next &&
next.type === "comment" &&
next.text === ignorePrevComment
) {
if (/\n/.test(next.raws.before)) {
result.warn('Unexpected comment /* ' + ignorePrevComment + ' */ must be after declaration at same line.', { node: next });
result.warn(
"Unexpected comment /* " +
ignorePrevComment +
" */ must be after declaration at same line.",
{ node: next }
);
} else {
// remove comment
next.remove();
Expand All @@ -113,15 +154,18 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
var size;
var params = rule.parent.params;

if (opts.landscape && params && params.indexOf('landscape') !== -1) {
if (opts.landscape && params && params.indexOf("landscape") !== -1) {
unit = opts.landscapeUnit;
size = opts.landscapeWidth;
} else {
unit = getUnit(decl.prop, opts);
size = opts.viewportWidth;
}

var value = decl.value.replace(pxRegex, createPxReplace(opts, unit, size));
var value = decl.value.replace(
pxRegex,
createPxReplace(opts, unit, size)
);

if (declarationExists(decl.parent, decl.prop, value)) return;

Expand All @@ -134,9 +178,12 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
});

if (landscapeRules.length > 0) {
var landscapeRoot = new postcss.atRule({ params: '(orientation: landscape)', name: 'media' });
var landscapeRoot = new postcss.atRule({
params: "(orientation: landscape)",
name: "media",
});

landscapeRules.forEach(function(rule) {
landscapeRules.forEach(function (rule) {
landscapeRoot.append(rule);
});
css.append(landscapeRoot);
Expand All @@ -145,57 +192,61 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
});

function getUnit(prop, opts) {
return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit;
return prop.indexOf("font") === -1
? opts.viewportUnit
: opts.fontViewportUnit;
}

function createPxReplace(opts, viewportUnit, viewportSize) {
return function (m, $1) {
if (!$1) return m;
var pixels = parseFloat($1);
if (pixels <= opts.minPixelValue) return m;
var parsedVal = toFixed((pixels / viewportSize * 100), opts.unitPrecision);
return parsedVal === 0 ? '0' : parsedVal + viewportUnit;
var parsedVal = toFixed((pixels / viewportSize) * 100, opts.unitPrecision);
return parsedVal === 0 ? "0" : parsedVal + viewportUnit;
};
}

function error(decl, message) {
throw decl.error(message, { plugin: 'postcss-px-to-viewport' });
throw decl.error(message, { plugin: "postcss-px-to-viewport" });
}

function checkRegExpOrArray(options, optionName) {
var option = options[optionName];
if (!option) return;
if (Object.prototype.toString.call(option) === '[object RegExp]') return;
if (Object.prototype.toString.call(option) === '[object Array]') {
if (Object.prototype.toString.call(option) === "[object RegExp]") return;
if (Object.prototype.toString.call(option) === "[object Array]") {
var bad = false;
for (var i = 0; i < option.length; i++) {
if (Object.prototype.toString.call(option[i]) !== '[object RegExp]') {
if (Object.prototype.toString.call(option[i]) !== "[object RegExp]") {
bad = true;
break;
}
}
if (!bad) return;
}
throw new Error('options.' + optionName + ' should be RegExp or Array of RegExp.');
throw new Error(
"options." + optionName + " should be RegExp or Array of RegExp."
);
}

function toFixed(number, precision) {
var multiplier = Math.pow(10, precision + 1),
wholeNumber = Math.floor(number * multiplier);
return Math.round(wholeNumber / 10) * 10 / multiplier;
return (Math.round(wholeNumber / 10) * 10) / multiplier;
}

function blacklistedSelector(blacklist, selector) {
if (typeof selector !== 'string') return;
if (typeof selector !== "string") return;
return blacklist.some(function (regex) {
if (typeof regex === 'string') return selector.indexOf(regex) !== -1;
if (typeof regex === "string") return selector.indexOf(regex) !== -1;
return selector.match(regex);
});
}

function declarationExists(decls, prop, value) {
return decls.some(function (decl) {
return (decl.prop === prop && decl.value === value);
return decl.prop === prop && decl.value === value;
});
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"postcss-plugin"
],
"scripts": {
"test": "jest spec/*.spec.js"
"test": "jest spec/*.js"
},
"dependencies": {
"object-assign": ">=4.0.1"
Expand All @@ -37,4 +37,4 @@
"peerDependencies": {
"postcss": ">=5.0.2"
}
}
}
Loading