@@ -3,50 +3,101 @@ import {
3
3
ColorResult ,
4
4
color as handleColor ,
5
5
hexToHsva ,
6
- hsvaToHsla ,
7
- hsvaToHslString ,
6
+ hsvaToRgbaString ,
8
7
validHex ,
8
+ hsvaToRgba ,
9
9
HsvaColor ,
10
- hslStringToHsva ,
10
+ rgbaStringToHsva ,
11
11
} from '@uiw/color-convert' ;
12
12
13
13
export interface SliderProps extends Omit < React . HTMLAttributes < HTMLDivElement > , 'onChange' | 'color' > {
14
14
prefixCls ?: string ;
15
15
color ?: string | HsvaColor ;
16
16
lightness ?: number [ ] ;
17
+ customColorShades ?: { color : string | HsvaColor ; lightness : number [ ] } [ ] ;
17
18
onChange ?: ( color : ColorResult , evn : React . MouseEvent < HTMLDivElement , MouseEvent > ) => void ;
18
19
}
19
20
21
+ const hsvaCheck = ( color ?: string | HsvaColor ) : HsvaColor => {
22
+ return ( typeof color === 'string' && validHex ( color ) ? hexToHsva ( color ) : color || { } ) as HsvaColor ;
23
+ } ;
24
+
25
+ // Check if values are within specified units of each other
26
+ const withinRange = ( val1 : number , val2 : number , tolerance : number = 2 ) : boolean => Math . abs ( val1 - val2 ) <= tolerance ;
27
+
28
+ const hsvaEqual = ( c1 : HsvaColor , c2 : HsvaColor , lightnessArray ?: number [ ] ) : boolean => {
29
+ // Check for match within 2 units of all properties
30
+ const baseMatch = withinRange ( c1 . h , c2 . h ) && withinRange ( c1 . s , c2 . s ) && withinRange ( c1 . a , c2 . a ) ;
31
+ const exactMatch = baseMatch && withinRange ( c1 . v , c2 . v ) ;
32
+
33
+ // If there's a match within range, return true
34
+ if ( exactMatch ) return true ;
35
+
36
+ // If no exact match and a lightness array exists,
37
+ // check if value is within range of any of the lightness array values
38
+ if ( lightnessArray ) {
39
+ return baseMatch && lightnessArray . some ( ( lightness ) => withinRange ( c2 . v , lightness ) ) ;
40
+ }
41
+
42
+ return false ;
43
+ } ;
44
+
20
45
const Slider = React . forwardRef < HTMLDivElement , SliderProps > ( ( props , ref ) => {
21
- const { prefixCls = 'w-color-slider' , className, style, onChange, color, lightness = [ 80 , 65 , 50 , 35 , 20 ] , ...other } = props ;
22
- const hsva = ( typeof color === 'string' && validHex ( color ) ? hexToHsva ( color ) : color || { } ) as HsvaColor ;
23
- const handleClick = ( hslStr : string , evn : React . MouseEvent < HTMLDivElement , MouseEvent > ) => {
24
- onChange && onChange ( handleColor ( hslStringToHsva ( hslStr ) ) , evn ) ;
46
+ const {
47
+ prefixCls = 'w-color-slider' ,
48
+ className,
49
+ style,
50
+ onChange,
51
+ color,
52
+ customColorShades = [
53
+ { color : '#000000' , lightness : [ 50 , 40 , 30 , 20 , 10 ] } ,
54
+ { color : '#ffffff' , lightness : [ 95 , 90 , 80 , 70 , 60 ] } ,
55
+ ] ,
56
+ lightness = [ 80 , 65 , 50 , 35 , 20 ] ,
57
+ ...other
58
+ } = props ;
59
+ const hsva = hsvaCheck ( color ) ;
60
+
61
+ // Find matching custom color and its lightness array
62
+ const matchingCustomColor = customColorShades . find ( ( shade ) => {
63
+ const customHsva = hsvaCheck ( shade . color ) ;
64
+ const isMatch = hsvaEqual ( customHsva , hsva , shade . lightness ) ;
65
+ return isMatch ;
66
+ } ) ;
67
+
68
+ // Determine which lightness array to use
69
+ const activeLightness = matchingCustomColor ? matchingCustomColor . lightness : lightness ;
70
+
71
+ const handleClick = ( rgbaStr : string , evn : React . MouseEvent < HTMLDivElement , MouseEvent > ) => {
72
+ const newHsva = rgbaStringToHsva ( rgbaStr ) ;
73
+ onChange && onChange ( handleColor ( newHsva ) , evn ) ;
25
74
} ;
75
+
26
76
return (
27
77
< div
28
78
ref = { ref }
29
79
style = { { display : 'flex' , ...style } }
30
80
className = { [ prefixCls , className || '' ] . filter ( Boolean ) . join ( ' ' ) }
31
81
{ ...other }
32
82
>
33
- { lightness . map ( ( num , idx ) => {
34
- const hsl = hsvaToHsla ( hsva ) ;
35
- const hslStr = `hsl(${ hsl . h } , 50%, ${ num } %)` ;
36
- const checked = hslStr === hsvaToHslString ( hsva ) ;
83
+ { activeLightness . map ( ( num : number , idx : number ) => {
84
+ const newHsva = { ...hsva , v : num } ;
85
+ const rgba = hsvaToRgba ( newHsva ) ;
86
+ const rgbaStr = `rgba(${ rgba . r } , ${ rgba . g } , ${ rgba . b } , ${ rgba . a } )` ;
87
+ const checked = rgbaStr === hsvaToRgbaString ( hsva ) ;
37
88
return (
38
89
< div
39
90
key = { idx }
40
91
style = { {
41
92
paddingLeft : 1 ,
42
- width : `${ 100 / lightness . length } %` ,
93
+ width : `${ 100 / activeLightness . length } %` ,
43
94
boxSizing : 'border-box' ,
44
95
} }
45
96
>
46
97
< div
47
- onClick = { ( evn ) => handleClick ( hslStr , evn ) }
98
+ onClick = { ( evn ) => handleClick ( rgbaStr , evn ) }
48
99
style = { {
49
- backgroundColor : hslStr ,
100
+ backgroundColor : rgbaStr ,
50
101
height : 12 ,
51
102
cursor : 'pointer' ,
52
103
...( checked
0 commit comments