fix(css): scope the subject compound so theme-dark rules keep matching
This commit is contained in:
1 parent
4f485b0bc4
commit
d692dff19a
2 files changed
+36
-5
No files matched your search
+26
-5
@@ -49,11 +49,32 @@ function mentions(selector, name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function scopeSelector(selector) {
|
function scopeSelector(selector) {
|
||||||
if (isPseudo(selector, "root") || isPseudo(selector, "host")) return selector;
|
if (isPseudo(selector, "root") || isPseudo(selector, "host")) {
|
||||||
if (mentions(selector, ROOT)) return selector;
|
return selector;
|
||||||
// `*` has to open a compound, and :is() takes that place now.
|
}
|
||||||
const rest = selector[0]?.type === "universal" ? selector.slice(1) : selector;
|
if (mentions(selector, ROOT)) {
|
||||||
return [SCOPE, ...rest];
|
return selector;
|
||||||
|
}
|
||||||
|
// The scope goes on the subject — the last compound — not the first:
|
||||||
|
// `.theme-dark .hue-chip` must keep matching with `.theme-dark` on body,
|
||||||
|
// outside the root.
|
||||||
|
let at = 0;
|
||||||
|
for (let i = 0; i < selector.length; i += 1) {
|
||||||
|
if (selector[i].type === "combinator") {
|
||||||
|
at = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const head = selector.slice(0, at);
|
||||||
|
const subject = selector.slice(at);
|
||||||
|
// `*` and type selectors must open a compound; :is() goes in their place
|
||||||
|
// or right after them.
|
||||||
|
if (subject[0]?.type === "universal") {
|
||||||
|
return [...head, SCOPE, ...subject.slice(1)];
|
||||||
|
}
|
||||||
|
if (subject[0]?.type === "type") {
|
||||||
|
return [...head, subject[0], SCOPE, ...subject.slice(1)];
|
||||||
|
}
|
||||||
|
return [...head, SCOPE, ...subject];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rewrites a built stylesheet so its rules only reach the plugin's own DOM. */
|
/** Rewrites a built stylesheet so its rules only reach the plugin's own DOM. */
|
||||||
|
|||||||
@@ -46,6 +46,16 @@ describe("scoping the built stylesheet", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("scopes the subject, so an ancestor outside the root still matches", () => {
|
||||||
|
expect(one(".theme-dark .hue-chip{c:1}")).toBe(
|
||||||
|
".theme-dark :is(.bcal-root, .bcal-root *).hue-chip { c: 1; }",
|
||||||
|
);
|
||||||
|
expect(one(".a > button{c:2}")).toBe(
|
||||||
|
".a > button:is(.bcal-root, .bcal-root *) { c: 2; }",
|
||||||
|
);
|
||||||
|
expect(one(".a *{c:3}")).toBe(".a :is(.bcal-root, .bcal-root *) { c: 3; }");
|
||||||
|
});
|
||||||
|
|
||||||
it("leaves rules that already name the root alone", () => {
|
it("leaves rules that already name the root alone", () => {
|
||||||
const reset = ".bcal-root.bcal-root button{cursor:pointer}";
|
const reset = ".bcal-root.bcal-root button{cursor:pointer}";
|
||||||
expect(one(reset)).toBe(".bcal-root.bcal-root button { cursor: pointer; }");
|
expect(one(reset)).toBe(".bcal-root.bcal-root button { cursor: pointer; }");
|
||||||
|
|||||||
Reference in new issue
Block a user