1
+ import { hex , hsl , rgb } from "color-convert" ;
1
2
import plugin from "tailwindcss/plugin" ;
2
- import { ThemeConfig } from "tailwindcss/types/config" ;
3
- import {
4
- type ColorTuple ,
5
- type HexColor ,
6
- type Modifier ,
7
- type Variants ,
8
- hexToRgb ,
9
- hslToRgb ,
10
- invertColor ,
11
- rgbToHsl ,
12
- shadeModifier ,
13
- tintModifier ,
14
- variants ,
15
- } from "./utils" ;
3
+ import { type ThemeConfig } from "tailwindcss/types/config" ;
4
+ import { ColorTuple , invertColor , isColorDark , shadeModifier , tintModifier } from "./utils" ;
16
5
6
+ type HexColor = `#${string } `;
17
7
type Plugin = ReturnType < typeof plugin > ;
18
8
export type RealtimeColorOptions = {
19
9
colors : {
@@ -27,84 +17,118 @@ export type RealtimeColorOptions = {
27
17
shades : ( keyof RealtimeColorOptions [ "colors" ] ) [ ] ;
28
18
prefix : string ;
29
19
shadeAlgorithm : keyof typeof availableModifiers ;
20
+ colorFormat : "rgb" | "hsl" | "lch" | "lab" ;
30
21
} ;
31
22
type RealtimeColorOptionsWithoutColor = Omit < RealtimeColorOptions , "colors" > ;
32
23
33
- const isDarkMode = ( color : HexColor ) => {
34
- const l = rgbToHsl ( hexToRgb ( color ) ) [ 2 ] ;
35
- return l > 50 ;
36
- } ;
37
-
24
+ const variants = [ 50 , 100 , 200 , 300 , 400 , 500 , 600 , 700 , 800 , 900 , 950 ] ;
38
25
const availableModifiers = {
39
26
tailwind : {
40
27
50 : tintModifier ( 0.95 ) ,
41
28
100 : tintModifier ( 0.9 ) ,
42
29
200 : tintModifier ( 0.75 ) ,
43
30
300 : tintModifier ( 0.6 ) ,
44
31
400 : tintModifier ( 0.3 ) ,
45
- 500 : ( c : ColorTuple < "RGB" > ) => c ,
32
+ 500 : ( c : ColorTuple ) => c ,
46
33
600 : shadeModifier ( 0.9 ) ,
47
34
700 : shadeModifier ( 0.6 ) ,
48
35
800 : shadeModifier ( 0.45 ) ,
49
36
900 : shadeModifier ( 0.3 ) ,
50
37
950 : shadeModifier ( 0.2 ) ,
51
- } as Record < Variants , Modifier < "RGB" > > ,
38
+ } ,
52
39
53
40
realtimeColors : Object . fromEntries (
54
41
variants . map ( ( variant ) => [
55
42
variant ,
56
- ( rgb ) => {
57
- const [ h , s , _l ] = rgbToHsl ( rgb ) ;
58
- return hslToRgb ( [ h , s , 100 - variant / 10 ] ) ;
43
+ ( color : ColorTuple ) => {
44
+ const [ h , s ] = rgb . hsl ( color ) ;
45
+ return hsl . rgb ( [ h , s , 100 - variant / 10 ] ) ;
59
46
} ,
60
47
] ) ,
61
- ) as Record < Variants , Modifier < "RGB" > > ,
48
+ ) ,
62
49
} ;
63
50
51
+ const formatRGBColor = ( color : ColorTuple , to : RealtimeColorOptions [ "colorFormat" ] ) => {
52
+ switch ( to ) {
53
+ case "rgb" : {
54
+ const [ r , g , b ] = color ;
55
+ return `${ r } , ${ g } , ${ b } ` ;
56
+ }
57
+ case "hsl" : {
58
+ const [ h , s , l ] = rgb . hsl ( color ) ;
59
+ return `${ h } ${ s } % ${ l } %` ;
60
+ }
61
+ case "lab" : {
62
+ const [ l , a , b ] = rgb . lab . raw ( color ) . map ( ( c ) => c . toFixed ( 2 ) ) ;
63
+ return `${ l } % ${ a } ${ b } ` ;
64
+ }
65
+ case "lch" : {
66
+ const [ l , c , h ] = rgb . lch . raw ( color ) . map ( ( c ) => c . toFixed ( 2 ) ) ;
67
+ return `${ l } % ${ c } ${ h } ` ;
68
+ }
69
+ }
70
+ } ;
71
+
72
+ const wrapInFunction = ( color : string , type : RealtimeColorOptions [ "colorFormat" ] ) =>
73
+ // For some reason rgb() doesn't work with `/ <alpha-value>`
74
+ type === "rgb" ? `rgba(${ color } )` : `${ type } (${ color } / <alpha-value>)` ;
75
+
64
76
const getCSS = ( config : RealtimeColorOptions ) => {
65
77
const { theme, shades, prefix, colors } = config ;
66
78
if ( ! theme ) return [ ] ;
67
79
const modifiers = availableModifiers [ config . shadeAlgorithm ] ;
68
80
const variables : Record < string , string > = { } ;
69
81
const altVariables : Record < string , string > = { } ;
70
82
for ( const [ colorName , color ] of Object . entries ( colors ) ) {
83
+ const rgbColor = hex . rgb ( color ) ;
71
84
if ( shades . includes ( colorName as keyof typeof colors ) ) {
72
- const rgb = hexToRgb ( color ) ;
73
85
for ( const [ variant , modifier ] of Object . entries ( modifiers ) ) {
74
- variables [ `--${ prefix } ${ colorName } -${ variant } ` ] = modifier ( rgb ) . join ( "," ) ;
75
- altVariables [ `--${ prefix } ${ colorName } -${ variant } ` ] = invertColor ( modifier ( rgb ) ) . join ( "," ) ;
86
+ variables [ `--${ prefix } ${ colorName } -${ variant } ` ] = formatRGBColor (
87
+ modifier ( rgbColor ) ,
88
+ config . colorFormat ,
89
+ ) ;
90
+ altVariables [ `--${ prefix } ${ colorName } -${ variant } ` ] = formatRGBColor (
91
+ invertColor ( modifier ( rgbColor ) ) ,
92
+ config . colorFormat ,
93
+ ) ;
76
94
}
77
95
} else {
78
- variables [ `--${ prefix } ${ colorName } ` ] = hexToRgb ( color ) . join ( ", " ) ;
79
- altVariables [ `--${ prefix } ${ colorName } ` ] = invertColor ( hexToRgb ( color ) ) . join ( ", " ) ;
96
+ variables [ `--${ prefix } ${ colorName } ` ] = formatRGBColor ( rgbColor , config . colorFormat ) ;
97
+ altVariables [ `--${ prefix } ${ colorName } ` ] = formatRGBColor (
98
+ invertColor ( rgbColor ) ,
99
+ config . colorFormat ,
100
+ ) ;
80
101
}
81
102
}
82
- const isDark = isDarkMode ( colors . background ) ;
103
+ const isDark = isColorDark ( colors . background ) ;
83
104
return [
84
105
{
85
106
":root" : isDark ? variables : altVariables ,
86
107
":is(.dark):root" : isDark ? altVariables : variables ,
87
108
} ,
88
109
] ;
89
110
} ;
90
-
91
111
const getTheme = ( config : RealtimeColorOptions ) => {
92
112
const { theme, shades, prefix, colors } = config ;
93
113
const colorsTheme : ThemeConfig [ "colors" ] = { } ;
94
114
const modifiers = availableModifiers [ config . shadeAlgorithm ] ;
95
115
for ( const [ colorName , color ] of Object . entries ( colors ) ) {
116
+ const rgbColor = hex . rgb ( color ) ;
96
117
if ( shades . includes ( colorName as keyof typeof colors ) ) {
97
- const rgb = hexToRgb ( color ) ;
98
118
colorsTheme [ `${ prefix } ${ colorName } ` ] = { } ;
99
119
for ( const [ variant , modifier ] of Object . entries ( modifiers ) ) {
100
- ( colorsTheme [ `${ prefix } ${ colorName } ` ] as Record < string , string > ) [ variant ] = `rgba(${
101
- theme ? `var(--${ prefix } ${ colorName } -${ variant } )` : modifier ( rgb ) . join ( ", " )
102
- } )`;
120
+ ( colorsTheme [ `${ prefix } ${ colorName } ` ] as Record < string , string > ) [ variant ] = wrapInFunction (
121
+ theme
122
+ ? `var(--${ prefix } ${ colorName } -${ variant } )`
123
+ : formatRGBColor ( modifier ( rgbColor ) , config . colorFormat ) ,
124
+ config . colorFormat ,
125
+ ) ;
103
126
}
104
127
} else {
105
- colorsTheme [ `${ prefix } ${ colorName } ` ] = `rgba(${
106
- theme ? `var(--${ prefix } ${ colorName } )` : hexToRgb ( color ) . join ( ", " )
107
- } )`;
128
+ colorsTheme [ `${ prefix } ${ colorName } ` ] = wrapInFunction (
129
+ theme ? `var(--${ prefix } ${ colorName } )` : formatRGBColor ( rgbColor , config . colorFormat ) ,
130
+ config . colorFormat ,
131
+ ) ;
108
132
}
109
133
}
110
134
return colorsTheme ;
@@ -139,6 +163,7 @@ function realtimeColors(
139
163
shades : [ "primary" , "secondary" , "accent" ] ,
140
164
prefix : "" ,
141
165
shadeAlgorithm : "tailwind" ,
166
+ colorFormat : "rgb" ,
142
167
} ;
143
168
144
169
if ( typeof configOrUrl === "string" ) {
0 commit comments