import * as Utils from "../utils" ; import { ReactNode , useRef } from "react" ; type Props = { height : number ; width : number ; handleHeight : number ; value : number ; handle : ReactNode ; onBeforeChange ? : ( ) => void ; onChange : ( value : number ) => void ; onAfterChange ? : ( ) => void ; disabled ? : boolean ; } ; type RegOptions = { target : HTMLElement ; touch : boolean ; clientY : number ; } ; export default function VerticalSlider ( { value , height , width , handle , handleHeight , onBeforeChange , onChange , onAfterChange , disabled , } ) { const ref = useRef < HTMLDivElement | null > ( null ) ; const handleRef = useRef < HTMLDivElement | null > ( null ) ; function registerMoveListener ( { target , clientY , touch } ) { const sliderNode = ref . current ; const handleNode = handleRef . current ; if ( sliderNode == null || handleNode == null ) { return null ; } const sliderRect = sliderNode . getBoundingClientRect ( ) ; const handleRect = handleNode . getBoundingClientRect ( ) ; const { top : sliderTop , height : sliderHeight } = sliderRect ; const { top : handleTop , height : realHandleHeight } = handleRect ; const handleOffset = handleNode . contains ( target as HTMLElement ) ? clientY - handleTop : realHandleHeight / 2 ; const baseOffset = sliderTop + handleOffset ; const spanSize = sliderHeight - realHandleHeight ; function moveToPosition ( y ) { const startOffset = y - baseOffset ; onChange ( Utils . clamp ( startOffset / spanSize , 0 , 1 ) ) ; } if ( touch ) { const handleTouchMove = ( event ) => { if ( event . cancelable ) { event . preventDefault ( ) ; } moveToPosition ( event . touches [ 0 ] . clientY ) ; } ; const handleTouchEnd = ( ) => { if ( onAfterChange != null ) { onAfterChange ( ) ; } document . removeEventListener ( "touchmove" , handleTouchMove ) ; document . removeEventListener ( "touchend" , handleTouchEnd ) ; } ; document . addEventListener ( "touchmove" , handleTouchMove , { passive : false , } ) ; document . addEventListener ( "touchend" , handleTouchEnd ) ; } else { const handleMouseMove = ( event ) => { event . preventDefault ( ) ; moveToPosition ( event . clientY ) ; } ; const handleMouseUp = ( ) => { if ( onAfterChange != null ) { onAfterChange ( ) ; } document . removeEventListener ( "mousemove" , handleMouseMove ) ; document . removeEventListener ( "mouseup" , handleMouseUp ) ; } ; document . addEventListener ( "mousemove" , handleMouseMove ) ; document . addEventListener ( "mouseup" , handleMouseUp ) ; } if ( onBeforeChange != null ) { onBeforeChange ( ) ; } moveToPosition ( clientY ) ; } function handleMouseDown ( e ) { e . preventDefault ( ) ; registerMoveListener ( { target : e . target as HTMLElement , clientY : e . clientY , touch : false , } ) ; } function handleTouchStart ( e ) { registerMoveListener ( { target : e . target as HTMLElement , clientY : e . touches [ 0 ] . clientY , touch : true , } ) ; } const offset = Math . floor ( ( height - handleHeight ) * value ) ; return ( < div style = { { height , width } } onMouseDown = { disabled ? undefined : handleMouseDown } onTouchStart = { disabled ? undefined : handleTouchStart } ref = { ref } > < div style = { { transform : `translateY(${ offset }px)` } } ref = { handleRef } > { handle } < /div> < /div>); }