You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.8 KiB
98 lines
3.8 KiB
'use strict'; |
|
|
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } |
|
|
|
var postcss = _interopDefault(require('postcss')); |
|
var selectorParser = _interopDefault(require('postcss-selector-parser')); |
|
|
|
var index = postcss.plugin('postcss-dir-pseudo-class', opts => { |
|
const dir = Object(opts).dir; |
|
const preserve = Boolean(Object(opts).preserve); |
|
return root => { |
|
// walk rules using the :dir pseudo-class |
|
root.walkRules(/:dir\([^\)]*\)/, rule => { |
|
let currentRule = rule; // conditionally preserve the original rule |
|
|
|
if (preserve) { |
|
currentRule = rule.cloneBefore(); |
|
} // update the rule selector |
|
|
|
|
|
currentRule.selector = selectorParser(selectors => { |
|
// for each (comma separated) selector |
|
selectors.nodes.forEach(selector => { |
|
// walk all selector nodes that are :dir pseudo-classes |
|
selector.walk(node => { |
|
if ('pseudo' === node.type && ':dir' === node.value) { |
|
// previous and next selector nodes |
|
const prev = node.prev(); |
|
const next = node.next(); |
|
const prevIsSpaceCombinator = prev && prev.type && 'combinator' === prev.type && ' ' === prev.value; |
|
const nextIsSpaceCombinator = next && next.type && 'combinator' === next.type && ' ' === next.value; // preserve the selector tree |
|
|
|
if (prevIsSpaceCombinator && (nextIsSpaceCombinator || !next)) { |
|
node.replaceWith(selectorParser.universal()); |
|
} else { |
|
node.remove(); |
|
} // conditionally prepend a combinator before inserting the [dir] attribute |
|
|
|
|
|
const first = selector.nodes[0]; |
|
const firstIsSpaceCombinator = first && 'combinator' === first.type && ' ' === first.value; |
|
const firstIsHtml = first && 'tag' === first.type && 'html' === first.value; |
|
const firstIsRoot = first && 'pseudo' === first.type && ':root' === first.value; |
|
|
|
if (first && !firstIsHtml && !firstIsRoot && !firstIsSpaceCombinator) { |
|
selector.prepend(selectorParser.combinator({ |
|
value: ' ' |
|
})); |
|
} // value of the :dir pseudo-class |
|
|
|
|
|
const value = node.nodes.toString(); // whether :dir matches the presumed direction |
|
|
|
const isdir = dir === value; // [dir] attribute |
|
|
|
const dirAttr = selectorParser.attribute({ |
|
attribute: 'dir', |
|
operator: '=', |
|
quoteMark: '"', |
|
value: `"${value}"` |
|
}); // not[dir] attribute |
|
|
|
const notDirAttr = selectorParser.pseudo({ |
|
value: `${firstIsHtml || firstIsRoot ? '' : 'html'}:not` |
|
}); |
|
notDirAttr.append(selectorParser.attribute({ |
|
attribute: 'dir', |
|
operator: '=', |
|
quoteMark: '"', |
|
value: `"${'ltr' === value ? 'rtl' : 'ltr'}"` |
|
})); |
|
|
|
if (isdir) { |
|
// if the direction is presumed |
|
if (firstIsHtml) { |
|
// insert :root after html tag |
|
selector.insertAfter(first, notDirAttr); |
|
} else { |
|
// prepend :root |
|
selector.prepend(notDirAttr); |
|
} |
|
} else if (firstIsHtml) { |
|
// otherwise, insert dir attribute after html tag |
|
selector.insertAfter(first, dirAttr); |
|
} else { |
|
// otherwise, prepend the dir attribute |
|
selector.prepend(dirAttr); |
|
} |
|
} |
|
}); |
|
}); |
|
}).processSync(currentRule.selector); |
|
}); |
|
}; |
|
}); |
|
|
|
module.exports = index; |
|
//# sourceMappingURL=index.cjs.js.map
|
|
|