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