@@ -337,12 +337,44 @@ export const getColorStyle = (color) => {
337337 return `var(--${ color } , inherit)`
338338}
339339
340+ /**
341+ * Convert Tailwind color definitions to RGBA format suitable for CSS style statements
342+ * @param {string } color - Tailwind color name (e.g., "amber-200", "slate-800") or hex/rgb/rgba string
343+ * @param {number } opacity - Opacity value between 0 and 1 (default: 1)
344+ * @returns {string } - RGBA color string in modernised format "rgba(r g b / a)"
345+ * @example
346+ * tailwindToRgba('amber-200') // returns "rgba(255, 245, 235, 1)"
347+ * tailwindToRgba('slate-800') // returns "rgba(30, 32, 34, 1)"
348+ * tailwindToRgba('blue-500') // returns "rgba(59, 130, 246, 1)"
349+ * tailwindToRgba('#3b82f6', 0.5) // returns "rgba(59, 130, 246, 0.5)"
350+ */
351+ export function tailwindToRgbWithOpacity ( color , opacity = 1 ) {
352+ let hex = ''
353+ // Check if it's a Tailwind color name (e.g., "amber-200")
354+ if ( / ^ [ a - z ] + - \d + $ / i. test ( color ) ) {
355+ hex = TAILWIND_COLORS [ color ]
356+ } else {
357+ logWarn ( `tailwindToRgba` , `Invalid Tailwind color name: ${ color } ` )
358+ return null
359+ }
360+
361+ // Parse RGB values
362+ const r = parseInt ( hex . substring ( 0 , 2 ) , 16 )
363+ const g = parseInt ( hex . substring ( 2 , 4 ) , 16 )
364+ const b = parseInt ( hex . substring ( 4 , 6 ) , 16 )
365+ // If alpha channel is present (#RRGGBBAA), then return as is
366+ if ( opacity !== 1 ) {
367+ return `rgb(${ r } ${ g } ${ b } / ${ opacity } )`
368+ }
369+ return hex
370+ }
371+
340372/**
341373 * Convert Tailwind color definitions to HSL format suitable for CSS style statements
342374 * Accepts Tailwind color names (e.g., "amber-200", "slate-800") or any chroma-parseable color format
343375 * @param {string } color - Tailwind color name (e.g., "amber-200", "slate-800") or hex/rgb/rgba string
344376 * @param {boolean } includeAlpha - Whether to include alpha channel in output (default: false)
345- * @returns {string } - HSL color string in format "hsl(h, s%, l% )" or "hsla(h, s%, l%, a)"
377+ * @returns {string } - HSL color string in modernised format "hsl(h s l )" or "hsla(h s l / a)"
346378 * @example
347379 * tailwindToHsl('amber-200') // returns "hsl(45, 93%, 77%)"
348380 * tailwindToHsl('slate-800') // returns "hsl(222, 47%, 11%)"
@@ -384,13 +416,80 @@ export const tailwindToHsl = (color, includeAlpha = false) => {
384416
385417 if ( includeAlpha ) {
386418 const alpha = chromaColor . alpha ( )
387- return `hsla(${ h } , ${ s } %, ${ l } %, ${ alpha } )`
419+ return `hsla(${ h } ${ s } % ${ l } % / ${ alpha } )`
388420 }
389421
390- return `hsl(${ h } , ${ s } %, ${ l } %)`
422+ return `hsl(${ h } ${ s } % ${ l } %)`
391423 } catch ( error ) {
392424 // If chroma can't parse the color, return null
393425 logError ( `tailwindToHsl` , `Error: ${ error . message } ` )
394426 return null
395427 }
396428}
429+
430+ /**
431+ * Convert any CSS color to rgba with specified opacity
432+ * Supports: #RGB, #RRGGBB, #RRGGBBAA, named CSS colors (e.g. red, blue), tailwind colors (amber-200, blue-500, etc.), hsl(), rgb(), rgba()
433+ * @param {string } color - CSS color value
434+ * @param {number } opacity - Opacity value between 0 and 1 (default: 1)
435+ * @returns {string } RGBA color string
436+ */
437+ export function colorToModernSpecWithOpacity ( colorIn : string , opacity : number = 1 ) : string {
438+ let color = colorIn . trim ( ) . toLowerCase ( )
439+
440+ // First convert Tailwind color names to hsl(), as we had that function already
441+ if ( / ^ \w + - \d + $ / . test ( color ) ) {
442+ color = tailwindToRgbWithOpacity ( color )
443+ return color
444+ }
445+
446+ // If already rgb(), add opacity if needed
447+ if ( color . startsWith ( 'rgb(' ) && opacity !== 1 ) {
448+ // Convert rgb(r,g,b) or rgb(r g b) to rgb(r g b / opacity)
449+ return color
450+ . replace ( ',' , ' ' , 'g' )
451+ . replace ( ')' , `, ${ opacity } )` )
452+ }
453+
454+ // If already hsl(), overwrite opacity if needed
455+ if ( color . startsWith ( 'hsl(' ) && opacity !== 1 ) {
456+ // Convert hsl(h,s,l) or hsl(h s l) to hsl(h s l / opacity)
457+ return color
458+ . replace ( ',' , ' ' , 'g' )
459+ . replace ( ')' , ` / ${ opacity } )` )
460+ }
461+
462+ // If already rgba() return as-is
463+ if ( color . startsWith ( 'rgba(' ) ) {
464+ return color
465+ }
466+
467+ // Handle hex colors (#RGB, #RRGGBB, #RRGGBBAA)
468+ if ( color . startsWith ( '#' ) ) {
469+ let hex = color . substring ( 1 )
470+
471+ // Expand shorthand #RGB to #RRGGBB
472+ if ( hex . length === 3 ) {
473+ hex = hex [ 0 ] + hex [ 0 ] + hex [ 1 ] + hex [ 1 ] + hex [ 2 ] + hex [ 2 ]
474+ }
475+
476+ // Parse RGB values
477+ const r = parseInt ( hex . substring ( 0 , 2 ) , 16 )
478+ const g = parseInt ( hex . substring ( 2 , 4 ) , 16 )
479+ const b = parseInt ( hex . substring ( 4 , 6 ) , 16 )
480+
481+ // Check if alpha channel is present (#RRGGBBAA)
482+ if ( hex . length === 8 ) {
483+ const a = parseInt ( hex . substring ( 6 , 8 ) , 16 ) / 255
484+ return `rgba(${ r } ${ g } ${ b } / ${ a } )`
485+ }
486+
487+ return `rgba(${ r } ${ g } ${ b } / ${ opacity } )`
488+ }
489+
490+ // For named colors (red, blue, etc.), add opacity (if wanted) using color-mix()
491+ if ( opacity !== 1 ) {
492+ return `color-mix(in srgb, ${ color } ${ opacity * 100 } %, transparent)`
493+ }
494+ return color
495+ }
0 commit comments