diff --git a/README.md b/README.md index 91019b5..0de6157 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ yarn add postcss-px-to-viewport-8-plugin -D selectorBlackList: [], minPixelValue: 1, mediaQuery: false, + keyframes: false, replace: true, exclude: [], landscape: false, @@ -121,23 +122,24 @@ yarn add postcss-px-to-viewport-8-plugin -D ## API 说明 -| 参数 | 说明 | 类型 | 默认值 | -| :-- | --- | --- | --- | -| `unitToConvert` | 需要转换的单位,默认为 px | `string` | px | -| `viewportWidth` | 设计稿的视口宽度,如传入函数,函数的参数为当前处理的文件路径,函数返回 `undefind` 跳过转换 | `number \| Function` | 320 | -| `unitPrecision` | 单位转换后保留的精度 | `number` | 5 | -| `propList` | 能转化为 vw 的属性列表 | `string[]` | ['*'] | -| `viewportUnit` | 希望使用的视口单位 | `string` | vw | -| `fontViewportUnit` | 字体使用的视口单位 | `string` | vw | -| `selectorBlackList` | 需要忽略的 CSS 选择器,不会转为视口单位,使用原有的 px 等单位 | `string[]` | [] | -| `minPixelValue` | 设置最小的转换数值,如果为 1 的话,只有大于 1 的值会被转换 | `number` | 1 | -| `mediaQuery` | 媒体查询里的单位是否需要转换单位 | `boolean` | false | -| `replace` | 是否直接更换属性值,而不添加备用属性 | `boolean` | true | -| `landscape` | 是否添加根据 `landscapeWidth` 生成的媒体查询条件 `@media (orientation: landscape)` | `boolean` | false | -| `landscapeUnit` | 横屏时使用的单位 | `string` | vw | -| `landscapeWidth` | 横屏时使用的视口宽度,,如传入函数,函数的参数为当前处理的文件路径,函数返回 `undefind` 跳过转换 | `number` | 568 | -| `exclude` | 忽略某些文件夹下的文件或特定文件,例如 node_modules 下的文件,如果值是一个正则表达式,那么匹配这个正则的文件会被忽略,如果传入的值是一个数组,那么数组里的值必须为正则 | `Regexp` | undefined | -| `include` | 需要转换的文件,例如只转换 'src/mobile' 下的文件 (`include: /\/src\/mobile\//`),如果值是一个正则表达式,将包含匹配的文件,否则将排除该文件, 如果传入的值是一个数组,那么数组里的值必须为正则 | `Regexp` | undefined | +| 参数 | 说明 | 类型 | 默认值 | +| :------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | --------- | +| `unitToConvert` | 需要转换的单位,默认为 px | `string` | px | +| `viewportWidth` | 设计稿的视口宽度,如传入函数,函数的参数为当前处理的文件路径,函数返回 `undefind` 跳过转换 | `number \| Function` | 320 | +| `unitPrecision` | 单位转换后保留的精度 | `number` | 5 | +| `propList` | 能转化为 vw 的属性列表 | `string[]` | ['*'] | +| `viewportUnit` | 希望使用的视口单位 | `string` | vw | +| `fontViewportUnit` | 字体使用的视口单位 | `string` | vw | +| `selectorBlackList` | 需要忽略的 CSS 选择器,不会转为视口单位,使用原有的 px 等单位 | `string[]` | [] | +| `minPixelValue` | 设置最小的转换数值,如果为 1 的话,只有大于 1 的值会被转换 | `number` | 1 | +| `mediaQuery` | 媒体查询里的单位是否需要转换单位 | `boolean` | false | +| `keyframes` | 关键帧里的单位是否需要转换单位 | `boolean` | false | +| `replace` | 是否直接更换属性值,而不添加备用属性 | `boolean` | true | +| `landscape` | 是否添加根据 `landscapeWidth` 生成的媒体查询条件 `@media (orientation: landscape)` | `boolean` | false | +| `landscapeUnit` | 横屏时使用的单位 | `string` | vw | +| `landscapeWidth` | 横屏时使用的视口宽度,,如传入函数,函数的参数为当前处理的文件路径,函数返回 `undefind` 跳过转换 | `number` | 568 | +| `exclude` | 忽略某些文件夹下的文件或特定文件,例如 node_modules 下的文件,如果值是一个正则表达式,那么匹配这个正则的文件会被忽略,如果传入的值是一个数组,那么数组里的值必须为正则 | `Regexp` | undefined | +| `include` | 需要转换的文件,例如只转换 'src/mobile' 下的文件 (`include: /\/src\/mobile\//`),如果值是一个正则表达式,将包含匹配的文件,否则将排除该文件, 如果传入的值是一个数组,那么数组里的值必须为正则 | `Regexp` | undefined | ## 补充说明 @@ -214,7 +216,7 @@ export default defineConfig({ plugins: [ postcsspxtoviewport8plugin({ unitToConvert: 'px', - viewportWidth: file => { + viewportWidth: (file) => { let num = 1920; if (file.indexOf('m_') !== -1) { num = 375; @@ -228,6 +230,7 @@ export default defineConfig({ selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。 minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换 mediaQuery: true, // 媒体查询里的单位是否需要转换单位 + keyframes: true, // 关键帧里的单位是否需要转换单位 replace: true, // 是否直接更换属性值,而不添加备用属性 exclude: [/node_modules\/ant-design-vue/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件 include: [], // 如果设置了include,那将只有匹配到的文件才会被转换 diff --git a/package.json b/package.json index 9beeeb4..6426fc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-px-to-viewport-8-plugin", - "version": "1.2.5", + "version": "1.2.6", "main": "lib/index.js", "module": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/spec/px-to-viewport.spec.ts b/spec/px-to-viewport.spec.js similarity index 87% rename from spec/px-to-viewport.spec.ts rename to spec/px-to-viewport.spec.js index 9d91a2b..244b56a 100644 --- a/spec/px-to-viewport.spec.ts +++ b/spec/px-to-viewport.spec.js @@ -11,10 +11,8 @@ var { filterPropList } = require('../src/prop-list-matcher'); describe('px-to-viewport', function() { it('should work on the readme example', function() { - var input = - 'h1 { margin: 0 0 20px; font-size: 32px; line-height: 2; letter-spacing: 1px; }'; - var output = - 'h1 { margin: 0 0 6.25vw; font-size: 10vw; line-height: 2; letter-spacing: 1px; }'; + var input = 'h1 { margin: 0 0 20px; font-size: 32px; line-height: 2; letter-spacing: 1px; }'; + var output = 'h1 { margin: 0 0 6.25vw; font-size: 10vw; line-height: 2; letter-spacing: 1px; }'; var processed = postcss(pxToViewport()).process(input).css; expect(processed).toBe(output); @@ -67,10 +65,8 @@ describe('value parsing', function() { var options = { propList: ['*'], }; - var rules = - '.rule { content: \'16px\'; font-family: "16px"; font-size: 16px; }'; - var expected = - '.rule { content: \'16px\'; font-family: "16px"; font-size: 5vw; }'; + var rules = '.rule { content: \'16px\'; font-family: "16px"; font-size: 16px; }'; + var expected = '.rule { content: \'16px\'; font-family: "16px"; font-size: 5vw; }'; var processed = postcss(pxToViewport(options)).process(rules).css; expect(processed).toBe(expected); @@ -251,6 +247,32 @@ describe('mediaQuery', function() { }); }); +describe('keyframes', function() { + it('should replace px inside media queries if opts.keyframes', function() { + var options = { + keyframes: true, + }; + var processed = postcss(pxToViewport(options)).process( + '@keyframes slidein { from { transform: translateX(16px) } }', + ).css; + var expected = '@keyframes slidein { from { transform: translateX(5vw) } }'; + + expect(processed).toBe(expected); + }); + + it('should not replace px inside media queries if not opts.keyframes', function() { + var options = { + keyframes: false, + }; + var processed = postcss(pxToViewport(options)).process( + '@keyframes slidein { from { transform: translateX(16px) } }', + ).css; + var expected = '@keyframes slidein { from { transform: translateX(16px) } }'; + + expect(processed).toBe(expected); + }); +}); + describe('propList', function() { it('should only replace properties in the prop list', function() { var css = @@ -293,10 +315,8 @@ describe('minPixelValue', function() { propWhiteList: [], minPixelValue: 2, }; - var rules = - '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; - var expected = - '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; + var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; + var expected = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; var processed = postcss(pxToViewport(options)).process(rules).css; expect(processed).toBe(expected); @@ -304,10 +324,8 @@ describe('minPixelValue', function() { }); describe('exclude', function() { - var rules = - '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; - var covered = - '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; + var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; + var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; it('when using regex at the time, the style should not be overwritten.', function() { var options = { exclude: /\/node_modules\//, @@ -354,10 +372,8 @@ describe('exclude', function() { }); describe('include', function() { - var rules = - '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; - var covered = - '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; + var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; + var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; it('when using regex at the time, the style should not be overwritten.', function() { var options = { include: /\/mobile\//, @@ -404,10 +420,8 @@ describe('include', function() { }); describe('include-and-exclude', function() { - var rules = - '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; - var covered = - '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; + var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; + var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; it('when using regex at the time, the style should not be overwritten.', function() { var options = { @@ -459,10 +473,8 @@ describe('include-and-exclude', function() { }); describe('regex', function() { - var rules = - '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; - var covered = - '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; + var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; + var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'; it('when using regex at the time, the style should not be overwritten.', function() { var options = { @@ -523,113 +535,49 @@ describe('replace', function() { describe('filter-prop-list', function() { it('should find "exact" matches from propList', function() { - var propList = [ - 'font-size', - 'margin', - '!padding', - '*border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', 'margin', '!padding', '*border*', '*', '*y', '!*font*']; var expected = 'font-size,margin'; expect(filterPropList.exact(propList).join()).toBe(expected); }); it('should find "contain" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - '*border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', '*border*', '*', '*y', '!*font*']; var expected = 'margin,border'; expect(filterPropList.contain(propList).join()).toBe(expected); }); it('should find "start" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - 'border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', 'border*', '*', '*y', '!*font*']; var expected = 'border'; expect(filterPropList.startWith(propList).join()).toBe(expected); }); it('should find "end" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - 'border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', 'border*', '*', '*y', '!*font*']; var expected = 'y'; expect(filterPropList.endWith(propList).join()).toBe(expected); }); it('should find "not" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - 'border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', 'border*', '*', '*y', '!*font*']; var expected = 'padding'; expect(filterPropList.notExact(propList).join()).toBe(expected); }); it('should find "not contain" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - '!border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', '!border*', '*', '*y', '!*font*']; var expected = 'font'; expect(filterPropList.notContain(propList).join()).toBe(expected); }); it('should find "not start" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - '!border*', - '*', - '*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', '!border*', '*', '*y', '!*font*']; var expected = 'border'; expect(filterPropList.notStartWith(propList).join()).toBe(expected); }); it('should find "not end" matches from propList and reduce to string', function() { - var propList = [ - 'font-size', - '*margin*', - '!padding', - '!border*', - '*', - '!*y', - '!*font*', - ]; + var propList = ['font-size', '*margin*', '!padding', '!border*', '*', '!*y', '!*font*']; var expected = 'y'; expect(filterPropList.notEndWith(propList).join()).toBe(expected); }); @@ -726,8 +674,7 @@ describe('/* px-to-viewport-ignore */ & /* px-to-viewport-ignore-next */', funct it('should ignore right-commented in multiline-css', function() { var css = '.rule {\n font-size: 15px;\n width: 100px; /*px-to-viewport-ignore*/\n height: 50px;\n}'; - var expected = - '.rule {\n font-size: 4.6875vw;\n width: 100px;\n height: 15.625vw;\n}'; + var expected = '.rule {\n font-size: 4.6875vw;\n width: 100px;\n height: 15.625vw;\n}'; var processed = postcss(pxToViewport()).process(css).css; diff --git a/src/index.ts b/src/index.ts index a8159a8..8d1dcb2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,6 @@ import { declarationExists, getUnit, isExclude, - validateParams, } from './utils'; import objectAssign from 'object-assign'; @@ -25,6 +24,7 @@ const defaults: Required> = { propList: ['*'], minPixelValue: 1, mediaQuery: false, + keyframes: false, replace: true, landscape: false, landscapeUnit: 'vw', @@ -94,7 +94,14 @@ const postcssPxToViewport = (options: OptionType) => { } } - if (!validateParams(rule.parent?.params, opts.mediaQuery)) return; + if (rule.parent.type === 'atrule') { + if (rule.parent.name === 'media' && !opts.mediaQuery) { + return; + } + if (rule.parent.name === 'keyframes' && !opts.keyframes) { + return; + } + } rule.walkDecls((decl, i) => { if (decl.value.indexOf(opts.unitToConvert) === -1) return; diff --git a/src/types.ts b/src/types.ts index f7a4c81..eab8bf4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -52,6 +52,10 @@ export type OptionType = { * 媒体查询里的单位是否需要转换单位 */ mediaQuery?: boolean; + /** + * keyframes 里的单位是否需要转换单位 + */ + keyframes?: boolean; /** * 是否直接更换属性值,而不添加备用属性 */ @@ -84,7 +88,7 @@ export type OptionType = { }; -export type ParentExtendType = { prop: string; value: string; params: string }; +export type ParentExtendType = { prop: string; value: string; params: string; name: string; }; export type ParentType = { parent: Rule['parent'] & ParentExtendType; diff --git a/src/utils.ts b/src/utils.ts index 29c0475..544766b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -43,8 +43,4 @@ export const declarationExists = (decls: ParentExtendType[], prop: string, value return decls?.some((decl: ParentExtendType) => { return decl.prop === prop && decl.value === value; }); -}; - -export const validateParams = (params: string, mediaQuery: boolean) => { - return !params || (params && mediaQuery); -}; +}; \ No newline at end of file