@@ -16,10 +16,12 @@ import { compareAtRuleOrMixed } from './sort-style-rules'
1616const isAtRule = ( cond : ConditionDetails ) : boolean => cond . type === 'at-rule'
1717
1818/**
19- * Checks if a condition is a pseudo-element selector (::before, ::after, etc.)
19+ * Matches pseudo-element selectors (::before, ::after, ::placeholder , etc.)
2020 * Pseudo-elements must appear at the end of CSS selector chains per the CSS spec.
2121 */
22- const isPseudoElement = ( cond : ConditionDetails ) : boolean => typeof cond . raw === 'string' && cond . raw . includes ( '::' )
22+ const pseudoElementRegex = / : : [ \w - ] /
23+ const isPseudoElement = ( cond : ConditionDetails ) : boolean =>
24+ typeof cond . raw === 'string' && pseudoElementRegex . test ( cond . raw )
2325
2426/**
2527 * Flattens a condition, extracting parts from mixed conditions.
@@ -201,14 +203,10 @@ export class Conditions {
201203 if ( aIsAtRule && ! bIsAtRule ) return - 1
202204 if ( ! aIsAtRule && bIsAtRule ) return 1
203205
204- // Among non-at-rules: pseudo-elements (::before, ::after, etc.) must come last
205- // CSS requires pseudo-elements at the end of selector chains
206- if ( ! aIsAtRule && ! bIsAtRule ) {
207- const aIsPseudoElement = isPseudoElement ( a . cond )
208- const bIsPseudoElement = isPseudoElement ( b . cond )
209- if ( aIsPseudoElement && ! bIsPseudoElement ) return 1
210- if ( ! aIsPseudoElement && bIsPseudoElement ) return - 1
211- }
206+ // Pseudo-elements (::before, ::after, etc.) must come last per CSS spec
207+ const aIsPseudo = isPseudoElement ( a . cond )
208+ const bIsPseudo = isPseudoElement ( b . cond )
209+ if ( aIsPseudo !== bIsPseudo ) return aIsPseudo ? 1 : - 1
212210
213211 // Within same category, preserve original source order
214212 return a . originalIndex - b . originalIndex
0 commit comments