packageDocumentation module import "./HueSlider.scss" ; import classnames from "classnames" ; import * as React from "react" ; import { HSVColor } from "@itwin/core-common" ; import { SpecialKey } from "@itwin/appui-abstract" ; import { CommonProps } from "@itwin/core-react" ; import { UiIModelComponents } from "../UiIModelComponents" ; function calculateHue ( currentPos , high , isVertical ) { if ( currentPos <= 0 ) { return isVertical ? 359 : 0 ; } else if ( currentPos >= high ) { return isVertical ? 0 : 359 ; } else { let percent = ( ( currentPos * 100 ) / high ) ; if ( isVertical ) percent = 100 - percent ; return Math . round ( ( ( 359 * percent ) / 100 ) ) ; } } function calculateChange ( currentHue , e , isHorizontal , container ) { const { width : containerWidth , height : containerHeight , top : containerTop , left : containerLeft } = container . getBoundingClientRect ( ) ; let x ; if ( "pageX" in e ) { x = e . pageX ; } else { if ( undefined === e . touches || 0 === e . touches . length ) return currentHue ; x = e . touches [ 0 ] . pageX ; } if ( undefined === x ) return currentHue ; let y ; if ( "pageY" in e ) { y = e . pageY ; } else { if ( undefined === e . touches || 0 === e . touches . length ) return currentHue ; y = e . touches [ 0 ] . pageY ; } if ( undefined === y ) return currentHue ; const pointerX = x - ( containerLeft + window . scrollX ) ; const pointerY = y - ( containerTop + window . scrollY ) ; if ( ! isHorizontal ) { return calculateHue ( pointerY , containerHeight , true ) ; } else { return calculateHue ( pointerX , containerWidth , false ) ; } } beta export interface HueSliderProps extends React . HTMLAttributes < HTMLDivElement > , CommonProps { /** true if slider is oriented horizontal, else vertical orientation is assumed */ isHorizontal ? : boolean ; /** function to run when user hue is changed */ onHueChange ? : ( ( hue : HSVColor ) => void ) | undefined ; /** HSV Color Value */ hsv : HSVColor ; } beta export function HueSlider ( { isHorizontal , onHueChange , hsv , className , style } ) { const container = React . useRef < HTMLDivElement > ( null ) ; const [ hueLabel ] = React . useState ( ( ) => UiIModelComponents . translate ( "color.hue" ) ) ; const isDragging = React . useRef ( false ) ; const onChange = React . useCallback ( ( e ) => { if ( container . current ) { const newHue = calculateChange ( hsv . h , e , ! ! isHorizontal , container . current ) ; const newColor = hsv . clone ( newHue ) ; if ( onHueChange ) onHueChange ( newColor ) ; } } , [ isHorizontal , hsv , onHueChange ] ) ; const onDragging = React . useCallback ( ( e ) => { if ( isDragging . current ) { onChange ( e ) ; } } , [ onChange ] ) ; const onMouseUp = React . useCallback ( ( ) => { if ( isDragging . current ) { isDragging . current = false ; } } , [ ] ) ; const onTouchEnd = React . useCallback ( ( event ) => { event . preventDefault ( ) ; if ( isDragging . current ) { onChange ( event ) ; isDragging . current = false ; } } , [ onChange ] ) ; const onMouseDown = React . useCallback ( ( e ) => { e . preventDefault ( ) ; if ( e . target !== e . currentTarget ) { if ( ! isDragging . current ) { document . addEventListener ( "mouseup" , onMouseUp , { capture : true , once : true } ) ; isDragging . current = true ; } } onChange ( e ) ; if ( container . current ) container . current . focus ( ) ; } , [ onChange , onMouseUp ] ) ; const onTouchStart = React . useCallback ( ( e ) => { if ( e . target !== e . currentTarget ) isDragging . current = true ; onChange ( e ) ; if ( container . current ) container . current . focus ( ) ; } , [ onChange ] ) ; const onKeyDown = React . useCallback ( ( evt ) => { let newHue ; const hueValue = hsv . h ; if ( evt . key === SpecialKey . ArrowLeft || evt . key === SpecialKey . ArrowDown ) { newHue = hueValue - ( evt . ctrlKey ? 10 : 1 ) ; } else if ( evt . key === SpecialKey . ArrowRight || evt . key === SpecialKey . ArrowUp ) { newHue = hueValue + ( evt . ctrlKey ? 10 : 1 ) ; } else if ( evt . key === SpecialKey . PageDown ) { newHue = hueValue - ( evt . ctrlKey ? 180 : 60 ) ; } else if ( evt . key === SpecialKey . PageUp ) { newHue = hueValue + ( evt . ctrlKey ? 180 : 60 ) ; } else if ( evt . key === SpecialKey . Home ) { newHue = 0 ; } else { if ( evt . key === SpecialKey . End ) { newHue = 359 ; } } if ( undefined !== newHue ) { if ( newHue > 359 ) newHue = 359 ; if ( newHue < 0 ) newHue = 0 ; const newColor = hsv . clone ( newHue ) ; if ( onHueChange ) onHueChange ( newColor ) ; evt . preventDefault ( ) ; } } , [ hsv , onHueChange ] ) ; const containerClasses = classnames ( isHorizontal ? "components-hue-container-horizontal" : "components-hue-container-vertical" , className ) ; const pointerStyle = isHorizontal ? { left : `${ ( hsv . h * 100 ) / 360 }%` , backgroundColor : `hsl(${ hsv . h } ,100%, 50%)` } : { left : `0px` , top : `${ - ( ( hsv . h * 100 ) / 360 ) + 100 }%` , backgroundColor : `hsl(${ hsv . h } ,100%, 50%)` } ; return ( < div className = { containerClasses } style = { style } data - testid = "hue-container" > < div data - testid = "hue-slider" role = "slider" aria - label = { hueLabel } aria - valuemin = { 0 } aria - valuemax = { 360 } aria - valuenow = { hsv . h } className = "components-hue-slider" ref = { container } onMouseDown = { onMouseDown } onMouseMove = { onDragging } onTouchMove = { onDragging } onMouseUp = { onMouseUp } onTouchStart = { onTouchStart } onTouchEnd = { onTouchEnd } tabIndex = { 0 } onKeyDown = { onKeyDown } > < div style = { pointerStyle } className = "components-hue-pointer" data - testid = "hue-pointer" / > < /div> < /div>); }