Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1979,6 +1979,7 @@ describe('@stylexjs/babel-plugin', () => {
`);
});

// Generates invalid CSS, need to revisit this API
test('"::before" containing pseudo-classes', () => {
const { code, metadata } = transform(`
import * as stylex from '@stylexjs/stylex';
Expand Down Expand Up @@ -2025,6 +2026,78 @@ describe('@stylexjs/babel-plugin', () => {
}
`);
});

test('legacy compound ":hover::after" selector as single key', () => {
const { code, metadata } = transform(`
import * as stylex from '@stylexjs/stylex';
export const styles = stylex.create({
foo: {
':hover::after': {
color: 'red',
},
},
});
`);
expect(code).toMatchInlineSnapshot(`
"import * as stylex from '@stylexjs/stylex';
export const styles = {
foo: {
kF1atM: "x1gfyp89",
$$css: true
}
};"
`);
expect(metadata).toMatchInlineSnapshot(`
{
"stylex": [
[
"x1gfyp89",
{
"ltr": ".x1gfyp89:hover::after{color:red}",
"rtl": null,
},
8130,
],
],
}
`);
});

test('compound ":hover::after" selector as single key', () => {
const { metadata } = transform(`
import * as stylex from '@stylexjs/stylex';
export const styles = stylex.create({
foo: {
color: {
default: 'red',
':hover::after': 'blue',
},
},
});
`);
expect(metadata).toMatchInlineSnapshot(`
{
"stylex": [
[
"x1e2nbdu",
{
"ltr": ".x1e2nbdu{color:red}",
"rtl": null,
},
3000,
],
[
"x6wc952",
{
"ltr": ".x6wc952:hover::after{color:blue}",
"rtl": null,
},
8130,
],
],
}
`);
});
});

describe('object values: queries', () => {
Expand Down
44 changes: 16 additions & 28 deletions packages/@stylexjs/shared/src/utils/property-priorities.js
Original file line number Diff line number Diff line change
Expand Up @@ -734,26 +734,22 @@ const RELATIONAL_SELECTORS = {
/^:where\(\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\s+~\s+\*,\s+:has\(~\s\.[0-9a-zA-Z_-]+(:[a-zA-Z-]+)\)\)$/,
};

// Matches pseudo-elements (::after) and pseudo-classes (:hover, :nth-child(2))
const PSEUDO_PART_REGEX = /::[a-zA-Z-]+|:[a-zA-Z-]+(?:\([^)]*\))?/g;

// Calculate priority for compound pseudo selectors like :hover::after
// We only handle chains of simple pseudo-classes and pseudo-elements and opt out of functional pseudo-classes
function getCompoundPseudoPriority(key: string): number | void {
const pseudoParts = key.match(PSEUDO_PART_REGEX);
if (pseudoParts && pseudoParts.length > 1) {
let total = 0;
for (const part of pseudoParts) {
if (part.startsWith('::')) {
total += PSEUDO_ELEMENT_PRIORITY;
} else {
const prop = part.includes('(')
? part.slice(0, part.indexOf('('))
: part;
total += PSEUDO_CLASS_PRIORITIES[prop] ?? 40;
}
}
return total;
const parts = key.match(PSEUDO_PART_REGEX);
if (!parts || parts.length <= 1 || parts.some((p) => p.includes('('))) return;

let total = 0;

for (const part of parts) {
total += part.startsWith('::')
? PSEUDO_ELEMENT_PRIORITY
: (PSEUDO_CLASS_PRIORITIES[part] ?? 40);
}

return total;
}

export function getAtRulePriority(key: string): number | void {
Expand All @@ -776,10 +772,6 @@ export function getAtRulePriority(key: string): number | void {

export function getPseudoElementPriority(key: string): number | void {
if (key.startsWith('::')) {
const compoundPriority = getCompoundPseudoPriority(key);
if (compoundPriority != null) {
return compoundPriority;
}
return PSEUDO_ELEMENT_PRIORITY;
}
}
Expand Down Expand Up @@ -816,14 +808,7 @@ export function getPseudoClassPriority(key: string): number | void {
}

if (key.startsWith(':')) {
const compoundPriority = getCompoundPseudoPriority(key);
if (compoundPriority != null) {
return compoundPriority;
}

const prop = key.includes('(')
? key.slice(0, key.indexOf('('))
: key;
const prop = key.split('(')[0];

return PSEUDO_CLASS_PRIORITIES[prop] ?? 40;
}
Expand All @@ -848,6 +833,9 @@ export default function getPriority(key: string): number {
const atRulePriority = getAtRulePriority(key);
if (atRulePriority) return atRulePriority;

const compoundPriority = getCompoundPseudoPriority(key);
if (compoundPriority != null) return compoundPriority;

const pseudoElementPriority = getPseudoElementPriority(key);
if (pseudoElementPriority) return pseudoElementPriority;

Expand Down