11const dlv = require ( 'dlv' )
22import { State } from './state'
33import removeMeta from './removeMeta'
4+ import { TinyColor } from '@ctrl/tinycolor'
5+ import { ensureArray , dedupe , flatten } from './array'
46
57const COLOR_PROPS = [
68 'caret-color' ,
@@ -19,202 +21,75 @@ const COLOR_PROPS = [
1921 'text-decoration-color' ,
2022]
2123
22- const COLOR_NAMES = {
23- transparent : 'rgba(0, 0, 0, 0.01)' ,
24- aliceblue : '#f0f8ff' ,
25- antiquewhite : '#faebd7' ,
26- aqua : '#0ff' ,
27- aquamarine : '#7fffd4' ,
28- azure : '#f0ffff' ,
29- beige : '#f5f5dc' ,
30- bisque : '#ffe4c4' ,
31- black : '#000' ,
32- blanchedalmond : '#ffebcd' ,
33- blue : '#00f' ,
34- blueviolet : '#8a2be2' ,
35- brown : '#a52a2a' ,
36- burlywood : '#deb887' ,
37- burntsienna : '#ea7e5d' ,
38- cadetblue : '#5f9ea0' ,
39- chartreuse : '#7fff00' ,
40- chocolate : '#d2691e' ,
41- coral : '#ff7f50' ,
42- cornflowerblue : '#6495ed' ,
43- cornsilk : '#fff8dc' ,
44- crimson : '#dc143c' ,
45- cyan : '#0ff' ,
46- darkblue : '#00008b' ,
47- darkcyan : '#008b8b' ,
48- darkgoldenrod : '#b8860b' ,
49- darkgray : '#a9a9a9' ,
50- darkgreen : '#006400' ,
51- darkgrey : '#a9a9a9' ,
52- darkkhaki : '#bdb76b' ,
53- darkmagenta : '#8b008b' ,
54- darkolivegreen : '#556b2f' ,
55- darkorange : '#ff8c00' ,
56- darkorchid : '#9932cc' ,
57- darkred : '#8b0000' ,
58- darksalmon : '#e9967a' ,
59- darkseagreen : '#8fbc8f' ,
60- darkslateblue : '#483d8b' ,
61- darkslategray : '#2f4f4f' ,
62- darkslategrey : '#2f4f4f' ,
63- darkturquoise : '#00ced1' ,
64- darkviolet : '#9400d3' ,
65- deeppink : '#ff1493' ,
66- deepskyblue : '#00bfff' ,
67- dimgray : '#696969' ,
68- dimgrey : '#696969' ,
69- dodgerblue : '#1e90ff' ,
70- firebrick : '#b22222' ,
71- floralwhite : '#fffaf0' ,
72- forestgreen : '#228b22' ,
73- fuchsia : '#f0f' ,
74- gainsboro : '#dcdcdc' ,
75- ghostwhite : '#f8f8ff' ,
76- gold : '#ffd700' ,
77- goldenrod : '#daa520' ,
78- gray : '#808080' ,
79- green : '#008000' ,
80- greenyellow : '#adff2f' ,
81- grey : '#808080' ,
82- honeydew : '#f0fff0' ,
83- hotpink : '#ff69b4' ,
84- indianred : '#cd5c5c' ,
85- indigo : '#4b0082' ,
86- ivory : '#fffff0' ,
87- khaki : '#f0e68c' ,
88- lavender : '#e6e6fa' ,
89- lavenderblush : '#fff0f5' ,
90- lawngreen : '#7cfc00' ,
91- lemonchiffon : '#fffacd' ,
92- lightblue : '#add8e6' ,
93- lightcoral : '#f08080' ,
94- lightcyan : '#e0ffff' ,
95- lightgoldenrodyellow : '#fafad2' ,
96- lightgray : '#d3d3d3' ,
97- lightgreen : '#90ee90' ,
98- lightgrey : '#d3d3d3' ,
99- lightpink : '#ffb6c1' ,
100- lightsalmon : '#ffa07a' ,
101- lightseagreen : '#20b2aa' ,
102- lightskyblue : '#87cefa' ,
103- lightslategray : '#789' ,
104- lightslategrey : '#789' ,
105- lightsteelblue : '#b0c4de' ,
106- lightyellow : '#ffffe0' ,
107- lime : '#0f0' ,
108- limegreen : '#32cd32' ,
109- linen : '#faf0e6' ,
110- magenta : '#f0f' ,
111- maroon : '#800000' ,
112- mediumaquamarine : '#66cdaa' ,
113- mediumblue : '#0000cd' ,
114- mediumorchid : '#ba55d3' ,
115- mediumpurple : '#9370db' ,
116- mediumseagreen : '#3cb371' ,
117- mediumslateblue : '#7b68ee' ,
118- mediumspringgreen : '#00fa9a' ,
119- mediumturquoise : '#48d1cc' ,
120- mediumvioletred : '#c71585' ,
121- midnightblue : '#191970' ,
122- mintcream : '#f5fffa' ,
123- mistyrose : '#ffe4e1' ,
124- moccasin : '#ffe4b5' ,
125- navajowhite : '#ffdead' ,
126- navy : '#000080' ,
127- oldlace : '#fdf5e6' ,
128- olive : '#808000' ,
129- olivedrab : '#6b8e23' ,
130- orange : '#ffa500' ,
131- orangered : '#ff4500' ,
132- orchid : '#da70d6' ,
133- palegoldenrod : '#eee8aa' ,
134- palegreen : '#98fb98' ,
135- paleturquoise : '#afeeee' ,
136- palevioletred : '#db7093' ,
137- papayawhip : '#ffefd5' ,
138- peachpuff : '#ffdab9' ,
139- peru : '#cd853f' ,
140- pink : '#ffc0cb' ,
141- plum : '#dda0dd' ,
142- powderblue : '#b0e0e6' ,
143- purple : '#800080' ,
144- rebeccapurple : '#663399' ,
145- red : '#f00' ,
146- rosybrown : '#bc8f8f' ,
147- royalblue : '#4169e1' ,
148- saddlebrown : '#8b4513' ,
149- salmon : '#fa8072' ,
150- sandybrown : '#f4a460' ,
151- seagreen : '#2e8b57' ,
152- seashell : '#fff5ee' ,
153- sienna : '#a0522d' ,
154- silver : '#c0c0c0' ,
155- skyblue : '#87ceeb' ,
156- slateblue : '#6a5acd' ,
157- slategray : '#708090' ,
158- slategrey : '#708090' ,
159- snow : '#fffafa' ,
160- springgreen : '#00ff7f' ,
161- steelblue : '#4682b4' ,
162- tan : '#d2b48c' ,
163- teal : '#008080' ,
164- thistle : '#d8bfd8' ,
165- tomato : '#ff6347' ,
166- turquoise : '#40e0d0' ,
167- violet : '#ee82ee' ,
168- wheat : '#f5deb3' ,
169- white : '#fff' ,
170- whitesmoke : '#f5f5f5' ,
171- yellow : '#ff0' ,
172- yellowgreen : '#9acd32' ,
173- }
174-
17524export function getColor (
17625 state : State ,
17726 keys : string [ ]
17827) : { documentation ?: string } {
17928 const item = dlv ( state . classNames . classNames , keys )
18029 if ( ! item . __rule ) return null
18130 const props = Object . keys ( removeMeta ( item ) )
31+ if ( props . length === 0 ) return null
18232 const nonCustomProps = props . filter ( ( prop ) => ! prop . startsWith ( '--' ) )
183- if ( nonCustomProps . length !== 1 ) return null
184- const prop = nonCustomProps [ 0 ]
185- if ( COLOR_PROPS . indexOf ( prop ) === - 1 ) return null
18633
187- const namedColor = COLOR_NAMES [ item [ prop ] . toLowerCase ( ) ]
188- if ( namedColor ) {
189- return { documentation : namedColor }
34+ const areAllCustom = nonCustomProps . length === 0
35+
36+ if (
37+ ! areAllCustom &&
38+ nonCustomProps . some ( ( prop ) => ! COLOR_PROPS . includes ( prop ) )
39+ ) {
40+ // they should all be color-based props
41+ return null
19042 }
19143
192- // matches: rgba(<r>, <g>, <b>, var(--bg-opacity))
193- // TODO: support other formats? e.g. hsla, css level 4
194- const match = item [ prop ] . match (
195- / ^ \s * r g b a \( \s * (?< r > [ 0 - 9 ] { 1 , 3 } ) \s * , \s * (?< g > [ 0 - 9 ] { 1 , 3 } ) \s * , \s * (?< b > [ 0 - 9 ] { 1 , 3 } ) \s * , \s * v a r /
44+ const propsToCheck = areAllCustom ? props : nonCustomProps
45+
46+ const colors = flatten (
47+ propsToCheck . map ( ( prop ) => ensureArray ( item [ prop ] ) . map ( createColor ) )
19648 )
197- if ( match ) {
198- return {
199- documentation : `rgb( ${ match . groups . r } , ${ match . groups . g } , ${ match . groups . b } )` ,
200- }
49+
50+ // check that all of the values are valid colors
51+ if ( colors . some ( ( color ) => ! color . isValid ) ) {
52+ return null
20153 }
20254
203- return { }
204- }
55+ // check that all of the values are the same color
56+ const colorStrings = colors . map ( ( color ) => color . toRgbString ( ) )
57+ if ( dedupe ( colorStrings ) . length !== 1 ) {
58+ return null
59+ }
20560
206- export function isColor ( str : any ) : boolean {
207- return (
208- typeof str === 'string' &&
209- / ^ (?: # | 0 x ) (?: [ a - f 0 - 9 ] { 3 , 4 } | [ a - f 0 - 9 ] { 6 } | [ a - f 0 - 9 ] { 8 } ) \b | (?: r g b | h s l ) a ? \( [ ^ \) ] * \) $ / . test (
210- str . trim ( )
211- )
212- )
61+ return { documentation : colorStrings [ 0 ] }
21362}
21463
21564export function getColorFromString ( str : string ) : string {
216- if ( isColor ( str ) ) {
217- return str
65+ if ( str === 'transparent' ) {
66+ return 'rgba(0, 0, 0, 0.01)'
67+ }
68+ const color = new TinyColor ( str )
69+ if ( color . isValid ) {
70+ return color . toRgbString ( )
21871 }
219- return COLOR_NAMES [ str ] || null
72+ return null
73+ }
74+
75+ function createColor ( str : string ) : TinyColor {
76+ if ( str === 'transparent' ) {
77+ return new TinyColor ( { r : 0 , g : 0 , b : 0 , a : 0.01 } )
78+ }
79+
80+ // matches: rgba(<r>, <g>, <b>, var(--bg-opacity))
81+ // TODO: support other formats? e.g. hsla, css level 4
82+ const match = str . match (
83+ / ^ \s * r g b a \( \s * (?< r > [ 0 - 9 ] { 1 , 3 } ) \s * , \s * (?< g > [ 0 - 9 ] { 1 , 3 } ) \s * , \s * (?< b > [ 0 - 9 ] { 1 , 3 } ) \s * , \s * v a r /
84+ )
85+
86+ if ( match ) {
87+ return new TinyColor ( {
88+ r : match . groups . r ,
89+ g : match . groups . g ,
90+ b : match . groups . b ,
91+ } )
92+ }
93+
94+ return new TinyColor ( str )
22095}
0 commit comments