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: 增加 keyframes 配置 #39

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
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 |

## 补充说明

Expand Down Expand Up @@ -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;
Expand All @@ -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,那将只有匹配到的文件才会被转换
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
151 changes: 49 additions & 102 deletions spec/px-to-viewport.spec.ts → spec/px-to-viewport.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -293,21 +315,17 @@ 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);
});
});

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\//,
Expand Down Expand Up @@ -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\//,
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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);
});
Expand Down Expand Up @@ -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;

Expand Down
11 changes: 9 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
declarationExists,
getUnit,
isExclude,
validateParams,
} from './utils';
import objectAssign from 'object-assign';

Expand All @@ -25,6 +24,7 @@ const defaults: Required<Omit<OptionType, 'exclude' | 'include'>> = {
propList: ['*'],
minPixelValue: 1,
mediaQuery: false,
keyframes: false,
replace: true,
landscape: false,
landscapeUnit: 'vw',
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export type OptionType = {
* 媒体查询里的单位是否需要转换单位
*/
mediaQuery?: boolean;
/**
* keyframes 里的单位是否需要转换单位
*/
keyframes?: boolean;
/**
* 是否直接更换属性值,而不添加备用属性
*/
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 1 addition & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
};