@@ -270,6 +270,10 @@ export function optimizeAst(
270270 Extract < AstNode , { nodes : AstNode [ ] } > [ 'nodes' ] ,
271271 Set < Declaration >
272272 > ( ( ) => new Set ( ) )
273+ let colorMixDeclarations = new DefaultMap <
274+ Extract < AstNode , { nodes : AstNode [ ] } > [ 'nodes' ] ,
275+ Set < Declaration >
276+ > ( ( ) => new Set ( ) )
273277 let keyframes = new Set < AtRule > ( )
274278 let usedKeyframeNames = new Set ( )
275279
@@ -326,71 +330,7 @@ export function optimizeAst(
326330 // Create fallback values for usages of the `color-mix(…)` function that reference variables
327331 // found in the theme config.
328332 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- }
333+ colorMixDeclarations . get ( parent ) . add ( node )
394334 }
395335
396336 parent . push ( node )
@@ -595,6 +535,74 @@ export function optimizeAst(
595535 newAst = newAst . concat ( atRoots )
596536
597537 // Fallbacks
538+ // Create fallback values for usages of the `color-mix(…)` function that reference variables
539+ // found in the theme config.
540+ if ( polyfills & Polyfills . ColorMix ) {
541+ for ( let [ parent , declarations ] of colorMixDeclarations ) {
542+ for ( let declaration of declarations ) {
543+ let idx = parent . indexOf ( declaration )
544+ // If the declaration is no longer present, we don't need to create a polyfill anymore
545+ if ( idx === - 1 || declaration . value == null ) continue
546+
547+ let ast = ValueParser . parse ( declaration . value )
548+ let requiresPolyfill = false
549+ ValueParser . walk ( ast , ( node , { replaceWith } ) => {
550+ if ( node . kind !== 'function' || node . value !== 'color-mix' ) return
551+ let containsUnresolvableVars = false
552+ let containsCurrentcolor = false
553+ ValueParser . walk ( node . nodes , ( node , { replaceWith } ) => {
554+ if ( node . kind == 'word' && node . value . toLowerCase ( ) === 'currentcolor' ) {
555+ containsCurrentcolor = true
556+ requiresPolyfill = true
557+ return
558+ }
559+ if ( node . kind !== 'function' || node . value !== 'var' ) return
560+ let firstChild = node . nodes [ 0 ]
561+ if ( ! firstChild || firstChild . kind !== 'word' ) return
562+ requiresPolyfill = true
563+ let inlinedColor = designSystem . theme . resolveValue ( null , [ firstChild . value as any ] )
564+ if ( ! inlinedColor ) {
565+ containsUnresolvableVars = true
566+ return
567+ }
568+ replaceWith ( { kind : 'word' , value : inlinedColor } )
569+ } )
570+ if ( containsUnresolvableVars || containsCurrentcolor ) {
571+ let separatorIndex = node . nodes . findIndex (
572+ ( node ) => node . kind === 'separator' && node . value . trim ( ) . includes ( ',' ) ,
573+ )
574+ if ( separatorIndex === - 1 ) return
575+ let firstColorValue =
576+ node . nodes . length > separatorIndex ? node . nodes [ separatorIndex + 1 ] : null
577+ if ( ! firstColorValue ) return
578+ replaceWith ( firstColorValue )
579+ } else if ( requiresPolyfill ) {
580+ // Change the colorspace to `srgb` since the fallback values should not be represented as
581+ // `oklab(…)` functions again as their support in Safari <16 is very limited.
582+ let colorspace = node . nodes [ 2 ]
583+ if (
584+ colorspace . kind === 'word' &&
585+ ( colorspace . value === 'oklab' ||
586+ colorspace . value === 'oklch' ||
587+ colorspace . value === 'lab' ||
588+ colorspace . value === 'lch' )
589+ ) {
590+ colorspace . value = 'srgb'
591+ }
592+ }
593+ } )
594+ if ( ! requiresPolyfill ) continue
595+
596+ let fallback = {
597+ ...declaration ,
598+ value : ValueParser . toCss ( ast ) ,
599+ }
600+ let colorMixQuery = rule ( '@supports (color: color-mix(in lab, red, red))' , [ declaration ] )
601+ parent . splice ( idx , 1 , fallback , colorMixQuery )
602+ }
603+ }
604+ }
605+
598606 if ( polyfills & Polyfills . AtProperty ) {
599607 let fallbackAst = [ ]
600608
0 commit comments