postcss-px-to-viewport-8-media-screen
Version:
204 lines (200 loc) • 7.54 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _pixelUnitRegexp = require("./pixel-unit-regexp");
var _propListMatcher = require("./prop-list-matcher");
var _utils = require("./utils");
var _objectAssign = _interopRequireDefault(require("object-assign"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const 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,
mediaScreen: [],
replace: true,
landscape: false,
landscapeUnit: 'vw',
landscapeWidth: 568
};
const mediaOptionDefault = {
screen: '',
viewportWidth: 320,
viewportUnit: 'vw',
unitToConvert: 'px'
};
const ignoreNextComment = 'px-to-viewport-ignore-next';
const ignorePrevComment = 'px-to-viewport-ignore';
const postcssPxToViewport = options => {
const opts = (0, _objectAssign.default)({}, defaults, options);
const pxRegex = (0, _pixelUnitRegexp.getUnitRegexp)(opts.unitToConvert);
const satisfyPropList = (0, _propListMatcher.createPropListMatcher)(opts.propList);
const landscapeRules = [];
return {
postcssPlugin: 'postcss-px-to-viewport',
Once(css, {
result
}) {
// @ts-ignore 补充类型
css.walkRules(rule => {
// Add exclude option to ignore some files like 'node_modules'
const file = rule.source?.input.file || '';
const isAtRule = rule.parent?.params;
if (opts.exclude && file) {
if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') {
if ((0, _utils.isExclude)(opts.exclude, file)) return;
} else if (
// Object.prototype.toString.call(opts.exclude) === '[object Array]' &&
opts.exclude instanceof Array) {
for (let i = 0; i < opts.exclude.length; i++) {
if ((0, _utils.isExclude)(opts.exclude[i], file)) return;
}
} else {
throw new Error('options.exclude should be RegExp or Array.');
}
}
if ((0, _utils.blacklistedSelector)(opts.selectorBlackList, rule.selector)) return;
if (opts.landscape && !rule.parent?.params) {
const landscapeRule = rule.clone().removeAll();
rule.walkDecls(decl => {
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
if (!satisfyPropList(decl.prop)) return;
let landscapeWidth;
if (typeof opts.landscapeWidth === 'function') {
const num = opts.landscapeWidth(file);
if (!num) return;
landscapeWidth = num;
} else {
landscapeWidth = opts.landscapeWidth;
}
landscapeRule.append(decl.clone({
value: decl.value.replace(pxRegex, (0, _utils.createPxReplace)(opts, opts.landscapeUnit, landscapeWidth))
}));
});
if (landscapeRule.nodes.length > 0) {
landscapeRules.push(landscapeRule);
}
}
const transformDecls = opts => {
rule.walkDecls((decl, i) => {
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
if (!satisfyPropList(decl.prop)) return;
const 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;
}
const 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;
}
}
let unit;
let size;
const {
params
} = rule.parent;
if (opts.landscape && params && params.indexOf('landscape') !== -1) {
unit = opts.landscapeUnit;
if (typeof opts.landscapeWidth === 'function') {
const num = opts.landscapeWidth(file);
if (!num) return;
size = num;
} else {
size = opts.landscapeWidth;
}
} else {
unit = (0, _utils.getUnit)(decl.prop, opts);
if (typeof opts.viewportWidth === 'function') {
const num = opts.viewportWidth(file);
if (!num) return;
size = num;
} else {
size = opts.viewportWidth;
}
}
const value = decl.value.replace(pxRegex, (0, _utils.createPxReplace)(opts, unit, size));
if ((0, _utils.declarationExists)(decl.parent, decl.prop, value)) return;
if (opts.replace) {
decl.value = value;
} else {
decl.parent?.insertAfter(i, decl.clone({
value
}));
}
});
};
if (Array.isArray(opts.mediaScreen) && opts.mediaScreen.length > 0 && rule.parent?.params) {
opts.mediaScreen.forEach(option => {
if ((0, _utils.validateScreen)(option.screen, rule.parent?.params)) {
const mediaOption = {
...mediaOptionDefault,
...option
};
transformDecls({
...opts,
...mediaOption
});
}
});
}
if (!(0, _utils.validateParams)(rule.parent?.params, opts.mediaQuery)) return;
transformDecls(opts);
});
// if (landscapeRules.length > 0) {
// const landscapeRoot = new AtRule({
// params: '(orientation: landscape)',
// name: 'media',
// });
// landscapeRules.forEach((rule) => {
// landscapeRoot.append(rule);
// });
// css.append(landscapeRoot);
// }
},
// https://www.postcss.com.cn/docs/writing-a-postcss-plugin
// Declaration Rule RuleExit OnceExit
// There two types or listeners: enter and exit.
// Once, Root, AtRule, and Rule will be called before processing children.
// OnceExit, RootExit, AtRuleExit, and RuleExit after processing all children inside node.
OnceExit(css, {
AtRule
}) {
// 在 Once里跑这段逻辑,设置横屏时,打包后到生产环境竖屏样式会覆盖横屏样式,所以 OnceExit再执行。
if (landscapeRules.length > 0) {
const landscapeRoot = new AtRule({
params: '(orientation: landscape)',
name: 'media'
});
landscapeRules.forEach(function (rule) {
landscapeRoot.append(rule);
});
css.append(landscapeRoot);
}
}
};
};
postcssPxToViewport.postcss = true;
module.exports = postcssPxToViewport;
var _default = postcssPxToViewport;
exports.default = _default;
;