99 unstable_useEventCallback as useEventCallback ,
1010 unstable_useForkRef as useForkRef ,
1111 unstable_useControlled as useControlled ,
12+ visuallyHidden ,
1213} from '@material-ui/utils' ;
1314import isHostComponent from '../utils/isHostComponent' ;
1415import sliderUnstyledClasses from './sliderUnstyledClasses' ;
@@ -19,6 +20,9 @@ function asc(a, b) {
1920}
2021
2122function clamp ( value , min , max ) {
23+ if ( value == null ) {
24+ return min ;
25+ }
2226 return Math . min ( Math . max ( min , value ) , max ) ;
2327}
2428
@@ -102,7 +106,7 @@ function focusThumb({ sliderRef, activeIndex, setActive }) {
102106 ! sliderRef . current . contains ( doc . activeElement ) ||
103107 Number ( doc . activeElement . getAttribute ( 'data-index' ) ) !== activeIndex
104108 ) {
105- sliderRef . current . querySelector ( `[role="slider "][data-index="${ activeIndex } "]` ) . focus ( ) ;
109+ sliderRef . current . querySelector ( `[type="range "][data-index="${ activeIndex } "]` ) . focus ( ) ;
106110 }
107111
108112 if ( setActive ) {
@@ -209,7 +213,7 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
209213 isRtl = false ,
210214 components = { } ,
211215 componentsProps = { } ,
212- /* eslint-disable react/prop-types */
216+ /* eslint-disable-next-line react/prop-types */
213217 theme,
214218 ...other
215219 } = props ;
@@ -223,7 +227,7 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
223227
224228 const [ valueDerived , setValueState ] = useControlled ( {
225229 controlled : valueProp ,
226- default : defaultValue ,
230+ default : defaultValue ?? min ,
227231 name : 'Slider' ,
228232 } ) ;
229233
@@ -304,62 +308,30 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
304308 setFocusVisible ( - 1 ) ;
305309 }
306310
307- const handleKeyDown = useEventCallback ( ( event ) => {
311+ const handleHiddenInputChange = useEventCallback ( ( event ) => {
308312 const index = Number ( event . currentTarget . getAttribute ( 'data-index' ) ) ;
309313 const value = values [ index ] ;
310- const tenPercents = ( max - min ) / 10 ;
311314 const marksValues = marks . map ( ( mark ) => mark . value ) ;
312315 const marksIndex = marksValues . indexOf ( value ) ;
313- let newValue ;
314- const increaseKey = isRtl ? 'ArrowLeft' : 'ArrowRight' ;
315- const decreaseKey = isRtl ? 'ArrowRight' : 'ArrowLeft' ;
316-
317- switch ( event . key ) {
318- case 'Home' :
319- newValue = min ;
320- break ;
321- case 'End' :
322- newValue = max ;
323- break ;
324- case 'PageUp' :
325- if ( step ) {
326- newValue = value + tenPercents ;
327- }
328- break ;
329- case 'PageDown' :
330- if ( step ) {
331- newValue = value - tenPercents ;
332- }
333- break ;
334- case increaseKey :
335- case 'ArrowUp' :
336- if ( step ) {
337- newValue = value + step ;
338- } else {
339- newValue = marksValues [ marksIndex + 1 ] || marksValues [ marksValues . length - 1 ] ;
340- }
341- break ;
342- case decreaseKey :
343- case 'ArrowDown' :
344- if ( step ) {
345- newValue = value - step ;
346- } else {
347- newValue = marksValues [ marksIndex - 1 ] || marksValues [ 0 ] ;
348- }
349- break ;
350- default :
351- return ;
352- }
353316
354- // Prevent scroll of the page
355- event . preventDefault ( ) ;
317+ let newValue = event . target . valueAsNumber ;
356318
357- if ( step ) {
358- newValue = roundValueToStep ( newValue , step , min ) ;
319+ if ( marks && step == null ) {
320+ newValue = newValue < value ? marksValues [ marksIndex - 1 ] : marksValues [ marksIndex + 1 ] ;
359321 }
360322
361323 newValue = clamp ( newValue , min , max ) ;
362324
325+ if ( marks && step == null ) {
326+ const markValues = marks . map ( ( mark ) => mark . value ) ;
327+ const currentMarkIndex = markValues . indexOf ( values [ index ] ) ;
328+
329+ newValue =
330+ newValue < values [ index ]
331+ ? markValues [ currentMarkIndex - 1 ]
332+ : markValues [ currentMarkIndex + 1 ] ;
333+ }
334+
363335 if ( range ) {
364336 const previousValue = newValue ;
365337 newValue = setValueIndex ( {
@@ -377,6 +349,7 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
377349 if ( handleChange ) {
378350 handleChange ( event , newValue ) ;
379351 }
352+
380353 if ( onChangeCommitted ) {
381354 onChangeCommitted ( event , newValue ) ;
382355 }
@@ -650,7 +623,6 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
650623 className = { clsx ( utilityClasses . track , trackProps . className ) }
651624 style = { { ...trackStyle , ...trackProps . style } }
652625 />
653- < input value = { values . join ( ',' ) } name = { name } type = "hidden" />
654626 { marks . map ( ( mark , index ) => {
655627 const percent = valueToPercent ( mark . value , min , max ) ;
656628 const style = axisProps [ axis ] . offset ( percent ) ;
@@ -715,55 +687,72 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
715687 const ValueLabelComponent = valueLabelDisplay === 'off' ? Forward : ValueLabel ;
716688
717689 return (
718- < ValueLabelComponent
719- key = { index }
720- valueLabelFormat = { valueLabelFormat }
721- valueLabelDisplay = { valueLabelDisplay }
722- value = {
723- typeof valueLabelFormat === 'function'
724- ? valueLabelFormat ( scale ( value ) , index )
725- : valueLabelFormat
726- }
727- index = { index }
728- open = { open === index || active === index || valueLabelDisplay === 'on' }
729- disabled = { disabled }
730- { ...valueLabelProps }
731- className = { clsx ( utilityClasses . valueLabel , valueLabelProps . className ) }
732- { ...( ! isHostComponent ( ValueLabel ) && {
733- styleProps : { ...styleProps , ...valueLabelProps . styleProps } ,
734- theme,
735- } ) }
736- >
737- < Thumb
738- tabIndex = { disabled ? null : 0 }
739- role = "slider"
740- data-index = { index }
741- aria-label = { getAriaLabel ? getAriaLabel ( index ) : ariaLabel }
742- aria-labelledby = { ariaLabelledby }
743- aria-orientation = { orientation }
744- aria-valuemax = { scale ( max ) }
745- aria-valuemin = { scale ( min ) }
746- aria-valuenow = { scale ( value ) }
747- aria-valuetext = {
748- getAriaValueText ? getAriaValueText ( scale ( value ) , index ) : ariaValuetext
690+ < React . Fragment key = { index } >
691+ < ValueLabelComponent
692+ valueLabelFormat = { valueLabelFormat }
693+ valueLabelDisplay = { valueLabelDisplay }
694+ value = {
695+ typeof valueLabelFormat === 'function'
696+ ? valueLabelFormat ( scale ( value ) , index )
697+ : valueLabelFormat
749698 }
750- onKeyDown = { handleKeyDown }
751- onFocus = { handleFocus }
752- onBlur = { handleBlur }
753- onMouseOver = { handleMouseOver }
754- onMouseLeave = { handleMouseLeave }
755- { ...thumbProps }
756- className = { clsx ( utilityClasses . thumb , thumbProps . className , {
757- [ utilityClasses . active ] : active === index ,
758- [ utilityClasses . focusVisible ] : focusVisible === index ,
759- } ) }
760- { ...( ! isHostComponent ( Thumb ) && {
761- styleProps : { ...styleProps , ...thumbProps . styleProps } ,
699+ index = { index }
700+ open = { open === index || active === index || valueLabelDisplay === 'on' }
701+ disabled = { disabled }
702+ { ...valueLabelProps }
703+ className = { clsx ( utilityClasses . valueLabel , valueLabelProps . className ) }
704+ { ...( ! isHostComponent ( ValueLabel ) && {
705+ styleProps : { ...styleProps , ...valueLabelProps . styleProps } ,
762706 theme,
763707 } ) }
764- style = { { ...style , ...thumbProps . style } }
765- />
766- </ ValueLabelComponent >
708+ >
709+ < Thumb
710+ data-index = { index }
711+ onMouseOver = { handleMouseOver }
712+ onMouseLeave = { handleMouseLeave }
713+ { ...thumbProps }
714+ className = { clsx ( utilityClasses . thumb , thumbProps . className , {
715+ [ utilityClasses [ 'active' ] ] : active === index ,
716+ [ utilityClasses [ 'focusVisible' ] ] : focusVisible === index ,
717+ } ) }
718+ { ...( ! isHostComponent ( Thumb ) && {
719+ styleProps : { ...styleProps , ...thumbProps . styleProps } ,
720+ theme,
721+ } ) }
722+ style = { { ...style , ...thumbProps . style } }
723+ >
724+ < input
725+ data-index = { index }
726+ aria-label = { getAriaLabel ? getAriaLabel ( index ) : ariaLabel }
727+ aria-labelledby = { ariaLabelledby }
728+ aria-orientation = { orientation }
729+ aria-valuemax = { scale ( max ) }
730+ aria-valuemin = { scale ( min ) }
731+ aria-valuenow = { scale ( value ) }
732+ aria-valuetext = {
733+ getAriaValueText ? getAriaValueText ( scale ( value ) , index ) : ariaValuetext
734+ }
735+ onFocus = { handleFocus }
736+ onBlur = { handleBlur }
737+ name = { name }
738+ type = "range"
739+ min = { props . min }
740+ max = { props . max }
741+ step = { props . step }
742+ disabled = { disabled }
743+ value = { values [ index ] }
744+ onChange = { handleHiddenInputChange }
745+ style = { {
746+ ...visuallyHidden ,
747+ direction : isRtl ? 'rtl' : 'ltr' ,
748+ // So that VoiceOver's focus indicator matches the thumb's dimensions
749+ width : '100%' ,
750+ height : '100%' ,
751+ } }
752+ />
753+ </ Thumb >
754+ </ ValueLabelComponent >
755+ </ React . Fragment >
767756 ) ;
768757 } ) }
769758 </ Root >
0 commit comments