postcss-logical-properties-polyfill
Version:
PostCSS plugin that polyfill W3C's CSS proposal to support logical properties and values
86 lines (85 loc) • 3.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const transformers_1 = require("./transformers");
const defaultBuildSelector = (selector, writingMode, direction) => {
let prefix = `html[dir="${direction}"]`;
if (writingMode !== 'horizontal-tb') {
prefix += ` .writing-mode-${writingMode}`;
}
return `${prefix} ${selector}`;
};
function normalizeOptions(options) {
// @ts-ignore
return options.map((mode) => {
if (Array.isArray(mode)) {
return mode;
}
return ['horizontal-tb', mode];
});
}
function generatePolyfills(decls, writingMode, direction) {
const newDecls = [];
decls.forEach((decl) => {
const newDecl = transformers_1.transformToNonLogical(decl, writingMode, direction);
if (!newDecl) {
return;
}
if (Array.isArray(newDecl)) {
newDecls.push(...newDecl);
}
else {
newDecls.push(newDecl);
}
});
return newDecls;
}
const plugin = ({ buildSelector = defaultBuildSelector, modes = [
['horizontal-tb', 'rtl'],
['horizontal-tb', 'ltr'],
], preserve = true, } = {}) => ({
// Force type since by an unknown reason it doesn't inherited from the function's generic
postcssPlugin: 'postcss-logical-properties-polyfill',
Root(root) {
modes = normalizeOptions(modes);
const rulesToProcess = new Map();
root.walkDecls((decl) => {
if (!transformers_1.isSupportedProp(decl.prop)) {
return;
}
const parent = decl.parent;
if (!parent || parent.type !== 'rule') {
return;
}
// Skip LESS namespaces and mixins, since they must have different behavior
if (parent.selector.match(/\((\s*|\s*[@].*)\)/)) {
return;
}
if (rulesToProcess.has(parent)) {
rulesToProcess.get(parent).push(decl);
}
else {
rulesToProcess.set(parent, [decl]);
}
});
for (const [rule, decls] of rulesToProcess) {
for (const [writingMode, direction] of modes) {
const declsForDirection = generatePolyfills(decls, writingMode, direction);
if (declsForDirection.length === 0) {
continue;
}
const newRule = rule.clone().removeAll();
newRule.selectors = rule.selectors.map((selector) => buildSelector(selector, writingMode, direction));
newRule.append(declsForDirection);
if (!newRule.raws.before.startsWith('\n\n')) {
newRule.raws.before = '\n\n' + newRule.raws.before;
}
rule.after(newRule);
}
if (!preserve) {
decls.forEach((decl) => decl.remove());
}
}
},
});
plugin.postcss = true;
exports.default = plugin;