xy-postcss-px-to-viewport
Advanced tools
Comparing version 1.0.0 to 2.0.1
@@ -8,2 +8,8 @@ # Changelog | ||
## [2.0.0] - 2024-06-13 | ||
### Support | ||
- support `postcss` version `8.x` | ||
## [1.0.0] - 2022-10-26 | ||
@@ -14,4 +20,4 @@ | ||
- `include` (Regexp or Array of Regexp) If `include` is set, only matching files will be converted, | ||
for example, only files under `src/mobile/` (`include: /\/src\/mobile\//`) | ||
- for example, only files under `src/mobile/` (`include: /\/src\/mobile\//`) | ||
- If the value is regexp, the matching file will be included, otherwise it will be excluded. | ||
- If value is array, the elements of the array are regexp. |
230
index.js
@@ -9,16 +9,15 @@ 'use strict'; | ||
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. | ||
selectorBlackList: [], | ||
propList: ['*'], | ||
minPixelValue: 1, | ||
mediaQuery: false, | ||
replace: true, | ||
landscape: false, | ||
landscapeUnit: 'vw', | ||
landscapeWidth: 568 | ||
unitToConvert: 'px', // 需要转换的单位 | ||
viewportUnit: 'vw', // 转换后的单位 | ||
fontViewportUnit: 'vw', // 字体使用的视口单位 | ||
viewportWidth: 750, // 标准视图宽度 | ||
unitPrecision: 5, // 转换后保留的精度 | ||
minPixelValue: 1, // 最小转换数值 | ||
selectorBlackList: [], // 选择器黑名单列表 | ||
propList: ['*'], // 能转换的属性列表;*代表所有 | ||
mediaQuery: false, // 媒体查询里的单位是否需要转换 | ||
replace: true, // 是否直接更换属性,不添加备用属性 | ||
landscape: false, // 是否添加 | ||
landscapeUnit: 'vw', // 横屏时使用的单位 | ||
landscapeWidth: 425 // 横屏宽度 | ||
}; | ||
@@ -29,3 +28,3 @@ | ||
module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { | ||
const plugin = function (options) { | ||
var opts = objectAssign({}, defaults, options); | ||
@@ -40,111 +39,116 @@ | ||
return function (css, result) { | ||
css.walkRules(function (rule) { | ||
// Add exclude option to ignore some files like 'node_modules' | ||
var file = rule.source && rule.source.input.file; | ||
if (opts.include && file) { | ||
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]') { | ||
var flag = false; | ||
for (var i = 0; i < opts.include.length; i++) { | ||
if (opts.include[i].test(file)) { | ||
flag = true; | ||
break; | ||
return { | ||
postcssPlugin: 'xy-postcss-px-to-viewport', | ||
prepare(result) { | ||
var root = result.root | ||
root.walkRules((rule) => { | ||
var file = rule.source && rule.source.input.file; | ||
if (opts.include && file) { | ||
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]') { | ||
var flag = false; | ||
for (var i = 0; i < opts.include.length; i++) { | ||
if (opts.include[i].test(file)) { | ||
flag = true; | ||
break; | ||
} | ||
} | ||
if (!flag) return; | ||
} | ||
if (!flag) return; | ||
} | ||
} | ||
if (opts.exclude && file) { | ||
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]') { | ||
for (var i = 0; i < opts.exclude.length; i++) { | ||
if (opts.exclude[i].test(file)) return; | ||
if (opts.exclude && file) { | ||
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]') { | ||
for (var i = 0; i < opts.exclude.length; i++) { | ||
if (opts.exclude[i].test(file)) return; | ||
} | ||
} | ||
} | ||
} | ||
if (blacklistedSelector(opts.selectorBlackList, rule.selector)) return; | ||
if (opts.landscape && !rule.parent.params) { | ||
var landscapeRule = rule.clone().removeAll(); | ||
rule.walkDecls(function(decl) { | ||
if (blacklistedSelector(opts.selectorBlackList, rule.selector)) return; | ||
if (opts.landscape && !rule.parent.params) { | ||
var landscapeRule = rule.clone().removeAll(); | ||
rule.walkDecls(function(decl) { | ||
if (decl.value.indexOf(opts.unitToConvert) === -1) return; | ||
if (!satisfyPropList(decl.prop)) return; | ||
landscapeRule.append(decl.clone({ | ||
value: decl.value.replace(pxRegex, createPxReplace(opts, opts.landscapeUnit, opts.landscapeWidth)) | ||
})); | ||
}); | ||
if (landscapeRule.nodes.length > 0) { | ||
landscapeRules.push(landscapeRule); | ||
} | ||
} | ||
if (!validateParams(rule.parent.params, opts.mediaQuery)) return; | ||
rule.walkDecls(function(decl, i) { | ||
if (decl.value.indexOf(opts.unitToConvert) === -1) return; | ||
if (!satisfyPropList(decl.prop)) return; | ||
landscapeRule.append(decl.clone({ | ||
value: decl.value.replace(pxRegex, createPxReplace(opts, opts.landscapeUnit, opts.landscapeWidth)) | ||
})); | ||
}); | ||
if (landscapeRule.nodes.length > 0) { | ||
landscapeRules.push(landscapeRule); | ||
} | ||
} | ||
if (!validateParams(rule.parent.params, opts.mediaQuery)) return; | ||
rule.walkDecls(function(decl, i) { | ||
if (decl.value.indexOf(opts.unitToConvert) === -1) 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) { | ||
// 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 (/\n/.test(next.raws.before)) { | ||
result.warn('Unexpected comment /* ' + ignorePrevComment + ' */ must be after declaration at same line.', { node: next }); | ||
} else { | ||
var prev = decl.prev(); | ||
// prev declaration is ignore conversion comment at same line | ||
if (prev && prev.type === 'comment' && prev.text === ignoreNextComment) { | ||
// remove comment | ||
next.remove(); | ||
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 (/\n/.test(next.raws.before)) { | ||
result.warn('Unexpected comment /* ' + ignorePrevComment + ' */ must be after declaration at same line.', { node: next }); | ||
} else { | ||
// remove comment | ||
next.remove(); | ||
return; | ||
} | ||
} | ||
var unit; | ||
var size; | ||
var params = rule.parent.params; | ||
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)); | ||
if (declarationExists(decl.parent, decl.prop, value)) return; | ||
if (opts.replace) { | ||
decl.value = value; | ||
} else { | ||
decl.parent.insertAfter(i, decl.clone({ value: value })); | ||
} | ||
}); | ||
}) | ||
var unit; | ||
var size; | ||
var params = rule.parent.params; | ||
if (landscapeRules.length > 0) { | ||
let landscapeRoot = new postcss.AtRule({ | ||
params: "(orientation: landscape)", | ||
name: "media", | ||
}); | ||
landscapeRules.forEach((rule) => landscapeRoot.append(rule)); | ||
root.append(landscapeRoot); | ||
} | ||
}, | ||
} | ||
}; | ||
if (opts.landscape && params && params.indexOf('landscape') !== -1) { | ||
unit = opts.landscapeUnit; | ||
size = opts.landscapeWidth; | ||
} else { | ||
unit = getUnit(decl.prop, opts); | ||
size = opts.viewportWidth; | ||
} | ||
plugin.postcss = true | ||
module.exports = plugin | ||
var value = decl.value.replace(pxRegex, createPxReplace(opts, unit, size)); | ||
if (declarationExists(decl.parent, decl.prop, value)) return; | ||
if (opts.replace) { | ||
decl.value = value; | ||
} else { | ||
decl.parent.insertAfter(i, decl.clone({ value: value })); | ||
} | ||
}); | ||
}); | ||
if (landscapeRules.length > 0) { | ||
var landscapeRoot = new postcss.atRule({ params: '(orientation: landscape)', name: 'media' }); | ||
landscapeRules.forEach(function(rule) { | ||
landscapeRoot.append(rule); | ||
}); | ||
css.append(landscapeRoot); | ||
} | ||
}; | ||
}); | ||
function getUnit(prop, opts) { | ||
@@ -164,6 +168,2 @@ return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit; | ||
function error(decl, message) { | ||
throw decl.error(message, { plugin: 'postcss-px-to-viewport' }); | ||
} | ||
function checkRegExpOrArray(options, optionName) { | ||
@@ -170,0 +170,0 @@ var option = options[optionName]; |
{ | ||
"name": "xy-postcss-px-to-viewport", | ||
"description": "A CSS post-processor that converts px to viewport units (vw, vh, vmin, vmax).", | ||
"version": "1.0.0", | ||
"version": "2.0.1", | ||
"author": "au1996", | ||
@@ -35,7 +35,7 @@ "license": "MIT", | ||
"jest": "^25.4.0", | ||
"postcss": ">=5.0.2" | ||
"postcss": "^8.0.0" | ||
}, | ||
"peerDependencies": { | ||
"postcss": ">=5.0.2" | ||
"postcss": "^8.0.0" | ||
} | ||
} |
@@ -9,3 +9,3 @@ # xy-postcss-px-to-viewport | ||
**支持 include 配置** | ||
## 支持 include 配置 | ||
@@ -20,3 +20,3 @@ ## 简介 | ||
.class { | ||
margin: -10px 0.5vh; | ||
margin: -10px .5vh; | ||
padding: 5vmin 9.5px 1px; | ||
@@ -30,6 +30,2 @@ border: 3px solid black; | ||
.class2 { | ||
padding-top: 10px; /* px-to-viewport-ignore */ | ||
/* px-to-viewport-ignore-next */ | ||
padding-bottom: 10px; | ||
/* Any other comment */ | ||
border: 1px solid black; | ||
@@ -53,18 +49,15 @@ margin-bottom: 1px; | ||
.class { | ||
margin: -3.125vw 0.5vh; | ||
padding: 5vmin 2.96875vw 1px; | ||
border: 0.9375vw solid black; | ||
margin: -1.33333vw .5vh; | ||
padding: 5vmin 1.26667vw 1px; | ||
border: 0.4vw solid black; | ||
border-bottom-width: 1px; | ||
font-size: 4.375vw; | ||
line-height: 6.25vw; | ||
font-size: 1.86667vw; | ||
line-height: 2.66667vw; | ||
} | ||
.class2 { | ||
padding-top: 10px; | ||
padding-bottom: 10px; | ||
/* Any other comment */ | ||
border: 1px solid black; | ||
margin-bottom: 1px; | ||
font-size: 6.25vw; | ||
line-height: 9.375vw; | ||
font-size: 2.66667vw; | ||
line-height: 4vw; | ||
} | ||
@@ -118,9 +111,9 @@ | ||
unitToConvert: 'px', | ||
viewportWidth: 320, | ||
unitPrecision: 5, | ||
propList: ['*'], | ||
viewportUnit: 'vw', | ||
fontViewportUnit: 'vw', | ||
viewportWidth: 750, | ||
unitPrecision: 5, | ||
minPixelValue: 1, | ||
selectorBlackList: [], | ||
minPixelValue: 1, | ||
propList: ['*'], | ||
mediaQuery: false, | ||
@@ -132,3 +125,3 @@ replace: true, | ||
landscapeUnit: 'vw', | ||
landscapeWidth: 568 | ||
landscapeWidth: 425 | ||
} | ||
@@ -169,8 +162,8 @@ ``` | ||
#### Ignoring (需要翻译帮助。) | ||
#### 忽略示例 | ||
You can use special comments for ignore conversion of single lines: | ||
您可以使用特殊注释来忽略单行的转换: | ||
- `/* px-to-viewport-ignore-next */` — on a separate line, prevents conversion on the next line. | ||
- `/* px-to-viewport-ignore */` — after the property on the right, prevents conversion on the same line. | ||
- `/* px-to-viewport-ignore-next */` — 在单独的行上,可防止在下一行进行转换。 | ||
- `/* px-to-viewport-ignore */` — 在右侧的属性之后,防止在同一行进行转换。 | ||
@@ -192,3 +185,3 @@ Example: | ||
width: 10px; | ||
padding: 3.125vw; | ||
padding: 1.33333vw; | ||
height: 10px; | ||
@@ -199,3 +192,3 @@ border: solid 2px #000; | ||
There are several more reasons why your pixels may not convert, the following options may affect this: | ||
还有多种原因导致您的像素无法转换,以下选项可能会影响此情况: | ||
`propList`, `selectorBlackList`, `minPixelValue`, `mediaQuery`, `exclude`, `include`. | ||
@@ -245,7 +238,7 @@ | ||
变更日志在 [这](CHANGELOG.md). | ||
变更日志在 [这里](CHANGELOG.md). | ||
## 版本跟踪 | ||
使用 [SemVer](http://semver.org/) 做版本跟踪, 可用版本可在[这](https://github.com/au1996/postcss-px-to-viewport/tags)看到 | ||
使用 [SemVer](http://semver.org/) 做版本跟踪, 可用版本可在[这里](https://github.com/au1996/postcss-px-to-viewport/tags)看到 | ||
@@ -252,0 +245,0 @@ ## 许可 |
@@ -9,3 +9,3 @@ # xy-postcss-px-to-viewport | ||
**Support include configuration** | ||
## Support include configuration | ||
@@ -20,3 +20,3 @@ ## Demo | ||
.class { | ||
margin: -10px 0.5vh; | ||
margin: -10px .5vh; | ||
padding: 5vmin 9.5px 1px; | ||
@@ -30,6 +30,2 @@ border: 3px solid black; | ||
.class2 { | ||
padding-top: 10px; /* px-to-viewport-ignore */ | ||
/* px-to-viewport-ignore-next */ | ||
padding-bottom: 10px; | ||
/* Any other comment */ | ||
border: 1px solid black; | ||
@@ -53,20 +49,15 @@ margin-bottom: 1px; | ||
.class { | ||
margin: -3.125vw 0.5vh; | ||
padding: 5vmin 2.96875vw 1px; | ||
border: 0.9375vw solid black; | ||
margin: -1.33333vw .5vh; | ||
padding: 5vmin 1.26667vw 1px; | ||
border: 0.4vw solid black; | ||
border-bottom-width: 1px; | ||
font-size: 4.375vw; | ||
line-height: 6.25vw; | ||
font-size: 1.86667vw; | ||
line-height: 2.66667vw; | ||
} | ||
.class2 { | ||
padding-top: 10px; | ||
padding-bottom: 10px; | ||
/* Any other comment */ | ||
border: 1px solid black; | ||
margin-bottom: 1px; | ||
font-size: 6.25vw; | ||
line-height: 9.375vw; | ||
font-size: 2.66667vw; | ||
line-height: 4vw; | ||
} | ||
@media (min-width: 750px) { | ||
@@ -118,9 +109,9 @@ .class3 { | ||
unitToConvert: 'px', | ||
viewportWidth: 320, | ||
unitPrecision: 5, | ||
propList: ['*'], | ||
viewportUnit: 'vw', | ||
fontViewportUnit: 'vw', | ||
viewportWidth: 750, | ||
unitPrecision: 5, | ||
minPixelValue: 1, | ||
selectorBlackList: [], | ||
minPixelValue: 1, | ||
propList: ['*'], | ||
mediaQuery: false, | ||
@@ -132,3 +123,3 @@ replace: true, | ||
landscapeUnit: 'vw', | ||
landscapeWidth: 568 | ||
landscapeWidth: 425 | ||
} | ||
@@ -191,3 +182,3 @@ ``` | ||
width: 10px; | ||
padding: 3.125vw; | ||
padding: 1.33333vw; | ||
height: 10px; | ||
@@ -194,0 +185,0 @@ border: solid 2px #000; |
Sorry, the diff of this file is not supported yet
405
30045
12
241