summaryrefslogtreecommitdiff
path: root/src/compiler/optimize/postcss-scoped-styles/index.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/optimize/postcss-scoped-styles/index.ts')
-rw-r--r--src/compiler/optimize/postcss-scoped-styles/index.ts20
1 files changed, 15 insertions, 5 deletions
diff --git a/src/compiler/optimize/postcss-scoped-styles/index.ts b/src/compiler/optimize/postcss-scoped-styles/index.ts
index 01c0acd94..23350869c 100644
--- a/src/compiler/optimize/postcss-scoped-styles/index.ts
+++ b/src/compiler/optimize/postcss-scoped-styles/index.ts
@@ -1,4 +1,4 @@
-import { Plugin } from 'postcss';
+import { Declaration, Plugin } from 'postcss';
interface AstroScopedOptions {
className: string;
@@ -11,17 +11,24 @@ interface Selector {
}
const CSS_SEPARATORS = new Set([' ', ',', '+', '>', '~']);
+const KEYFRAME_PERCENT = /\d+\.?\d*%/;
/** HTML tags that should never get scoped classes */
export const NEVER_SCOPED_TAGS = new Set<string>(['base', 'body', 'font', 'frame', 'frameset', 'head', 'html', 'link', 'meta', 'noframes', 'noscript', 'script', 'style', 'title']);
/**
- * Scope Selectors
+ * Scope Rules
* Given a selector string (`.btn>span,.nav>span`), add an additional CSS class to every selector (`.btn.myClass>span.myClass,.nav.myClass>span.myClass`)
* @param {string} selector The minified selector string to parse. Cannot contain arbitrary whitespace (other than child selector syntax).
* @param {string} className The CSS class to apply.
*/
-export function scopeSelectors(selector: string, className: string) {
+export function scopeRule(selector: string, className: string) {
+ // if this is a keyframe keyword, return original selector
+ if (selector === 'from' || selector === 'to' || KEYFRAME_PERCENT.test(selector)) {
+ return selector;
+ }
+
+ // For everything else, parse & scope
const c = className.replace(/^\.?/, '.'); // make sure class always has leading '.'
const selectors: Selector[] = [];
let ss = selector; // final output
@@ -30,9 +37,12 @@ export function scopeSelectors(selector: string, className: string) {
{
let start = 0;
let lastValue = '';
+ let parensOpen = false;
for (let n = 0; n < ss.length; n++) {
const isEnd = n === selector.length - 1;
- if (isEnd || CSS_SEPARATORS.has(selector[n])) {
+ if (selector[n] === '(') parensOpen = true;
+ if (selector[n] === ')') parensOpen = false;
+ if (isEnd || (parensOpen === false && CSS_SEPARATORS.has(selector[n]))) {
lastValue = selector.substring(start, isEnd ? undefined : n);
if (!lastValue) continue;
selectors.push({ start, end: isEnd ? n + 1 : n, value: lastValue });
@@ -90,7 +100,7 @@ export default function astroScopedStyles(options: AstroScopedOptions): Plugin {
return {
postcssPlugin: '@astro/postcss-scoped-styles',
Rule(rule) {
- rule.selector = scopeSelectors(rule.selector, options.className);
+ rule.selector = scopeRule(rule.selector, options.className);
},
};
}