@@ -49,19 +49,20 @@ function getKeywordColor(value: unknown): KeywordColor | null {
4949 return null
5050}
5151
52- function getColorsInString ( state : State , str : string ) : ParsedColor [ ] {
52+ function getColorsInString ( state : State , str : string , preferDark : boolean = false ) : ParsedColor [ ] {
5353 if ( / (?: b o x | d r o p ) - s h a d o w / . test ( str ) && ! / - - t w - d r o p - s h a d o w / . test ( str ) ) return [ ]
5454
5555 str = replaceCssVarsWithFallbacks ( state , str )
5656 str = removeColorMixWherePossible ( str )
57- str = resolveLightDark ( str )
57+ str = resolveLightDark ( str , preferDark )
5858
5959 return parseColors ( str )
6060}
6161
6262function getColorFromDecls (
6363 state : State ,
6464 decls : Record < string , string | string [ ] > ,
65+ preferDark : boolean = false ,
6566) : ParsedColor | null {
6667 let props = Object . keys ( decls ) . filter ( ( prop ) => {
6768 // ignore content: "";
@@ -104,7 +105,7 @@ function getColorFromDecls(
104105 const propsToCheck = areAllCustom ? props : nonCustomProps
105106
106107 const colors = propsToCheck . flatMap ( ( prop ) =>
107- ensureArray ( decls [ prop ] ) . flatMap ( ( str ) => getColorsInString ( state , str ) ) ,
108+ ensureArray ( decls [ prop ] ) . flatMap ( ( str ) => getColorsInString ( state , str , preferDark ) ) ,
108109 )
109110
110111 // check that all of the values are the same color, ignoring alpha
@@ -137,7 +138,11 @@ function getColorFromDecls(
137138 return null
138139}
139140
140- function getColorFromRoot ( state : State , css : AstNode [ ] ) : ParsedColor | null {
141+ function getColorFromRoot (
142+ state : State ,
143+ css : AstNode [ ] ,
144+ preferDark : boolean = false ,
145+ ) : ParsedColor | null {
141146 let decls : Record < string , string [ ] > = { }
142147
143148 walk ( css , ( node ) => {
@@ -171,7 +176,7 @@ function getColorFromRoot(state: State, css: AstNode[]): ParsedColor | null {
171176 return WalkAction . Continue
172177 } )
173178
174- return getColorFromDecls ( state , decls )
179+ return getColorFromDecls ( state , decls , preferDark )
175180}
176181
177182let isNegative = / ^ - /
@@ -190,13 +195,17 @@ function isLikelyColorless(className: string) {
190195 return false
191196}
192197
193- export function getColor ( state : State , className : string ) : ParsedColor | null {
198+ export function getColor (
199+ state : State ,
200+ className : string ,
201+ preferDark : boolean = false ,
202+ ) : ParsedColor | null {
194203 if ( state . v4 ) {
195204 // FIXME: This is a performance optimization and not strictly correct
196205 if ( isLikelyColorless ( className ) ) return null
197206
198207 let css = state . designSystem . compile ( [ className ] ) [ 0 ]
199- let color = getColorFromRoot ( state , css )
208+ let color = getColorFromRoot ( state , css , preferDark )
200209
201210 let prefix = state . designSystem . theme . prefix ?? ''
202211
@@ -205,7 +214,7 @@ export function getColor(state: State, className: string): ParsedColor | null {
205214 if ( prefix && ! color && ! className . startsWith ( prefix + ':' ) ) {
206215 className = `${ prefix } :${ className } `
207216 css = state . designSystem . compile ( [ className ] ) [ 0 ]
208- color = getColorFromRoot ( state , css )
217+ color = getColorFromRoot ( state , css , preferDark )
209218 }
210219
211220 return color
@@ -215,7 +224,7 @@ export function getColor(state: State, className: string): ParsedColor | null {
215224 if ( state . classNames ) {
216225 const item = dlv ( state . classNames . classNames , [ className , '__info' ] )
217226 if ( item && item . __rule ) {
218- return getColorFromDecls ( state , removeMeta ( item ) )
227+ return getColorFromDecls ( state , removeMeta ( item ) , preferDark )
219228 }
220229 }
221230
@@ -244,7 +253,7 @@ export function getColor(state: State, className: string): ParsedColor | null {
244253 decls [ decl . prop ] = decl . value
245254 }
246255 } )
247- return getColorFromDecls ( state , decls )
256+ return getColorFromDecls ( state , decls , preferDark )
248257 }
249258
250259 let parts = getClassNameParts ( state , className )
@@ -253,7 +262,7 @@ export function getColor(state: State, className: string): ParsedColor | null {
253262 const item = dlv ( state . classNames . classNames , [ ...parts , '__info' ] )
254263 if ( ! item . __rule ) return null
255264
256- return getColorFromDecls ( state , removeMeta ( item ) )
265+ return getColorFromDecls ( state , removeMeta ( item ) , preferDark )
257266}
258267
259268export function getColorFromValue ( value : unknown ) : ParsedColor | null {
@@ -315,10 +324,53 @@ function removeColorMixWherePossible(str: string) {
315324 } )
316325}
317326
318- const LIGHT_DARK_REGEX = / l i g h t - d a r k \( \s * ( .* ?) \s * , \s * .* ?\s * \) / g
327+ const LIGHT_DARK_START = / l i g h t - d a r k \( \s * / g
328+
329+ export function resolveLightDark ( str : string , preferDark : boolean = false ) : string {
330+ let result = ''
331+ let lastIndex = 0
332+ let match : RegExpExecArray | null
333+
334+ LIGHT_DARK_START . lastIndex = 0
335+
336+ while ( ( match = LIGHT_DARK_START . exec ( str ) ) !== null ) {
337+ result += str . slice ( lastIndex , match . index )
338+
339+ let start = match . index + match [ 0 ] . length
340+ let depth = 1
341+ let commaIndex = - 1
342+ let i = start
343+
344+ // Find the comma separating light and dark values, handling nested parentheses
345+ while ( i < str . length && depth > 0 ) {
346+ let char = str [ i ]
347+ if ( char === '(' ) {
348+ depth ++
349+ } else if ( char === ')' ) {
350+ depth --
351+ } else if ( char === ',' && depth === 1 && commaIndex === - 1 ) {
352+ commaIndex = i
353+ }
354+ i ++
355+ }
356+
357+ if ( commaIndex === - 1 || depth !== 0 ) {
358+ // Invalid light-dark() syntax, keep original
359+ result += match [ 0 ]
360+ lastIndex = start
361+ continue
362+ }
363+
364+ let lightColor = str . slice ( start , commaIndex ) . trim ( )
365+ let darkColor = str . slice ( commaIndex + 1 , i - 1 ) . trim ( )
366+
367+ result += preferDark ? darkColor : lightColor
368+ lastIndex = i
369+ LIGHT_DARK_START . lastIndex = i
370+ }
319371
320- function resolveLightDark ( str : string ) {
321- return str . replace ( LIGHT_DARK_REGEX , ( _ , lightColor ) => lightColor )
372+ result += str . slice ( lastIndex )
373+ return result
322374}
323375
324376const COLOR_FNS = new Set ( [
0 commit comments