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 122 123 | 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 1x | import React from 'react';
import type * as CSS from 'csstype';
import { HsvaColor, type ColorResult, validHex, hexToHsva, hsvaToHex, color as handleColor } from '@uiw/color-convert';
import Interactive, { type Interaction } from '@uiw/react-drag-event-interactive';
import { Pointer, type PointerProps } from './Pointer';
import { getWheelHandlePosition, getWheelValueFromInput } from './utils';
export interface WheelProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'color'> {
prefixCls?: string;
color?: string | HsvaColor;
width?: number;
height?: number;
radius?: CSS.Properties<string | number>['borderRadius'];
/** Direction of the oval: 'x' or 'y'. */
oval?: string;
/** Starting angle of the color wheel's hue gradient, measured in degrees. */
angle?: number;
/** Direction of the color wheel's hue gradient; either clockwise or anticlockwise. Default: `anticlockwise` */
direction?: 'clockwise' | 'anticlockwise';
pointer?: ({ prefixCls, left, top, color }: PointerProps) => JSX.Element;
onChange?: (color: ColorResult) => void;
}
const HUE_GRADIENT_CLOCKWISE = 'conic-gradient(red, yellow, lime, aqua, blue, magenta, red)';
const HUE_GRADIENT_ANTICLOCKWISE = 'conic-gradient(red, magenta, blue, aqua, lime, yellow, red)';
const Wheel = React.forwardRef<HTMLDivElement, WheelProps>((props, ref) => {
const {
prefixCls = 'w-color-wheel',
radius = 0,
pointer,
className,
style,
width = 200,
height = 200,
oval,
direction = 'anticlockwise',
angle = 180,
color,
onChange,
...other
} = props;
const hsva = (typeof color === 'string' && validHex(color) ? hexToHsva(color) : color || {}) as HsvaColor;
const hex = color ? hsvaToHex(hsva) : '';
const positions = getWheelHandlePosition({ width }, hsva);
const comProps = {
top: '0',
left: '0',
color: hex,
};
const handleChange = (interaction: Interaction, event: MouseEvent | TouchEvent) => {
const result = getWheelValueFromInput({ width }, width - interaction.x, height - interaction.y);
const handleHsva = {
h: result.h,
s: result.s,
v: hsva.v,
a: hsva.a,
};
onChange && onChange(handleColor(handleHsva));
};
const pointerStyle: CSS.Properties<string | number> = {
zIndex: 1,
position: 'absolute',
transform: `translate(${positions.x}px, ${positions.y}px) ${
oval === 'x' || oval === 'X' ? 'scaleY(2)' : oval === 'y' || oval === 'Y' ? 'scaleX(2)' : ''
}`,
};
const pointerElement =
pointer && typeof pointer === 'function' ? (
pointer({ prefixCls, style: pointerStyle, ...comProps })
) : (
<Pointer prefixCls={prefixCls} style={pointerStyle} {...comProps} />
);
return (
<Interactive
className={[prefixCls, className || ''].filter(Boolean).join(' ')}
{...other}
style={{
position: 'relative',
width,
transform: oval === 'x' || oval === 'X' ? 'scaleY(0.5)' : oval === 'y' || oval === 'Y' ? 'scaleX(0.5)' : '',
height,
...style,
}}
ref={ref}
onMove={handleChange}
onDown={handleChange}
>
{pointerElement}
<div
style={{
position: 'absolute',
borderRadius: '50%',
background: direction === 'anticlockwise' ? HUE_GRADIENT_CLOCKWISE : HUE_GRADIENT_ANTICLOCKWISE,
transform: `rotateZ(${angle + 90}deg)`,
inset: 0,
}}
/>
<div
style={{
position: 'absolute',
borderRadius: '50%',
background: 'radial-gradient(circle closest-side, #fff, transparent)',
inset: 0,
}}
/>
<div
style={{
backgroundColor: '#000',
borderRadius: '50%',
position: 'absolute',
inset: 0,
opacity: typeof hsva.v === 'number' ? 1 - hsva.v / 100 : 0,
}}
/>
</Interactive>
);
});
Wheel.displayName = 'Wheel';
export default Wheel;
|