postcss-px-to-viewport
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -7,7 +7,5 @@ 'use strict'; | ||
var css = fs.readFileSync('main.css', 'utf8'); | ||
var options = { | ||
replace: false | ||
}; | ||
var processedCss = postcss(pxToViewport(options)).process(css).css; | ||
var processedCss = postcss(pxToViewport()).process(css).css; | ||
fs.writeFile('main-viewport.css', processedCss, function (err) { | ||
@@ -14,0 +12,0 @@ if (err) { |
139
index.js
@@ -6,2 +6,3 @@ 'use strict'; | ||
var { createPropListMatcher } = require('./src/prop-list-matcher'); | ||
var { getUnitRegexp } = require('./src/pixel-unit-regexp'); | ||
@@ -19,3 +20,6 @@ var defaults = { | ||
mediaQuery: false, | ||
replace: true | ||
replace: true, | ||
landscape: false, | ||
landscapeUnit: 'vw', | ||
landscapeWidth: 568 | ||
}; | ||
@@ -26,66 +30,84 @@ | ||
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, 'g'); | ||
var pxRegex = getUnitRegexp(opts.unitToConvert); | ||
var satisfyPropList = createPropListMatcher(opts.propList); | ||
var landscapeRules = []; | ||
return function (css) { | ||
css.walkRules(function (rule) { | ||
// Add exclude option to ignore some files like 'node_modules' | ||
var file = rule.source.input.file; | ||
return function (css) { | ||
css.walkDecls(function (decl, i) { | ||
// Add exlclude option to ignore some files like 'node_modules' | ||
if (opts.exclude && decl.source.input.file) { | ||
if (opts.exclude && file) { | ||
if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') { | ||
if (!handleExclude(opts.exclude, decl.source.input.file)) return; | ||
if (isExclude(opts.exclude, file)) return; | ||
} else if (Object.prototype.toString.call(opts.exclude) === '[object Array]') { | ||
for (let i = 0; i < opts.exclude.length; ++i) { | ||
if (!handleExclude(opts.exclude[i], decl.source.input.file)) return; | ||
for (let i = 0; i < opts.exclude.length; i++) { | ||
if (isExclude(opts.exclude[i], file)) return; | ||
} | ||
} else { | ||
throw new Error('options.exclude should be RegExp or Array!'); | ||
throw new Error('options.exclude should be RegExp or Array.'); | ||
} | ||
} | ||
if (blacklistedSelector(opts.selectorBlackList, rule.selector)) return; | ||
if ( | ||
decl.value.indexOf(opts.unitToConvert) === -1 || | ||
!satisfyPropList(decl.prop) || | ||
blacklistedSelector(opts.selectorBlackList, decl.parent.selector) | ||
) return; | ||
if (opts.landscape && !rule.parent.params) { | ||
var landscapeRule = rule.clone().removeAll(); | ||
var unit = getUnit(decl.prop, opts); | ||
var value = decl.value.replace(pxRegex, createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, unit)); | ||
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 (declarationExists(decl.parent, decl.prop, value)) return; | ||
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; | ||
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 (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 })); | ||
} | ||
}); | ||
}); | ||
if (opts.mediaQuery) { | ||
css.walkAtRules('media', function (rule) { | ||
if (rule.params.indexOf(opts.unitToConvert) === -1) return; | ||
rule.params = rule.params.replace(pxRegex, pxReplace); | ||
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 handleExclude (reg, file) { | ||
if (Object.prototype.toString.call(reg) !== '[object RegExp]') { | ||
throw new Error('options.exclude should be RegExp!'); | ||
} | ||
if (file.match(reg) !== null) return false; | ||
return true; | ||
} | ||
function getUnit(prop, opts) { | ||
@@ -95,8 +117,8 @@ return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit; | ||
function createPxReplace(viewportSize, minPixelValue, unitPrecision, viewportUnit) { | ||
function createPxReplace(opts, viewportUnit, viewportSize) { | ||
return function (m, $1) { | ||
if (!$1) return m; | ||
var pixels = parseFloat($1); | ||
if (pixels <= minPixelValue) return m; | ||
var parsedVal = toFixed((pixels / viewportSize * 100), unitPrecision); | ||
if (pixels <= opts.minPixelValue) return m; | ||
var parsedVal = toFixed((pixels / viewportSize * 100), opts.unitPrecision); | ||
return parsedVal === 0 ? '0' : parsedVal + viewportUnit; | ||
@@ -120,6 +142,17 @@ }; | ||
function isExclude(reg, file) { | ||
if (Object.prototype.toString.call(reg) !== '[object RegExp]') { | ||
throw new Error('options.exclude should be RegExp.'); | ||
} | ||
return file.match(reg) !== null; | ||
} | ||
function declarationExists(decls, prop, value) { | ||
return decls.some(function (decl) { | ||
return (decl.prop === prop && decl.value === value); | ||
}); | ||
} | ||
return decls.some(function (decl) { | ||
return (decl.prop === prop && decl.value === value); | ||
}); | ||
} | ||
function validateParams(params, mediaQuery) { | ||
return !params || (params && mediaQuery); | ||
} |
{ | ||
"name": "postcss-px-to-viewport", | ||
"description": "A CSS post-processor that converts px to viewport units (vw, vh, vmin, vmax).", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"author": "Dmitry Karpunin <koderfunk@gmail.com>", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
120
README.md
@@ -1,7 +0,6 @@ | ||
# postcss-px-to-viewport [![NPM version](https://badge.fury.io/js/postcss-px-to-viewport.svg)](http://badge.fury.io/js/postcss-px-to-viewport) | ||
# postcss-px-to-viewport | ||
[![NPM version](https://badge.fury.io/js/postcss-px-to-viewport.svg)](http://badge.fury.io/js/postcss-px-to-viewport) | ||
A plugin for [PostCSS](https://github.com/postcss/postcss) that generates viewport units (vw, vh, vmin, vmax) from pixel units. | ||
Feel free to start watching and ⭐ project in order not miss the release or updates. | ||
<a href="https://evrone.com/?utm_source=postcss-px-to-viewport"> | ||
@@ -12,16 +11,9 @@ <img src="https://user-images.githubusercontent.com/417688/34437029-dbfe4ee6-ecab-11e7-9d80-2b274b4149b3.png" | ||
## Install | ||
``` | ||
$ npm install postcss-px-to-viewport --save-dev | ||
``` | ||
## Demo | ||
## Usage | ||
If your project involves a fixed width, this script will help to convert pixels into viewport units. | ||
### Input/Output | ||
### Input | ||
```css | ||
// input | ||
.class { | ||
@@ -49,5 +41,6 @@ margin: -10px .5vh; | ||
} | ||
``` | ||
// output | ||
### Output | ||
```css | ||
.class { | ||
@@ -69,6 +62,6 @@ margin: -3.125vw .5vh; | ||
@media (min-width: 234.375vw) { | ||
@media (min-width: 750px) { | ||
.class3 { | ||
font-size: 5vw; | ||
line-height: 6.875vw; | ||
font-size: 16px; | ||
line-height: 22px; | ||
} | ||
@@ -78,27 +71,17 @@ } | ||
### Example | ||
## Getting Started | ||
```js | ||
'use strict'; | ||
var fs = require('fs'); | ||
var postcss = require('postcss'); | ||
var pxToViewport = require('..'); | ||
var css = fs.readFileSync('main.css', 'utf8'); | ||
var options = { | ||
replace: false | ||
}; | ||
var processedCss = postcss(pxToViewport(options)).process(css).css; | ||
fs.writeFile('main-viewport.css', processedCss, function (err) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('File with viewport units written.'); | ||
}); | ||
### Installation | ||
Add via npm | ||
``` | ||
$ npm install postcss-px-to-viewport --save-dev | ||
``` | ||
or yarn | ||
``` | ||
$ yarn add postcss-px-to-viewport | ||
``` | ||
### Options | ||
### Usage | ||
Default: | ||
Default Options: | ||
```js | ||
@@ -108,7 +91,6 @@ { | ||
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. | ||
fontViewportUnit: 'vw', | ||
selectorBlackList: [], | ||
@@ -118,3 +100,6 @@ minPixelValue: 1, | ||
replace: true, | ||
exclude: [] // ignore some files | ||
exclude: [], | ||
landscape: false, | ||
landscapeUnit: 'vw', | ||
landscapeWidth: 568 | ||
} | ||
@@ -124,3 +109,2 @@ ``` | ||
- `viewportWidth` (Number) The width of the viewport. | ||
- `viewportHeight` (Number) The height of the viewport. | ||
- `unitPrecision` (Number) The decimal numbers to allow the vw units to grow to. | ||
@@ -146,5 +130,9 @@ - `propList` (Array) The properties that can change from px to vw. | ||
- If value is array, the elements of the array are regexp. | ||
- `landscape` (Boolean) Adds `@media (orientation: landscape)` with values converted via `landscapeWidth`. | ||
- `landscapeUnit` (String) Expected unit for `landscape` option | ||
- `landscapeWidth` (Number) Viewport width for landscape orientation. | ||
### Use with gulp-postcss | ||
add to your gulp config: | ||
#### Use with gulp-postcss | ||
add to your `gulpfile.js`: | ||
```js | ||
@@ -169,4 +157,6 @@ var gulp = require('gulp'); | ||
``` | ||
### Use with Postcss configuration file | ||
add to postcss.config.js | ||
#### Use with PostCss configuration file | ||
add to your `postcss.config.js` | ||
```js | ||
@@ -182,1 +172,39 @@ module.exports = { | ||
``` | ||
## Running the tests | ||
In order to run tests, you need to install `jasmine-node` globally: | ||
``` | ||
$ npm install jasmine-node -g | ||
``` | ||
Then run the tests via npm script: | ||
``` | ||
$ npm run test | ||
``` | ||
## Contributing | ||
Please read [Code of Conduct](CODE-OF-CONDUCT.md) and [Contributing Guidelines](CONTRIBUTING.md) for submitting pull requests to us. | ||
## Versioning | ||
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/evrone/postcss-px-to-viewport/tags). | ||
## Changelog | ||
The changelog is [here](CHANGELOG.md). | ||
## Authors | ||
* [Dmitry Karpunin](https://github.com/KODerFunk) - *Initial work* | ||
* [Ivan Bunin](https://github.com/chernobelenkiy) | ||
See also the list of [contributors](https://github.com/evrone/postcss-px-to-viewport/contributors) who participated in this project. | ||
## License | ||
This project is licensed under the [MIT License](LICENSE). | ||
## Acknowledgments | ||
* Hat tip to https://github.com/cuth/postcss-pxtorem/ for inspiring us for this project. |
var filterPropList = { | ||
exact: function (list) { | ||
return list.filter(function (m) { | ||
return m.match(/^[^\*\!]+$/); | ||
}); | ||
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); | ||
}); | ||
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); | ||
}); | ||
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); | ||
}); | ||
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); | ||
}); | ||
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); | ||
}); | ||
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); | ||
}); | ||
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); | ||
}); | ||
return list.filter(function (m) { | ||
return m.match(/^\![^\*]+\*$/); | ||
}).map(function (m) { | ||
return m.substr(1, m.length - 2); | ||
}); | ||
} | ||
@@ -62,40 +62,40 @@ }; | ||
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) | ||
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; | ||
}) | ||
) | ||
); | ||
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; | ||
}) | ||
) | ||
); | ||
}; | ||
@@ -105,4 +105,4 @@ } | ||
module.exports = { | ||
filterPropList, | ||
createPropListMatcher | ||
filterPropList, | ||
createPropListMatcher | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
21789
12
303
201
0