@@ -266,10 +266,8 @@ export function optimizeAst(
266266) {
267267 let atRoots : AstNode [ ] = [ ]
268268 let seenAtProperties = new Set < string > ( )
269- let cssThemeVariables = new DefaultMap <
270- Extract < AstNode , { nodes : AstNode [ ] } > [ 'nodes' ] ,
271- Set < Declaration >
272- > ( ( ) => new Set ( ) )
269+ let cssThemeVariables = new DefaultMap < AstNode [ ] , Set < Declaration > > ( ( ) => new Set ( ) )
270+ let colorMixDeclarations = new DefaultMap < AstNode [ ] , Set < Declaration > > ( ( ) => new Set ( ) )
273271 let keyframes = new Set < AtRule > ( )
274272 let usedKeyframeNames = new Set ( )
275273
@@ -280,7 +278,7 @@ export function optimizeAst(
280278
281279 function transform (
282280 node : AstNode ,
283- parent : Extract < AstNode , { nodes : AstNode [ ] } > [ 'nodes' ] ,
281+ parent : AstNode [ ] ,
284282 context : Record < string , string | boolean > = { } ,
285283 depth = 0 ,
286284 ) {
@@ -326,71 +324,7 @@ export function optimizeAst(
326324 // Create fallback values for usages of the `color-mix(…)` function that reference variables
327325 // found in the theme config.
328326 if ( polyfills & Polyfills . ColorMix && node . value . includes ( 'color-mix(' ) ) {
329- let ast = ValueParser . parse ( node . value )
330-
331- let requiresPolyfill = false
332- ValueParser . walk ( ast , ( node , { replaceWith } ) => {
333- if ( node . kind !== 'function' || node . value !== 'color-mix' ) return
334-
335- let containsUnresolvableVars = false
336- let containsCurrentcolor = false
337- ValueParser . walk ( node . nodes , ( node , { replaceWith } ) => {
338- if ( node . kind == 'word' && node . value . toLowerCase ( ) === 'currentcolor' ) {
339- containsCurrentcolor = true
340- requiresPolyfill = true
341- return
342- }
343- if ( node . kind !== 'function' || node . value !== 'var' ) return
344- let firstChild = node . nodes [ 0 ]
345- if ( ! firstChild || firstChild . kind !== 'word' ) return
346-
347- requiresPolyfill = true
348-
349- let inlinedColor = designSystem . theme . resolveValue ( null , [ firstChild . value as any ] )
350- if ( ! inlinedColor ) {
351- containsUnresolvableVars = true
352- return
353- }
354-
355- replaceWith ( { kind : 'word' , value : inlinedColor } )
356- } )
357-
358- if ( containsUnresolvableVars || containsCurrentcolor ) {
359- let separatorIndex = node . nodes . findIndex (
360- ( node ) => node . kind === 'separator' && node . value . trim ( ) . includes ( ',' ) ,
361- )
362- if ( separatorIndex === - 1 ) return
363- let firstColorValue =
364- node . nodes . length > separatorIndex ? node . nodes [ separatorIndex + 1 ] : null
365- if ( ! firstColorValue ) return
366- replaceWith ( firstColorValue )
367- } else if ( requiresPolyfill ) {
368- // Change the colorspace to `srgb` since the fallback values should not be represented as
369- // `oklab(…)` functions again as their support in Safari <16 is very limited.
370- let colorspace = node . nodes [ 2 ]
371- if (
372- colorspace . kind === 'word' &&
373- ( colorspace . value === 'oklab' ||
374- colorspace . value === 'oklch' ||
375- colorspace . value === 'lab' ||
376- colorspace . value === 'lch' )
377- ) {
378- colorspace . value = 'srgb'
379- }
380- }
381- } )
382-
383- if ( requiresPolyfill ) {
384- let fallback = {
385- ...node ,
386- value : ValueParser . toCss ( ast ) ,
387- }
388- let colorMixQuery = rule ( '@supports (color: color-mix(in lab, red, red))' , [ node ] )
389-
390- parent . push ( fallback , colorMixQuery )
391-
392- return
393- }
327+ colorMixDeclarations . get ( parent ) . add ( node )
394328 }
395329
396330 parent . push ( node )
@@ -595,6 +529,74 @@ export function optimizeAst(
595529 newAst = newAst . concat ( atRoots )
596530
597531 // Fallbacks
532+ // Create fallback values for usages of the `color-mix(…)` function that reference variables
533+ // found in the theme config.
534+ if ( polyfills & Polyfills . ColorMix ) {
535+ for ( let [ parent , declarations ] of colorMixDeclarations ) {
536+ for ( let declaration of declarations ) {
537+ let idx = parent . indexOf ( declaration )
538+ // If the declaration is no longer present, we don't need to create a polyfill anymore
539+ if ( idx === - 1 || declaration . value == null ) continue
540+
541+ let ast = ValueParser . parse ( declaration . value )
542+ let requiresPolyfill = false
543+ ValueParser . walk ( ast , ( node , { replaceWith } ) => {
544+ if ( node . kind !== 'function' || node . value !== 'color-mix' ) return
545+ let containsUnresolvableVars = false
546+ let containsCurrentcolor = false
547+ ValueParser . walk ( node . nodes , ( node , { replaceWith } ) => {
548+ if ( node . kind == 'word' && node . value . toLowerCase ( ) === 'currentcolor' ) {
549+ containsCurrentcolor = true
550+ requiresPolyfill = true
551+ return
552+ }
553+ if ( node . kind !== 'function' || node . value !== 'var' ) return
554+ let firstChild = node . nodes [ 0 ]
555+ if ( ! firstChild || firstChild . kind !== 'word' ) return
556+ requiresPolyfill = true
557+ let inlinedColor = designSystem . theme . resolveValue ( null , [ firstChild . value as any ] )
558+ if ( ! inlinedColor ) {
559+ containsUnresolvableVars = true
560+ return
561+ }
562+ replaceWith ( { kind : 'word' , value : inlinedColor } )
563+ } )
564+ if ( containsUnresolvableVars || containsCurrentcolor ) {
565+ let separatorIndex = node . nodes . findIndex (
566+ ( node ) => node . kind === 'separator' && node . value . trim ( ) . includes ( ',' ) ,
567+ )
568+ if ( separatorIndex === - 1 ) return
569+ let firstColorValue =
570+ node . nodes . length > separatorIndex ? node . nodes [ separatorIndex + 1 ] : null
571+ if ( ! firstColorValue ) return
572+ replaceWith ( firstColorValue )
573+ } else if ( requiresPolyfill ) {
574+ // Change the colorspace to `srgb` since the fallback values should not be represented as
575+ // `oklab(…)` functions again as their support in Safari <16 is very limited.
576+ let colorspace = node . nodes [ 2 ]
577+ if (
578+ colorspace . kind === 'word' &&
579+ ( colorspace . value === 'oklab' ||
580+ colorspace . value === 'oklch' ||
581+ colorspace . value === 'lab' ||
582+ colorspace . value === 'lch' )
583+ ) {
584+ colorspace . value = 'srgb'
585+ }
586+ }
587+ } )
588+ if ( ! requiresPolyfill ) continue
589+
590+ let fallback = {
591+ ...declaration ,
592+ value : ValueParser . toCss ( ast ) ,
593+ }
594+ let colorMixQuery = rule ( '@supports (color: color-mix(in lab, red, red))' , [ declaration ] )
595+ parent . splice ( idx , 1 , fallback , colorMixQuery )
596+ }
597+ }
598+ }
599+
598600 if ( polyfills & Polyfills . AtProperty ) {
599601 let fallbackAst = [ ]
600602
0 commit comments