diff --git a/docs/data/base/components/slider/DiscreteSlider.js b/docs/data/base/components/slider/DiscreteSlider.js new file mode 100644 index 00000000000000..af17c12ef2b790 --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSlider.js @@ -0,0 +1,120 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } + `, +); + +function valuetext(value) { + return `${value}°C`; +} + +export default function DiscreteSlider() { + return ( + + + + ); +} diff --git a/docs/data/base/components/slider/DiscreteSlider.tsx b/docs/data/base/components/slider/DiscreteSlider.tsx new file mode 100644 index 00000000000000..68db5df993f4da --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSlider.tsx @@ -0,0 +1,120 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } + `, +); + +function valuetext(value: number) { + return `${value}°C`; +} + +export default function DiscreteSlider() { + return ( + + + + ); +} diff --git a/docs/data/base/components/slider/DiscreteSlider.tsx.preview b/docs/data/base/components/slider/DiscreteSlider.tsx.preview new file mode 100644 index 00000000000000..1555bdaf8cfe40 --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSlider.tsx.preview @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/docs/data/base/components/slider/DiscreteSliderMarks.js b/docs/data/base/components/slider/DiscreteSliderMarks.js new file mode 100644 index 00000000000000..302b2286842f97 --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSliderMarks.js @@ -0,0 +1,143 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markLabel} { + font-family: IBM Plex Sans; + font-size: 12px; + position: absolute; + top: 20px; + transform: translateX(-50%); + } +`, +); + +const marks = [ + { + value: 0, + label: '0°C', + }, + { + value: 20, + label: '20°C', + }, + { + value: 37, + label: '37°C', + }, + { + value: 100, + label: '100°C', + }, +]; + +function valuetext(value) { + return `${value}°C`; +} + +export default function DiscreteSliderMarks() { + return ( + + + + ); +} diff --git a/docs/data/base/components/slider/DiscreteSliderMarks.tsx b/docs/data/base/components/slider/DiscreteSliderMarks.tsx new file mode 100644 index 00000000000000..78ace0c541d36d --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSliderMarks.tsx @@ -0,0 +1,143 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markLabel} { + font-family: IBM Plex Sans; + font-size: 12px; + position: absolute; + top: 20px; + transform: translateX(-50%); + } +`, +); + +const marks = [ + { + value: 0, + label: '0°C', + }, + { + value: 20, + label: '20°C', + }, + { + value: 37, + label: '37°C', + }, + { + value: 100, + label: '100°C', + }, +]; + +function valuetext(value: number) { + return `${value}°C`; +} + +export default function DiscreteSliderMarks() { + return ( + + + + ); +} diff --git a/docs/data/base/components/slider/DiscreteSliderMarks.tsx.preview b/docs/data/base/components/slider/DiscreteSliderMarks.tsx.preview new file mode 100644 index 00000000000000..3ac66f37d33610 --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSliderMarks.tsx.preview @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/docs/data/base/components/slider/DiscreteSliderValues.js b/docs/data/base/components/slider/DiscreteSliderValues.js new file mode 100644 index 00000000000000..a9461452939d1e --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSliderValues.js @@ -0,0 +1,144 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markLabel} { + font-family: IBM Plex Sans; + font-size: 12px; + position: absolute; + top: 20px; + transform: translateX(-50%); + } +`, +); + +const marks = [ + { + value: 0, + label: '0°C', + }, + { + value: 20, + label: '20°C', + }, + { + value: 37, + label: '37°C', + }, + { + value: 100, + label: '100°C', + }, +]; + +function valuetext(value) { + return `${value}°C`; +} + +export default function DiscreteSliderValues() { + return ( + + + + ); +} diff --git a/docs/data/base/components/slider/DiscreteSliderValues.tsx b/docs/data/base/components/slider/DiscreteSliderValues.tsx new file mode 100644 index 00000000000000..f8ed812e622e34 --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSliderValues.tsx @@ -0,0 +1,144 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markLabel} { + font-family: IBM Plex Sans; + font-size: 12px; + position: absolute; + top: 20px; + transform: translateX(-50%); + } +`, +); + +const marks = [ + { + value: 0, + label: '0°C', + }, + { + value: 20, + label: '20°C', + }, + { + value: 37, + label: '37°C', + }, + { + value: 100, + label: '100°C', + }, +]; + +function valuetext(value: number) { + return `${value}°C`; +} + +export default function DiscreteSliderValues() { + return ( + + + + ); +} diff --git a/docs/data/base/components/slider/DiscreteSliderValues.tsx.preview b/docs/data/base/components/slider/DiscreteSliderValues.tsx.preview new file mode 100644 index 00000000000000..a8de136dfa93ca --- /dev/null +++ b/docs/data/base/components/slider/DiscreteSliderValues.tsx.preview @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/data/base/components/slider/RangeSlider.js b/docs/data/base/components/slider/RangeSlider.js new file mode 100644 index 00000000000000..c5546c25792d5d --- /dev/null +++ b/docs/data/base/components/slider/RangeSlider.js @@ -0,0 +1,133 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } +`, +); + +function valuetext(value) { + return `${value}°C`; +} + +export default function RangeSlider() { + const [value, setValue] = React.useState([20, 37]); + + const handleChange = (event, newValue) => { + setValue(newValue); + }; + + return ( + + {/* controlled: */} + 'Temperature range'} + getAriaValueText={valuetext} + min={0} + max={100} + /> + {/* uncontrolled: */} + 'Temperature range'} + getAriaValueText={valuetext} + min={0} + max={100} + /> + + ); +} diff --git a/docs/data/base/components/slider/RangeSlider.tsx b/docs/data/base/components/slider/RangeSlider.tsx new file mode 100644 index 00000000000000..bed530a507e46b --- /dev/null +++ b/docs/data/base/components/slider/RangeSlider.tsx @@ -0,0 +1,133 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; + +const StyledSlider = styled(SliderUnstyled)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? '#1976d2' : '#90caf9'}; + height: 4px; + width: 100%; + padding: 13px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + opacity: 0.75; + + &:hover { + opacity: 1; + } + + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.38; + } + + & .${sliderUnstyledClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderUnstyledClasses.thumb} { + position: absolute; + width: 14px; + height: 14px; + margin-left: -6px; + margin-top: -5px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 2px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderUnstyledClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.15, + )}; + } + + &.${sliderUnstyledClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', + 0.3, + )}; + } + } + + & .${sliderUnstyledClasses.mark} { + position: absolute; + width: 4px; + height: 4px; + border-radius: 2px; + background-color: currentColor; + top: 50%; + opacity: 0.7; + transform: translateX(-50%); + } + + & .${sliderUnstyledClasses.markActive} { + background-color: #fff; + } + + & .${sliderUnstyledClasses.valueLabel} { + font-family: IBM Plex Sans; + font-size: 14px; + display: block; + position: relative; + top: -1.6em; + text-align: center; + transform: translateX(-50%); + } +`, +); + +function valuetext(value: number) { + return `${value}°C`; +} + +export default function RangeSlider() { + const [value, setValue] = React.useState([20, 37]); + + const handleChange = (event: Event, newValue: number | number[]) => { + setValue(newValue as number[]); + }; + + return ( + + {/* controlled: */} + 'Temperature range'} + getAriaValueText={valuetext} + min={0} + max={100} + /> + {/* uncontrolled: */} + 'Temperature range'} + getAriaValueText={valuetext} + min={0} + max={100} + /> + + ); +} diff --git a/docs/data/material/components/slider/UnstyledSlider.js b/docs/data/base/components/slider/UnstyledSlider.js similarity index 75% rename from docs/data/material/components/slider/UnstyledSlider.js rename to docs/data/base/components/slider/UnstyledSlider.js index 2a06fdb9568aac..0290a7115fb868 100644 --- a/docs/data/material/components/slider/UnstyledSlider.js +++ b/docs/data/base/components/slider/UnstyledSlider.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { styled, alpha, Box } from '@mui/system'; -import SliderUnstyled from '@mui/base/SliderUnstyled'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; const StyledSlider = styled(SliderUnstyled)( ({ theme }) => ` @@ -14,11 +14,18 @@ const StyledSlider = styled(SliderUnstyled)( touch-action: none; -webkit-tap-highlight-color: transparent; opacity: 0.75; + &:hover { opacity: 1; } - & .MuiSlider-rail { + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { display: block; position: absolute; width: 100%; @@ -28,7 +35,7 @@ const StyledSlider = styled(SliderUnstyled)( opacity: 0.38; } - & .MuiSlider-track { + & .${sliderUnstyledClasses.track} { display: block; position: absolute; height: 4px; @@ -36,7 +43,7 @@ const StyledSlider = styled(SliderUnstyled)( background-color: currentColor; } - & .MuiSlider-thumb { + & .${sliderUnstyledClasses.thumb} { position: absolute; width: 14px; height: 14px; @@ -49,14 +56,14 @@ const StyledSlider = styled(SliderUnstyled)( background-color: #fff; :hover, - &.Mui-focusVisible { + &.${sliderUnstyledClasses.focusVisible} { box-shadow: 0 0 0 0.25rem ${alpha( theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', 0.15, )}; } - &.Mui-active { + &.${sliderUnstyledClasses.active} { box-shadow: 0 0 0 0.25rem ${alpha( theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', 0.3, @@ -70,6 +77,7 @@ export default function UnstyledSlider() { return ( + ); } diff --git a/docs/data/material/components/slider/UnstyledSlider.tsx b/docs/data/base/components/slider/UnstyledSlider.tsx similarity index 75% rename from docs/data/material/components/slider/UnstyledSlider.tsx rename to docs/data/base/components/slider/UnstyledSlider.tsx index 2a06fdb9568aac..0290a7115fb868 100644 --- a/docs/data/material/components/slider/UnstyledSlider.tsx +++ b/docs/data/base/components/slider/UnstyledSlider.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { styled, alpha, Box } from '@mui/system'; -import SliderUnstyled from '@mui/base/SliderUnstyled'; +import SliderUnstyled, { sliderUnstyledClasses } from '@mui/base/SliderUnstyled'; const StyledSlider = styled(SliderUnstyled)( ({ theme }) => ` @@ -14,11 +14,18 @@ const StyledSlider = styled(SliderUnstyled)( touch-action: none; -webkit-tap-highlight-color: transparent; opacity: 0.75; + &:hover { opacity: 1; } - & .MuiSlider-rail { + &.${sliderUnstyledClasses.disabled} { + pointer-events: none; + cursor: default; + color: #bdbdbd; + } + + & .${sliderUnstyledClasses.rail} { display: block; position: absolute; width: 100%; @@ -28,7 +35,7 @@ const StyledSlider = styled(SliderUnstyled)( opacity: 0.38; } - & .MuiSlider-track { + & .${sliderUnstyledClasses.track} { display: block; position: absolute; height: 4px; @@ -36,7 +43,7 @@ const StyledSlider = styled(SliderUnstyled)( background-color: currentColor; } - & .MuiSlider-thumb { + & .${sliderUnstyledClasses.thumb} { position: absolute; width: 14px; height: 14px; @@ -49,14 +56,14 @@ const StyledSlider = styled(SliderUnstyled)( background-color: #fff; :hover, - &.Mui-focusVisible { + &.${sliderUnstyledClasses.focusVisible} { box-shadow: 0 0 0 0.25rem ${alpha( theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', 0.15, )}; } - &.Mui-active { + &.${sliderUnstyledClasses.active} { box-shadow: 0 0 0 0.25rem ${alpha( theme.palette.mode === 'light' ? '#1976d2' : '#90caf9', 0.3, @@ -70,6 +77,7 @@ export default function UnstyledSlider() { return ( + ); } diff --git a/docs/data/base/components/slider/UnstyledSlider.tsx.preview b/docs/data/base/components/slider/UnstyledSlider.tsx.preview new file mode 100644 index 00000000000000..d326ff94b11db6 --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSlider.tsx.preview @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/docs/data/base/components/slider/slider.md b/docs/data/base/components/slider/slider.md new file mode 100644 index 00000000000000..ac011d62403321 --- /dev/null +++ b/docs/data/base/components/slider/slider.md @@ -0,0 +1,63 @@ +--- +product: base +title: React Slider unstyled component and hook +components: SliderUnstyled +githubLabel: 'component: slider' +waiAria: https://www.w3.org/TR/wai-aria-practices/#slider +packageName: '@mui/base' +--- + +# Slider + +

The SliderUnstyled component lets users make selections from a range of values along a horizontal or vertical bar.

+ +Users may need to select a single value or a range of values on a slider. +They are ideal for interface controls that benefit from a visual representation of adjustable content, such as volume or brightness settings, or for applying image filters. + +{{"component": "modules/components/ComponentLinkHeader.js", "design": false}} + +```js +import SliderUnstyled from '@mui/base/SliderUnstyled'; +``` + +{{"demo": "UnstyledSlider.js", "defaultCodeOpen": false}} + +## Discrete sliders + +The most basic slider is _continuous_, which means it does not have pre-defined (_discrete_) values for the user to select from. +This is suitable for situations in which an approximate value is good enough for the user, such as brightness or volume. + +But if your users need more precise options, you can create a discrete slider that snaps to pre-defined stops along the bar. +To generate a mark for each stop, use `marks={true}`: + +{{"demo": "DiscreteSlider.js"}} + +### Custom marks + +You can create custom marks by providing a rich array to the `marks` prop: + +{{"demo": "DiscreteSliderMarks.js"}} + +### Restricted values + +If the user should only be able to select from the values provided with the `marks` prop, add `step={null}` to disable all other options: + +{{"demo": "DiscreteSliderValues.js"}} + +## Range slider + +To let users set the start and end of a range on a slider, provide an array of values to the `value` or `defaultValue` prop: + +{{"demo": "RangeSlider.js"}} + +## Accessibility + +(WAI-ARIA: https://www.w3.org/TR/wai-aria-practices/#slider) + +The component handles most of the work necessary to make it accessible. +However, you need to make sure that: + +- Each thumb has a user-friendly label (`aria-label`, `aria-labelledby` or `getAriaLabel` prop). +- Each thumb has a user-friendly text for its current value. + This is not required if the value matches the semantics of the label. + You can change the name with the `getAriaValueText` or `aria-valuetext` prop. diff --git a/docs/data/base/pages.ts b/docs/data/base/pages.ts index 626667e8c12d54..de736f4782bcea 100644 --- a/docs/data/base/pages.ts +++ b/docs/data/base/pages.ts @@ -18,6 +18,7 @@ const pages = [ { pathname: '/base/react-button', title: 'Button' }, { pathname: '/base/react-input', title: 'Input' }, { pathname: '/base/react-select', title: 'Select' }, + { pathname: '/base/react-slider', title: 'Slider' }, ], }, { diff --git a/docs/data/material/components/slider/UnstyledSlider.tsx.preview b/docs/data/material/components/slider/UnstyledSlider.tsx.preview deleted file mode 100644 index 9280bf10ade5d0..00000000000000 --- a/docs/data/material/components/slider/UnstyledSlider.tsx.preview +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/data/material/components/slider/slider.md b/docs/data/material/components/slider/slider.md index efe9205b79159f..cc3ef260436069 100644 --- a/docs/data/material/components/slider/slider.md +++ b/docs/data/material/components/slider/slider.md @@ -1,10 +1,11 @@ --- product: material-ui title: React Slider component -components: Slider, SliderUnstyled +components: Slider githubLabel: 'component: slider' materialDesign: https://material.io/components/sliders waiAria: https://www.w3.org/TR/wai-aria-practices/#slider +unstyled: /base/react-slider/ --- # Slider @@ -132,21 +133,6 @@ Increasing _x_ by one increases the represented value by factor _2_. {{"demo": "NonLinearSlider.js"}} -## Unstyled - - - -- 📦 [5.6 kB gzipped](https://bundlephobia.com/package/@mui/base@latest) - -The slider also comes with an unstyled version. -It's ideal for doing heavy customizations and minimizing bundle size. - -```js -import SliderUnstyled from '@mui/base/SliderUnstyled'; -``` - -{{"demo": "UnstyledSlider.js"}} - ## Accessibility (WAI-ARIA: https://www.w3.org/TR/wai-aria-practices/#slider) diff --git a/docs/pages/api-docs/slider-unstyled.js b/docs/pages/api-docs/slider-unstyled.js deleted file mode 100644 index 5c255387f8e51f..00000000000000 --- a/docs/pages/api-docs/slider-unstyled.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import ApiPage from 'docs/src/modules/components/ApiPage'; -import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './slider-unstyled.json'; - -export default function Page(props) { - const { descriptions, pageContent } = props; - return ; -} - -Page.getInitialProps = () => { - const req = require.context( - 'docs/translations/api-docs/slider-unstyled', - false, - /slider-unstyled.*.json$/, - ); - const descriptions = mapApiPageTranslations(req); - - return { - descriptions, - pageContent: jsonPageContent, - }; -}; diff --git a/docs/pages/api-docs/slider-unstyled.json b/docs/pages/api-docs/slider-unstyled.json deleted file mode 100644 index aefda45f07d4c3..00000000000000 --- a/docs/pages/api-docs/slider-unstyled.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "props": { - "aria-label": { "type": { "name": "custom", "description": "string" } }, - "aria-labelledby": { "type": { "name": "string" } }, - "aria-valuetext": { "type": { "name": "custom", "description": "string" } }, - "classes": { "type": { "name": "object" } }, - "component": { "type": { "name": "elementType" } }, - "components": { - "type": { - "name": "shape", - "description": "{ Input?: elementType, Mark?: elementType, MarkLabel?: elementType, Rail?: elementType, Root?: elementType, Thumb?: elementType, Track?: elementType, ValueLabel?: elementType }" - }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ input?: object, mark?: object, markLabel?: object, rail?: object, root?: object, thumb?: object, track?: object, valueLabel?: { className?: string, components?: { Root?: elementType }, style?: object, value?: Array<number>
| number, valueLabelDisplay?: 'auto'
| 'off'
| 'on' } }" - }, - "default": "{}" - }, - "defaultValue": { - "type": { "name": "union", "description": "Array<number>
| number" } - }, - "disabled": { "type": { "name": "bool" } }, - "disableSwap": { "type": { "name": "bool" } }, - "getAriaLabel": { "type": { "name": "func" } }, - "getAriaValueText": { "type": { "name": "func" } }, - "isRtl": { "type": { "name": "bool" } }, - "marks": { - "type": { - "name": "union", - "description": "Array<{ label?: node, value: number }>
| bool" - }, - "default": "false" - }, - "max": { "type": { "name": "number" }, "default": "100" }, - "min": { "type": { "name": "number" }, "default": "0" }, - "name": { "type": { "name": "string" } }, - "onChange": { "type": { "name": "func" } }, - "onChangeCommitted": { "type": { "name": "func" } }, - "orientation": { - "type": { "name": "enum", "description": "'horizontal'
| 'vertical'" }, - "default": "'horizontal'" - }, - "scale": { "type": { "name": "func" }, "default": "(x) => x" }, - "step": { "type": { "name": "number" }, "default": "1" }, - "tabIndex": { "type": { "name": "number" } }, - "track": { - "type": { - "name": "enum", - "description": "'inverted'
| 'normal'
| false" - }, - "default": "'normal'" - }, - "value": { - "type": { "name": "union", "description": "Array<number>
| number" } - }, - "valueLabelDisplay": { - "type": { "name": "enum", "description": "'auto'
| 'off'
| 'on'" }, - "default": "'off'" - }, - "valueLabelFormat": { - "type": { "name": "union", "description": "func
| string" }, - "default": "(x) => x" - } - }, - "name": "SliderUnstyled", - "styles": { - "classes": [ - "root", - "marked", - "vertical", - "disabled", - "dragging", - "rail", - "track", - "trackFalse", - "trackInverted", - "thumb", - "active", - "focusVisible", - "valueLabel", - "valueLabelOpen", - "valueLabelCircle", - "valueLabelLabel", - "mark", - "markActive", - "markLabel", - "markLabelActive" - ], - "globalClasses": { - "root": "MuiSlider-root", - "marked": "MuiSlider-marked", - "vertical": "MuiSlider-vertical", - "disabled": "Mui-disabled", - "dragging": "MuiSlider-dragging", - "rail": "MuiSlider-rail", - "track": "MuiSlider-track", - "trackFalse": "MuiSlider-trackFalse", - "trackInverted": "MuiSlider-trackInverted", - "thumb": "MuiSlider-thumb", - "active": "Mui-active", - "focusVisible": "Mui-focusVisible", - "valueLabel": "MuiSlider-valueLabel", - "valueLabelOpen": "MuiSlider-valueLabelOpen", - "valueLabelCircle": "MuiSlider-valueLabelCircle", - "valueLabelLabel": "MuiSlider-valueLabelLabel", - "mark": "MuiSlider-mark", - "markActive": "MuiSlider-markActive", - "markLabel": "MuiSlider-markLabel", - "markLabelActive": "MuiSlider-markLabelActive" - }, - "name": null - }, - "spread": true, - "forwardsRefTo": "HTMLSpanElement", - "filename": "/packages/mui-base/src/SliderUnstyled/SliderUnstyled.js", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/base/api/slider-unstyled.json b/docs/pages/base/api/slider-unstyled.json index b389675e06a67d..def83e5e452bb6 100644 --- a/docs/pages/base/api/slider-unstyled.json +++ b/docs/pages/base/api/slider-unstyled.json @@ -117,6 +117,6 @@ "forwardsRefTo": "HTMLSpanElement", "filename": "/packages/mui-base/src/SliderUnstyled/SliderUnstyled.js", "inheritance": null, - "demos": "", + "demos": "", "cssComponent": false } diff --git a/docs/pages/base/react-slider.js b/docs/pages/base/react-slider.js new file mode 100644 index 00000000000000..8af3db31d4872c --- /dev/null +++ b/docs/pages/base/react-slider.js @@ -0,0 +1,11 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import { + demos, + docs, + demoComponents, +} from 'docs/data/base/components/slider/slider.md?@mui/markdown'; + +export default function Page() { + return ; +} diff --git a/docs/scripts/buildApiUtils.ts b/docs/scripts/buildApiUtils.ts index 703b0371ac2c08..6514a542b755d7 100644 --- a/docs/scripts/buildApiUtils.ts +++ b/docs/scripts/buildApiUtils.ts @@ -116,6 +116,7 @@ const migratedBaseComponents = [ 'OptionUnstyled', 'Portal', 'SelectUnstyled', + 'SliderUnstyled', 'TablePaginationUnstyled', 'TabPanelUnstyled', 'TabsListUnstyled', diff --git a/docs/src/pagesApi.js b/docs/src/pagesApi.js index 1aede10c5423b8..90ed7a1e8f637e 100644 --- a/docs/src/pagesApi.js +++ b/docs/src/pagesApi.js @@ -108,7 +108,6 @@ module.exports = [ { pathname: '/api-docs/skeleton' }, { pathname: '/api-docs/slide' }, { pathname: '/api-docs/slider' }, - { pathname: '/api-docs/slider-unstyled' }, { pathname: '/api-docs/snackbar' }, { pathname: '/api-docs/snackbar-content' }, { pathname: '/api-docs/speed-dial' }, diff --git a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.d.ts b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.d.ts index ffd3d1bd17fe06..76351b512326bc 100644 --- a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.d.ts +++ b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.d.ts @@ -5,11 +5,11 @@ import { SliderUnstyledTypeMap } from './SliderUnstyledProps'; * * Demos: * - * - [Slider](https://mui.com/components/slider/) + * - [Slider](https://mui.com/base/react-slider/) * * API: * - * - [SliderUnstyled API](https://mui.com/api/slider-unstyled/) + * - [SliderUnstyled API](https://mui.com/base/api/slider-unstyled/) */ declare const SliderUnstyled: OverridableComponent;