From df6516177a508289f0aee55fcda6a349821fc2c4 Mon Sep 17 00:00:00 2001 From: Ivan Bunin Date: Fri, 1 Feb 2019 16:03:04 +0300 Subject: [PATCH] add landscape orientation option --- index.js | 48 ++++++++++++++++++++++++------- spec/px-to-viewport.spec.js | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index b130e2d..d2cb976 100755 --- a/index.js +++ b/index.js @@ -16,7 +16,9 @@ var defaults = { propList: ['*'], minPixelValue: 1, mediaQuery: false, - replace: true + replace: true, + landscape: false, + landscapeUnit: 'vh' }; module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { @@ -24,7 +26,8 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { var opts = objectAssign({}, defaults, options); 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' @@ -42,18 +45,32 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { } } - if (rule.parent.params && !opts.mediaQuery) return; + if (!validateParams(rule.parent.params, opts.mediaQuery)) return; if (blacklistedSelector(opts.selectorBlackList, rule.selector)) return; + if (opts.landscape && !rule.parent.params) { + var landscapeRule = rule.clone().removeAll(); + landscapeRules.push(landscapeRule); + + 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)) + })); + }); + } + rule.walkDecls(function(decl, i) { if (decl.value.indexOf(opts.unitToConvert) === -1) return; if (!satisfyPropList(decl.prop)) return; var unit = getUnit(decl.prop, opts); - var value = decl.value.replace(pxRegex, createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, unit)); - + var value = decl.value.replace(pxRegex, createPxReplace(opts, unit)); + if (declarationExists(decl.parent, decl.prop, value)) return; - + if (opts.replace) { decl.value = value; } else { @@ -61,6 +78,13 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { } }); }); + + if (landscapeRules.length > 0) { + var landscapeRoot = new postcss.atRule({ params: '(orientation: landscape)', name: 'media' }); + + landscapeRules.forEach(rule => landscapeRoot.append(rule)); + css.append(landscapeRoot); + } }; }); @@ -75,12 +99,12 @@ function getUnit(prop, opts) { return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit; } -function createPxReplace(viewportSize, minPixelValue, unitPrecision, viewportUnit) { +function createPxReplace(opts, viewportUnit) { 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 / opts.viewportWidth * 100), opts.unitPrecision); return parsedVal === 0 ? '0' : parsedVal + viewportUnit; }; } @@ -103,4 +127,8 @@ function declarationExists(decls, prop, value) { return decls.some(function (decl) { return (decl.prop === prop && decl.value === value); }); -} \ No newline at end of file +} + +function validateParams(params, mediaQuery) { + return !params || (params && mediaQuery && params.indexOf('landscape') === -1); +} diff --git a/spec/px-to-viewport.spec.js b/spec/px-to-viewport.spec.js index dab0b51..d327259 100644 --- a/spec/px-to-viewport.spec.js +++ b/spec/px-to-viewport.spec.js @@ -221,6 +221,16 @@ describe('mediaQuery', function () { expect(processed).toBe(expected); }); + + it('should not replace px inside media queries if it has params orientation landscape', function() { + var options = { + mediaQuery: true + }; + var processed = postcss(pxToViewport(options)).process('@media (orientation-landscape) and (min-width: 500px) { .rule { font-size: 16px } }').css; + var expected = '@media (orientation-landscape) and (min-width: 500px) { .rule { font-size: 16px } }'; + + expect(processed).toBe(expected); + }); }); describe('propList', function () { @@ -379,3 +389,50 @@ describe('filter-prop-list', function () { }); }); +describe('landscape', function() { + it('should add landscape atRule', function() { + var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }'; + var expected = '.rule { font-size: 5vw; margin: 5vw; margin-left: 1.5625vw; padding: 1.5625vw; padding-right: 5vw }@media (orientation: landscape) {.rule { font-size: 5vh; margin: 5vh; margin-left: 1.5625vh; padding: 1.5625vh; padding-right: 5vh } }'; + var options = { + landscape: true + }; + var processed = postcss(pxToViewport(options)).process(css).css; + + expect(processed).toBe(expected); + }); + + it('should add landscape atRule with specified landscapeUnits', function() { + var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }'; + var expected = '.rule { font-size: 5vw; margin: 5vw; margin-left: 1.5625vw; padding: 1.5625vw; padding-right: 5vw }@media (orientation: landscape) {.rule { font-size: 5vw; margin: 5vw; margin-left: 1.5625vw; padding: 1.5625vw; padding-right: 5vw } }'; + var options = { + landscape: true, + landscapeUnit: 'vw' + }; + var processed = postcss(pxToViewport(options)).process(css).css; + + expect(processed).toBe(expected); + }); + + it('should not add landscape atRule in mediaQueries', function() { + var css = '@media (min-width: 500px) { .rule { font-size: 16px } }'; + var expected = '@media (min-width: 500px) { .rule { font-size: 5vw } }'; + var options = { + landscape: true, + mediaQuery: true + }; + var processed = postcss(pxToViewport(options)).process(css).css; + + expect(processed).toBe(expected); + }); + + it('should not replace values inside landscape atRule', function() { + var options = { + replace: false, + landscape: true + }; + var processed = postcss(pxToViewport(options)).process(basicCSS).css; + var expected = '.rule { font-size: 15px; font-size: 4.6875vw }@media (orientation: landscape) {.rule { font-size: 4.6875vh } }'; + + expect(processed).toBe(expected); + }) +});