@@ -366,6 +366,14 @@ export const Slider: React.FC<SliderProps> = ({
366366 [ tickMarkers ]
367367 )
368368
369+ /** Convert from the slider track value format (0.0 - 1.0) to the format used by the value. */
370+ const convertDecimalToValue = useCallback (
371+ x => min + x * ( max - min ) ,
372+ [ min , max ]
373+ )
374+
375+ const shouldSnapToTick = snap && tickMarkers . length > 0
376+
369377 // Computes the new value and passed it to the handleChange callback
370378 const handleClick = useCallback (
371379 ( e : PointerEvent | React . MouseEvent < BaseElement > ) => {
@@ -377,15 +385,15 @@ export const Slider: React.FC<SliderProps> = ({
377385 let x = clamp ( ( e . pageX - left ) / width )
378386
379387 // Find x position if snap is enabled
380- if ( e . type !== 'pointermove' && snap && tickMarkers . length > 0 ) {
388+ if ( e . type !== 'pointermove' && shouldSnapToTick ) {
381389 const snapTo = snapValues . reduce ( ( a , b ) =>
382390 Math . abs ( b - x ) < Math . abs ( a - x ) ? b : a
383391 )
384392
385393 x = snapTo
386394 }
387395
388- handleChange ( min + x * ( max - min ) )
396+ handleChange ( convertDecimalToValue ( x ) )
389397 }
390398 } ,
391399 [ handleChange , max , min , onClick , snap , snapValues , tickMarkers . length ]
@@ -421,6 +429,15 @@ export const Slider: React.FC<SliderProps> = ({
421429 }
422430 } , [ handleClick , pressed ] )
423431
432+ const getNextSnap = useCallback (
433+ ( ) => snapValues . find ( snapValue => snapValue > fraction ) ,
434+ [ snapValues , fraction ]
435+ )
436+ const getPreviousSnap = useCallback (
437+ ( ) => snapValues . reverse ( ) . find ( snapValue => snapValue < fraction ) ,
438+ [ snapValues , fraction ]
439+ )
440+
424441 // Keyboard support
425442 const handleKeyDown = useCallback < React . KeyboardEventHandler < BaseElement > > (
426443 event => {
@@ -442,23 +459,31 @@ export const Slider: React.FC<SliderProps> = ({
442459 switch ( event . key ) {
443460 case SliderKeys . ArrowRight :
444461 case SliderKeys . ArrowUp : {
445- newValue = value + onePercent
462+ newValue = shouldSnapToTick
463+ ? convertDecimalToValue ( getNextSnap ( ) )
464+ : value + onePercent
446465 break
447466 }
448467
449468 case SliderKeys . ArrowLeft :
450469 case SliderKeys . ArrowDown : {
451- newValue = value - onePercent
470+ newValue = shouldSnapToTick
471+ ? convertDecimalToValue ( getPreviousSnap ( ) )
472+ : value - onePercent
452473 break
453474 }
454475
455476 case SliderKeys . PageUp : {
456- newValue = value + onePercent * 10
477+ newValue = shouldSnapToTick
478+ ? convertDecimalToValue ( getNextSnap ( ) )
479+ : value + onePercent * 10
457480 break
458481 }
459482
460483 case SliderKeys . PageDown : {
461- newValue = value - onePercent * 10
484+ newValue = shouldSnapToTick
485+ ? convertDecimalToValue ( getPreviousSnap ( ) )
486+ : value - onePercent * 10
462487 break
463488 }
464489
@@ -475,6 +500,7 @@ export const Slider: React.FC<SliderProps> = ({
475500 default :
476501 }
477502
503+ // keep new value inside min and max
478504 if ( newValue !== undefined ) {
479505 if ( newValue > max ) {
480506 newValue = max
0 commit comments