@@ -38,6 +38,8 @@ function getDocumentColorProvider(): DocumentColorProvider {
3838 ...extractRgbaToColors ( text ) ,
3939 ...extractHsvToColors ( text ) ,
4040 ...extractHsvaToColors ( text ) ,
41+ ...extractHslToColors ( text ) ,
42+ ...extractHslaToColors ( text ) ,
4143 ]
4244
4345 return matchedColors . map ( match => {
@@ -56,6 +58,7 @@ function getDocumentColorProvider(): DocumentColorProvider {
5658 new ColorPresentation ( fromColorToHexAarrggbb ( color ) ) ,
5759 new ColorPresentation ( fromColorToRgba ( color ) ) ,
5860 new ColorPresentation ( fromColorToHsva ( color ) ) ,
61+ new ColorPresentation ( fromColorToHsla ( color ) ) ,
5962 ]
6063
6164 if ( color . alpha === 1 )
@@ -64,6 +67,7 @@ function getDocumentColorProvider(): DocumentColorProvider {
6467 new ColorPresentation ( fromColorToHexRrggbb ( color ) ) ,
6568 new ColorPresentation ( fromColorToRgb ( color ) ) ,
6669 new ColorPresentation ( fromColorToHsv ( color ) ) ,
70+ new ColorPresentation ( fromColorToHsl ( color ) ) ,
6771 )
6872
6973 return supportedPresentation
@@ -270,6 +274,66 @@ export function extractHsvaToColors(text: string): readonly MatchedColor[] {
270274 . filter ( notNil )
271275}
272276
277+ export function extractHslToColors ( text : string ) : readonly MatchedColor [ ] {
278+ // parse 'hsl(360, 100%, 100%)'
279+ const matches = text . matchAll (
280+ / h s l \s * \( \s * ( \d + % ? ) \s * , \s * ( \d + % ? ) \s * , \s * ( \d + % ? ) \s * \) / g,
281+ )
282+
283+ return [ ...matches ]
284+ . map ( match => {
285+ if ( isNil ( match . index ) ) return undefined
286+
287+ const [ code , h , s , l ] = match
288+
289+ if ( isNil ( h ) || isNil ( s ) || isNil ( l ) ) return undefined
290+
291+ const rgb = hslToRgb ( {
292+ h : Number ( h ) ,
293+ s : fromColorValueStringToNumber ( s ) ,
294+ l : fromColorValueStringToNumber ( l ) ,
295+ } )
296+ return {
297+ color : new Color ( rgb . r , rgb . g , rgb . b , 1 ) ,
298+ offsetRange : {
299+ start : match . index ,
300+ end : match . index + code . length ,
301+ } ,
302+ }
303+ } )
304+ . filter ( notNil )
305+ }
306+
307+ export function extractHslaToColors ( text : string ) : readonly MatchedColor [ ] {
308+ // parse 'hsla(360, 100%, 100%, 100%)'
309+ const matches = text . matchAll (
310+ / h s l a \s * \( \s * ( \d + % ? ) \s * , \s * ( \d + % ? ) \s * , \s * ( \d + % ? ) \s * , \s * ( \d + % ? ) \s * \) / g,
311+ )
312+
313+ return [ ...matches ]
314+ . map ( match => {
315+ if ( isNil ( match . index ) ) return undefined
316+
317+ const [ code , h , s , l , a ] = match
318+
319+ if ( isNil ( h ) || isNil ( s ) || isNil ( l ) || isNil ( a ) ) return undefined
320+
321+ const rgb = hslToRgb ( {
322+ h : Number ( h ) ,
323+ s : fromColorValueStringToNumber ( s ) ,
324+ l : fromColorValueStringToNumber ( l ) ,
325+ } )
326+ return {
327+ color : new Color ( rgb . r , rgb . g , rgb . b , fromColorValueStringToNumber ( a ) ) ,
328+ offsetRange : {
329+ start : match . index ,
330+ end : match . index + code . length ,
331+ } ,
332+ }
333+ } )
334+ . filter ( notNil )
335+ }
336+
273337export type MatchedColor = {
274338 readonly color : Color
275339 readonly offsetRange : {
@@ -356,6 +420,16 @@ export function fromColorToHsva(color: Color) {
356420 return `hsva(${ h } , ${ s * 100 } %, ${ v * 100 } %, ${ color . alpha * 100 } %)`
357421}
358422
423+ export function fromColorToHsl ( color : Color ) {
424+ const { h, s, l } = rgbToHsl ( { r : color . red , g : color . green , b : color . blue } )
425+ return `hsl(${ h } , ${ s * 100 } %, ${ l * 100 } %)`
426+ }
427+
428+ export function fromColorToHsla ( color : Color ) {
429+ const { h, s, l } = rgbToHsl ( { r : color . red , g : color . green , b : color . blue } )
430+ return `hsla(${ h } , ${ s * 100 } %, ${ l * 100 } %, ${ color . alpha * 100 } %)`
431+ }
432+
359433function fromColorValueStringToNumber ( str : string ) {
360434 if ( str . endsWith ( '%' ) ) return parseInt ( str . slice ( 0 , - 1 ) , 10 ) / 100
361435 return parseInt ( str , 10 ) / 255
@@ -423,3 +497,66 @@ export function rgbToHsv({ r, g, b }: { r: number; g: number; b: number }) {
423497
424498 return { h, s, v }
425499}
500+
501+ export function hslToRgb ( { h, s, l } : { h : number ; s : number ; l : number } ) {
502+ const c = ( 1 - Math . abs ( 2 * l - 1 ) ) * s
503+ const x = c * ( 1 - Math . abs ( ( ( h / 60 ) % 2 ) - 1 ) )
504+ const m = l - c / 2
505+
506+ let r = 0
507+ let g = 0
508+ let b = 0
509+
510+ if ( h < 60 ) {
511+ r = c
512+ g = x
513+ b = 0
514+ } else if ( h < 120 ) {
515+ r = x
516+ g = c
517+ b = 0
518+ } else if ( h < 180 ) {
519+ r = 0
520+ g = c
521+ b = x
522+ } else if ( h < 240 ) {
523+ r = 0
524+ g = x
525+ b = c
526+ } else if ( h < 300 ) {
527+ r = x
528+ g = 0
529+ b = c
530+ } else {
531+ r = c
532+ g = 0
533+ b = x
534+ }
535+
536+ return { r : r + m , g : g + m , b : b + m }
537+ }
538+
539+ export function rgbToHsl ( { r, g, b } : { r : number ; g : number ; b : number } ) {
540+ const max = Math . max ( r , g , b )
541+ const min = Math . min ( r , g , b )
542+ const c = max - min
543+
544+ let h = 0
545+ let s = 0
546+ const l = ( max + min ) / 2
547+
548+ if ( c !== 0 ) {
549+ if ( max === r ) {
550+ h = ( ( g - b ) / c ) % 6
551+ } else if ( max === g ) {
552+ h = ( b - r ) / c + 2
553+ } else {
554+ h = ( r - g ) / c + 4
555+ }
556+
557+ h *= 60
558+ s = c / ( 1 - Math . abs ( 2 * l - 1 ) )
559+ }
560+
561+ return { h, s, l }
562+ }
0 commit comments