diff options
Diffstat (limited to 'src/compiler/optimize/postcss-scoped-styles/index.ts')
-rw-r--r-- | src/compiler/optimize/postcss-scoped-styles/index.ts | 20 |
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); }, }; } |