Skip to content

Commit d6d976c

Browse files
committed
build(scripts): extract postcssScopedStyles plugin
1 parent 2c29a64 commit d6d976c

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { Plugin } from "postcss";
2+
3+
/**
4+
* Scopes CSS selectors to a given module name.
5+
*
6+
* @example
7+
* ```css
8+
* .moduleName p { color: red; }
9+
* .moduleName div { background: blue; }
10+
* ```
11+
*/
12+
export const postcssScopedStyles = (moduleName: string): Plugin => {
13+
return {
14+
postcssPlugin: "postcss-plugin:scoped-styles",
15+
Once(root) {
16+
root.walkRules((rule) => {
17+
rule.selectors = rule.selectors.map((selector) => {
18+
if (/^pre /.test(selector)) {
19+
selector = `pre.${moduleName}${selector.replace(/^pre /, " ")}`;
20+
} else {
21+
selector = `.${moduleName} ${selector}`;
22+
}
23+
return selector;
24+
});
25+
});
26+
},
27+
};
28+
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { describe, expect, it } from "bun:test";
2+
import postcss from "postcss";
3+
import { postcssScopedStyles } from "../scripts/utils/postcss-scoped-styles";
4+
5+
describe("postcssScopedStyles", () => {
6+
const process = (css: string) => {
7+
return postcss([postcssScopedStyles("moduleName")]).process(css).css;
8+
};
9+
10+
it("should scope regular CSS selectors", async () => {
11+
const input = `
12+
p { color: red; }
13+
div { background: blue; }
14+
`;
15+
const expected = `
16+
.moduleName p { color: red; }
17+
.moduleName div { background: blue; }
18+
`;
19+
expect(process(input)).toBe(expected);
20+
});
21+
22+
it("should handle pre selectors", async () => {
23+
const input = `
24+
pre .className { color: red; }
25+
pre.someClass { background: blue; }
26+
pre { padding: 1em; }
27+
`;
28+
const expected = `
29+
pre.moduleName .className { color: red; }
30+
.moduleName pre.someClass { background: blue; }
31+
.moduleName pre { padding: 1em; }
32+
`;
33+
expect(process(input)).toBe(expected);
34+
});
35+
36+
it("should handle complex selectors", async () => {
37+
const input = `
38+
div > p { color: red; }
39+
.class1 .class2 { background: blue; }
40+
#id1 span { padding: 1em; }
41+
`;
42+
const expected = `
43+
.moduleName div > p { color: red; }
44+
.moduleName .class1 .class2 { background: blue; }
45+
.moduleName #id1 span { padding: 1em; }
46+
`;
47+
expect(process(input)).toBe(expected);
48+
});
49+
});

0 commit comments

Comments
 (0)