@@ -32,6 +32,7 @@ import { createCssUtility } from './utilities'
3232import { expand } from './utils/brace-expansion'
3333import { escape , unescape } from './utils/escape'
3434import { segment } from './utils/segment'
35+ import { topologicalSort } from './utils/topological-sort'
3536import { compoundsForSelectors , IS_VALID_VARIANT_NAME , substituteAtVariant } from './variants'
3637export type Config = UserConfig
3738
@@ -150,7 +151,8 @@ async function parseCss(
150151
151152 let important = null as boolean | null
152153 let theme = new Theme ( )
153- let customVariants : ( ( designSystem : DesignSystem ) => void ) [ ] = [ ]
154+ let customVariants = new Map < string , ( designSystem : DesignSystem ) => void > ( )
155+ let customVariantDependencies = new Map < string , Set < string > > ( )
154156 let customUtilities : ( ( designSystem : DesignSystem ) => void ) [ ] = [ ]
155157 let firstThemeRule = null as StyleRule | null
156158 let utilitiesNode = null as AtRule | null
@@ -390,7 +392,7 @@ async function parseCss(
390392 }
391393 }
392394
393- customVariants . push ( ( designSystem ) => {
395+ customVariants . set ( name , ( designSystem ) => {
394396 designSystem . variants . static (
395397 name ,
396398 ( r ) => {
@@ -411,6 +413,7 @@ async function parseCss(
411413 } ,
412414 )
413415 } )
416+ customVariantDependencies . set ( name , new Set < string > ( ) )
414417
415418 return
416419 }
@@ -431,9 +434,17 @@ async function parseCss(
431434 // }
432435 // ```
433436 else {
434- customVariants . push ( ( designSystem ) => {
435- designSystem . variants . fromAst ( name , node . nodes )
437+ let dependencies = new Set < string > ( )
438+ walk ( node . nodes , ( child ) => {
439+ if ( child . kind === 'at-rule' && child . name === '@variant' ) {
440+ dependencies . add ( child . params )
441+ }
442+ } )
443+
444+ customVariants . set ( name , ( designSystem ) => {
445+ designSystem . variants . fromAst ( name , node . nodes , designSystem )
436446 } )
447+ customVariantDependencies . set ( name , dependencies )
437448
438449 return
439450 }
@@ -605,8 +616,27 @@ async function parseCss(
605616 sources,
606617 } )
607618
608- for ( let customVariant of customVariants ) {
609- customVariant ( designSystem )
619+ for ( let name of customVariants . keys ( ) ) {
620+ // Pre-register the variant to ensure its position in the variant list is
621+ // based on the order we see them in the CSS.
622+ designSystem . variants . static ( name , ( ) => { } )
623+ }
624+
625+ // Register custom variants in order
626+ for ( let variant of topologicalSort ( customVariantDependencies , {
627+ onCircularDependency ( path , start ) {
628+ let output = toCss (
629+ path . map ( ( name , idx ) => {
630+ return atRule ( '@custom-variant' , name , [ atRule ( '@variant' , path [ idx + 1 ] ?? start , [ ] ) ] )
631+ } ) ,
632+ )
633+ . replaceAll ( ';' , ' { … }' )
634+ . replace ( `@custom-variant ${ start } {` , `@custom-variant ${ start } { /* ← */` )
635+
636+ throw new Error ( `Circular dependency detected in custom variants:\n\n${ output } ` )
637+ } ,
638+ } ) ) {
639+ customVariants . get ( variant ) ?.( designSystem )
610640 }
611641
612642 for ( let customUtility of customUtilities ) {
0 commit comments