import type { HsvaColor } from '../types.js' ; import { fire , tpl } from '../utils/dom.js' ; import { clamp } from '../utils/math.js' ; export interface Offset { x : number ; y : number ; } let hasTouched = false ; const isTouch = ( e ) : e is TouchEvent => 'touches' in e ; const isValid = ( event ) : boolean => { if ( hasTouched && ! isTouch ( event ) ) return false ; if ( ! hasTouched ) hasTouched = isTouch ( event ) ; return true ; } ; const pointerMove = ( target , event ) : void => { const pointer = isTouch ( event ) ? event . touches [ 0 ] : ( event as MouseEvent ) ; const rect = target . el . getBoundingClientRect ( ) ; fire ( target . el , 'move' , target . getMove ( { x : clamp ( ( pointer . pageX - ( rect . left + window . pageXOffset ) ) / rect . width ) , y : clamp ( ( pointer . pageY - ( rect . top + window . pageYOffset ) ) / rect . height ) } ) ) ; } ; const keyMove = ( target , event ) : void => { const keyCode = event . keyCode ; if ( keyCode > 40 || ( target . xy && keyCode < 37 ) || keyCode < 33 ) return ; event . preventDefault ( ) ; fire ( target . el , 'move' , target . getMove ( { x : keyCode === 39 ? 0.01 : keyCode === 37 ? - 0.01 : keyCode === 34 ? 0.05 : keyCode === 33 ? - 0.05 : keyCode === 35 ? 1 : keyCode === 36 ? - 1 : 0 , y : keyCode === 40 ? 0.01 : keyCode === 38 ? - 0.01 : 0 } , true ) ) ; } ; export abstract class Slider { declare nodes : HTMLElement [ ] ; declare el : HTMLElement ; declare xy : boolean ; constructor ( root , part , aria , xy ) { const template = tpl ( `<div role="slider" tabindex="0" part="${ part }" ${ aria }><div part="${ part }-pointer"></div></div>` ) ; root . appendChild ( template . content . cloneNode ( true ) ) ; const el = root . querySelector ( `[part=${ part }]` ) as HTMLElement ; el . addEventListener ( 'mousedown' , this ) ; el . addEventListener ( 'touchstart' , this ) ; el . addEventListener ( 'keydown' , this ) ; this . el = el ; this . xy = xy ; this . nodes = [ el . firstChild as HTMLElement , el ] ; } set dragging ( state ) { const toggleEvent = state ? document . addEventListener : document . removeEventListener ; toggleEvent ( hasTouched ? 'touchmove' : 'mousemove' , this ) ; toggleEvent ( hasTouched ? 'touchend' : 'mouseup' , this ) ; } handleEvent ( event ) { switch ( event . type ) { case 'mousedown' : case 'touchstart' : event . preventDefault ( ) ; if ( ! isValid ( event ) || ( ! hasTouched && ( event as MouseEvent ) . button != 0 ) ) return ; this . el . focus ( ) ; pointerMove ( this , event ) ; this . dragging = true ; break ; case 'mousemove' : case 'touchmove' : event . preventDefault ( ) ; pointerMove ( this , event ) ; break ; case 'mouseup' : case 'touchend' : this . dragging = false ; break ; case 'keydown' : keyMove ( this , event as KeyboardEvent ) ; break ; } } abstract getMove ( offset , key ? ) ; abstract update ( hsva ) ; style ( styles ) { styles . forEach ( ( style , i ) => { for ( const p in style ) { this . nodes [ i ] . style . setProperty ( p , style [ p ] ) ; } } ) ; } }