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 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 1x | import React from 'react'; import { HsvaColor, ColorResult, validHex, hexToHsva, hsvaToHex, color as handleColor } from '@uiw/color-convert'; import Interactive, { Interaction } from '@uiw/react-drag-event-interactive'; import { Pointer, 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?: React.CSSProperties['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: React.CSSProperties = { zIndex: 1, 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; |