Skip to content
25 changes: 21 additions & 4 deletions packages/helpers/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@ export class CSSHelp {
this.doc = doc;
}

private selectorHasUniversal(selector: string): boolean {
return /(^|\s|\+|>|~)\*/.test(selector);
}

private _getStyleRules() {
const styleSheet = this.getStyleSheet();
return this.styleSheetToCssRulesArray(styleSheet).filter(
Expand All @@ -486,10 +490,23 @@ export class CSSHelp {
}

getStyle(selector: string): ExtendedStyleDeclaration | null {
const style = this._getStyleRules().find(
(ele) => ele?.selectorText === selector,
)?.style as ExtendedStyleDeclaration | undefined;
if (!style) return null;
const wantsUniversal = this.selectorHasUniversal(selector);

const rule = this._getStyleRules().find((ele) => {
if (!ele?.selectorText) return false;

const ruleHasUniversal = this.selectorHasUniversal(ele.selectorText);

// Block universal selector leakage
if (ruleHasUniversal && !wantsUniversal) return false;

return ele.selectorText === selector;
});

if (!rule) return null;

const style = rule.style as ExtendedStyleDeclaration;

style.getPropVal = (prop: string, strip = false) =>
strip
? style.getPropertyValue(prop).replace(/\s+/g, "")
Expand Down
12 changes: 12 additions & 0 deletions packages/tests/__fixtures__/curriculum-helper-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,18 @@ body {
.card:hover {
background-color: khaki;
}

`;
export const cssWithUniversal = `
span[class~="one"] *:first-of-type {
border-color: #d61;
}
`;

export const cssWithoutUniversal = `
span[class~="one"] > p:first-of-type {
color: red;
}
`;

const testValues = {
Expand Down
55 changes: 54 additions & 1 deletion packages/tests/css-helper.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// @vitest-environment jsdom
import { cssString } from "./__fixtures__/curriculum-helper-css";
import {
cssString,
cssWithUniversal,
cssWithoutUniversal,
} from "./__fixtures__/curriculum-helper-css";
import { CSSHelp } from "./../helpers/lib/index";

describe("css-help", () => {
Expand Down Expand Up @@ -142,3 +146,52 @@ describe("css-help", () => {
document.head.innerHTML = "";
});
});
describe("CSSHelp – universal selector handling", () => {
afterEach(() => {
document.head.innerHTML = "";
});

function injectStyle(css: string) {
const styleEl = document.createElement("style");
styleEl.textContent = css;
document.head.appendChild(styleEl);
}

it("want universal selector, universal selector in css", () => {
injectStyle(cssWithUniversal);

const cssHelp = new CSSHelp(document);
const style = cssHelp.getStyle('span[class~="one"] *:first-of-type');

expect(style).not.toBeNull();
expect(style?.getPropVal("border-color")).toBe("#d61");
});

it("want universal selector, universal selector not in css", () => {
injectStyle(cssWithoutUniversal);

const cssHelp = new CSSHelp(document);
const style = cssHelp.getStyle('span[class~="one"] *:first-of-type');

expect(style).toBeNull();
});

it("don't want universal selector, universal selector in css", () => {
injectStyle(cssWithUniversal);

const cssHelp = new CSSHelp(document);
const style = cssHelp.getStyle('span[class~="one"] > p:first-of-type');

expect(style).toBeNull();
});

it("don't want universal selector, universal selector not in css", () => {
injectStyle(cssWithoutUniversal);

const cssHelp = new CSSHelp(document);
const style = cssHelp.getStyle('span[class~="one"] > p:first-of-type');

expect(style).not.toBeNull();
expect(style?.getPropVal("color")).toBe("red");
});
});
2 changes: 2 additions & 0 deletions packages/tests/curriculum-helper.test.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes to this file are only some empty lines added, please revert

Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import React from "react";
import ReactDOM from "react-dom/client";

import cssTestValues from "./__fixtures__/curriculum-helper-css";

import htmlTestValues from "./__fixtures__/curriculum-helpers-html";
import jsTestValues from "./__fixtures__/curriculum-helpers-javascript";
import whiteSpaceTestValues from "./__fixtures__/curriculum-helpers-remove-white-space";

import * as helper from "./../helpers/lib/index";

const { stringWithWhiteSpaceChars, stringWithWhiteSpaceCharsRemoved } =
Expand Down