UNPKG

rollup-plugin-react-scoped-css

Version:

A rollup plugin designed to allow scoped css to be run in react (Compatible with vite and rollup)

88 lines (87 loc) 3.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.scopeCss = scopeCss; const css_tree_1 = require("css-tree"); const getSelectors = (items) => { const selectorLists = items.reduce((acc, node) => { if (node.type === "Rule" && node?.prelude?.type === "SelectorList") { acc.push(node.prelude.children); } else if (node.type === "Atrule" && node.name === "media") { node.block?.children.forEach((rule) => { if (rule.type === "Atrule" && rule.name === "media") { const selectors = getSelectors(rule.block?.children); acc.push(...selectors); } if (rule.type === "Rule" && rule.prelude.type === "SelectorList") { acc.push(rule.prelude.children); } }); } return acc; }, []); return selectorLists; }; const isScopePiercingPseudoSelector = (item) => { return (item?.data?.type === "PseudoElementSelector" && (item?.data?.name === "v-deep" || item?.data?.name === "deep")); }; const isPseudoSelector = (item) => { return (item?.data?.type === "PseudoClassSelector" || item?.data?.type === "PseudoElementSelector"); }; const isCombinator = (item) => { return item?.data?.type === "Combinator"; }; function scopeCss(css, filename, hash) { try { const ast = (0, css_tree_1.parse)(css); const selectorLists = getSelectors(ast.children); const attributeSelector = { type: "AttributeSelector", name: { type: "Identifier", name: hash }, matcher: null, value: null, flags: null, }; selectorLists.forEach((selectorList) => { selectorList.forEach((selector) => { if (selector.type !== "Selector") { return; } let item = selector.children.head; const itemsToInsertScopeBefore = []; let currentChunkIndex = 0; while (item !== null) { if (isScopePiercingPseudoSelector(item)) { Object.assign(item.data, attributeSelector); break; } else if (isCombinator(item) || isPseudoSelector(item)) { currentChunkIndex += 1; } else if (item.next) { itemsToInsertScopeBefore[currentChunkIndex] = item.next; } else { selector.children.appendData(attributeSelector); break; } item = item?.next ?? null; } // This is true if one of the two break statements above was run. Which means we don't want to add to the last one. if (itemsToInsertScopeBefore[currentChunkIndex]) { itemsToInsertScopeBefore.pop(); } itemsToInsertScopeBefore.forEach((scopePositionItem) => { selector.children.insertData(attributeSelector, scopePositionItem); }); }); }); return (0, css_tree_1.generate)(ast); } catch (e) { console.log(`Failed scoping css of file: ${filename}\n\nError:\n`, e); return css; } }