diff --git a/src/transformers/globalRule.ts b/src/transformers/globalRule.ts
index 27af4377..3a5b689b 100644
--- a/src/transformers/globalRule.ts
+++ b/src/transformers/globalRule.ts
@@ -1,19 +1,15 @@
import postcss from 'postcss';
import { Transformer } from '../types';
-import { globalifyPlugin } from './globalStyle';
+import { wrapSelectorInGlobal } from './globalStyle';
const globalifyRulePlugin = (root: any) => {
- root.walkAtRules(/^global$/, (atrule: any) => {
- globalifyPlugin(atrule);
- let after = atrule;
-
- atrule.each(function (child: any) {
- after.after(child);
- after = child;
- });
-
- atrule.remove();
+ root.walkRules(/:global(?!\()/, (rule: any) => {
+ const [beginning, ...rest] = rule.selector.split(/:global(?!\()/);
+ rule.selector = (
+ beginning.trim() + ' '
+ + rest.filter((x: string) => !!x).map(wrapSelectorInGlobal).join(' ')
+ ).trim();
});
};
diff --git a/src/transformers/globalStyle.ts b/src/transformers/globalStyle.ts
index 9d03aa2b..fce02330 100644
--- a/src/transformers/globalStyle.ts
+++ b/src/transformers/globalStyle.ts
@@ -2,7 +2,23 @@ import postcss from 'postcss';
import { Transformer } from '../types';
-export const globalifyPlugin = (root: any) => {
+export const wrapSelectorInGlobal = (selector: string) => {
+ return selector
+ .trim()
+ .split(' ')
+ .map((selectorPart) => {
+ if (selectorPart.startsWith(':local')) {
+ return selectorPart.replace(/:local\((.+?)\)/g, '$1');
+ }
+ if (selectorPart.startsWith(':global')) {
+ return selectorPart;
+ }
+ return `:global(${selectorPart})`;
+ })
+ .join(' ');
+};
+
+const globalifyPlugin = (root: any) => {
root.walkAtRules(/keyframes$/, (atrule: any) => {
if (!atrule.params.startsWith('-global-')) {
atrule.params = '-global-' + atrule.params;
@@ -14,20 +30,7 @@ export const globalifyPlugin = (root: any) => {
return;
}
- rule.selectors = rule.selectors.map((selector: string) => {
- return selector
- .split(' ')
- .map((selectorPart) => {
- if (selectorPart.startsWith(':local')) {
- return selectorPart.replace(/:local\((.+?)\)/g, '$1');
- }
- if (selectorPart.startsWith(':global')) {
- return selectorPart;
- }
- return `:global(${selectorPart})`;
- })
- .join(' ');
- });
+ rule.selectors = rule.selectors.map(wrapSelectorInGlobal);
});
};
diff --git a/test/transformers/globalRule.test.ts b/test/transformers/globalRule.test.ts
index aa21fe5b..e0f63ae4 100644
--- a/test/transformers/globalRule.test.ts
+++ b/test/transformers/globalRule.test.ts
@@ -3,7 +3,7 @@ import { preprocess } from '../utils';
describe('transformer - globalRule', () => {
it('wraps selector in :global(...) modifier', async () => {
- const template = ``;
+ const template = ``;
const opts = autoProcess();
const preprocessed = await preprocess(template, opts);
expect(preprocessed.toString()).toContain(
@@ -11,32 +11,70 @@ describe('transformer - globalRule', () => {
);
});
- it('wraps selector in :global(...) modifier only inside the rule', async () => {
- const template = ``;
+ it('wraps selector in :global(...) only if needed', async () => {
+ const template = ``;
const opts = autoProcess();
const preprocessed = await preprocess(template, opts);
expect(preprocessed.toString()).toContain(
- `:global(div){color:red}.test{}`,
+ `:global(.test){}:global(.foo){}`,
);
});
- it('wraps selector in :global(...) only if needed', async () => {
- const template = ``;
+ it('wraps selector in :global(...) on multiple levels', async () => {
+ const template = '';
const opts = autoProcess();
const preprocessed = await preprocess(template, opts);
- expect(preprocessed.toString()).toContain(
- `:global(.test){}:global(.foo){}`,
+ expect(preprocessed.toString()).toMatch(
+ // either be :global(div .cls){}
+ // or :global(div) :global(.cls){}
+ /(:global\(div .cls\)\{\}|:global\(div\) :global\(\.cls\)\{\})/,
);
});
- it("prefixes @keyframes names with '-global-' only if needed", async () => {
- const template = ``;
+ it('wraps selector in :global(...) on multiple levels when in the middle', async () => {
+ const template = '';
const opts = autoProcess();
const preprocessed = await preprocess(template, opts);
- expect(preprocessed.toString()).toContain(
- `@keyframes -global-a {from{} to{}}@keyframes -global-b {from{} to{}}`,
+ expect(preprocessed.toString()).toMatch(
+ // either be div :global(span .cls) {}
+ // or div :global(span) :global(.cls) {}
+ /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/,
+ );
+ });
+
+ it('does not break when at the end', async () => {
+ const template = '';
+ const opts = autoProcess();
+ const preprocessed = await preprocess(template, opts);
+ expect(preprocessed.toString()).toContain('span{}');
+ });
+
+ it('works with collapsed nesting several times', async () => {
+ const template = '';
+ const opts = autoProcess();
+ const preprocessed = await preprocess(template, opts);
+ expect(preprocessed.toString()).toMatch(
+ // either be div :global(span .cls) {}
+ // or div :global(span) :global(.cls) {}
+ /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/,
+ );
+ });
+
+ it('does not interfere with the :global(...) syntax', async () => {
+ const template = '';
+ const opts = autoProcess();
+ const preprocessed = await preprocess(template, opts);
+ expect(preprocessed.toString()).toContain('div :global(span){}');
+ });
+
+ it('allows mixing with the :global(...) syntax', async () => {
+ const template = '';
+ const opts = autoProcess();
+ const preprocessed = await preprocess(template, opts);
+ expect(preprocessed.toString()).toMatch(
+ // either be div :global(span .cls) {}
+ // or div :global(span) :global(.cls) {}
+ /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/,
);
});
});