diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/css/index.js b/docs/data/base/components/slider/UnstyledSliderBasic/css/index.js new file mode 100644 index 00000000000000..7adf6f79e4c75a --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/css/index.js @@ -0,0 +1,131 @@ +import * as React from 'react'; +import { useTheme, alpha } from '@mui/system'; +import Slider, { sliderClasses } from '@mui/base/Slider'; + +export default function UnstyledSlider() { + return ( +
+ + + +
+ ); +} + +const cyan = { + 50: '#E9F8FC', + 100: '#BDEBF4', + 200: '#99D8E5', + 300: '#66BACC', + 400: '#1F94AD', + 500: '#0D5463', + 600: '#094855', + 700: '#063C47', + 800: '#043039', + 900: '#022127', +}; + +const grey = { + 50: '#f6f8fa', + 100: '#eaeef2', + 200: '#d0d7de', + 300: '#afb8c1', + 400: '#8c959f', + 500: '#6e7781', + 600: '#57606a', + 700: '#424a53', + 800: '#32383f', + 900: '#24292f', +}; + +function useIsDarkMode() { + const theme = useTheme(); + return theme.palette.mode === 'dark'; +} + +function Styles() { + // Replace this with your app logic for determining dark mode + const isDarkMode = useIsDarkMode(); + return ( + + ); +} diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/css/index.tsx b/docs/data/base/components/slider/UnstyledSliderBasic/css/index.tsx new file mode 100644 index 00000000000000..7adf6f79e4c75a --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/css/index.tsx @@ -0,0 +1,131 @@ +import * as React from 'react'; +import { useTheme, alpha } from '@mui/system'; +import Slider, { sliderClasses } from '@mui/base/Slider'; + +export default function UnstyledSlider() { + return ( +
+ + + +
+ ); +} + +const cyan = { + 50: '#E9F8FC', + 100: '#BDEBF4', + 200: '#99D8E5', + 300: '#66BACC', + 400: '#1F94AD', + 500: '#0D5463', + 600: '#094855', + 700: '#063C47', + 800: '#043039', + 900: '#022127', +}; + +const grey = { + 50: '#f6f8fa', + 100: '#eaeef2', + 200: '#d0d7de', + 300: '#afb8c1', + 400: '#8c959f', + 500: '#6e7781', + 600: '#57606a', + 700: '#424a53', + 800: '#32383f', + 900: '#24292f', +}; + +function useIsDarkMode() { + const theme = useTheme(); + return theme.palette.mode === 'dark'; +} + +function Styles() { + // Replace this with your app logic for determining dark mode + const isDarkMode = useIsDarkMode(); + return ( + + ); +} diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/system/index.js b/docs/data/base/components/slider/UnstyledSliderBasic/system/index.js new file mode 100644 index 00000000000000..215236f098aaff --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/system/index.js @@ -0,0 +1,106 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import Slider, { sliderClasses } from '@mui/base/Slider'; + +export default function UnstyledSlider() { + return ( + + + + + ); +} + +const blue = { + 100: '#DAECFF', + 200: '#99CCF3', + 400: '#3399FF', + 300: '#66B2FF', + 500: '#007FFF', + 600: '#0072E5', + 900: '#003A75', +}; + +const grey = { + 50: '#f6f8fa', + 100: '#eaeef2', + 200: '#d0d7de', + 300: '#afb8c1', + 400: '#8c959f', + 500: '#6e7781', + 600: '#57606a', + 700: '#424a53', + 800: '#32383f', + 900: '#24292f', +}; + +const StyledSlider = styled(Slider)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? blue[500] : blue[400]}; + height: 6px; + width: 100%; + padding: 16px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + + &:hover { + opacity: 1; + } + + &.${sliderClasses.disabled} { + pointer-events: none; + cursor: default; + color: ${theme.palette.mode === 'light' ? grey[300] : grey[600]}; + opacity: 0.5; + } + + & .${sliderClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.4; + } + + & .${sliderClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderClasses.thumb} { + position: absolute; + width: 16px; + height: 16px; + margin-left: -6px; + margin-top: -6px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 3px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? blue[400] : blue[300], + 0.15, + )}; + } + + &.${sliderClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? blue[200] : blue[300], + 0.3, + )}; + } + } +`, +); diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/system/index.tsx b/docs/data/base/components/slider/UnstyledSliderBasic/system/index.tsx new file mode 100644 index 00000000000000..215236f098aaff --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/system/index.tsx @@ -0,0 +1,106 @@ +import * as React from 'react'; +import { styled, alpha, Box } from '@mui/system'; +import Slider, { sliderClasses } from '@mui/base/Slider'; + +export default function UnstyledSlider() { + return ( + + + + + ); +} + +const blue = { + 100: '#DAECFF', + 200: '#99CCF3', + 400: '#3399FF', + 300: '#66B2FF', + 500: '#007FFF', + 600: '#0072E5', + 900: '#003A75', +}; + +const grey = { + 50: '#f6f8fa', + 100: '#eaeef2', + 200: '#d0d7de', + 300: '#afb8c1', + 400: '#8c959f', + 500: '#6e7781', + 600: '#57606a', + 700: '#424a53', + 800: '#32383f', + 900: '#24292f', +}; + +const StyledSlider = styled(Slider)( + ({ theme }) => ` + color: ${theme.palette.mode === 'light' ? blue[500] : blue[400]}; + height: 6px; + width: 100%; + padding: 16px 0; + display: inline-block; + position: relative; + cursor: pointer; + touch-action: none; + -webkit-tap-highlight-color: transparent; + + &:hover { + opacity: 1; + } + + &.${sliderClasses.disabled} { + pointer-events: none; + cursor: default; + color: ${theme.palette.mode === 'light' ? grey[300] : grey[600]}; + opacity: 0.5; + } + + & .${sliderClasses.rail} { + display: block; + position: absolute; + width: 100%; + height: 4px; + border-radius: 2px; + background-color: currentColor; + opacity: 0.4; + } + + & .${sliderClasses.track} { + display: block; + position: absolute; + height: 4px; + border-radius: 2px; + background-color: currentColor; + } + + & .${sliderClasses.thumb} { + position: absolute; + width: 16px; + height: 16px; + margin-left: -6px; + margin-top: -6px; + box-sizing: border-box; + border-radius: 50%; + outline: 0; + border: 3px solid currentColor; + background-color: #fff; + + :hover, + &.${sliderClasses.focusVisible} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? blue[400] : blue[300], + 0.15, + )}; + } + + &.${sliderClasses.active} { + box-shadow: 0 0 0 0.25rem ${alpha( + theme.palette.mode === 'light' ? blue[200] : blue[300], + 0.3, + )}; + } + } +`, +); diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/system/index.tsx.preview b/docs/data/base/components/slider/UnstyledSliderBasic/system/index.tsx.preview new file mode 100644 index 00000000000000..d326ff94b11db6 --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/system/index.tsx.preview @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/tailwind/index.js b/docs/data/base/components/slider/UnstyledSliderBasic/tailwind/index.js new file mode 100644 index 00000000000000..8b6681e97e3b3d --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/tailwind/index.js @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { useTheme } from '@mui/system'; +import Slider from '@mui/base/Slider'; + +function useIsDarkMode() { + const theme = useTheme(); + return theme.palette.mode === 'dark'; +} + +export default function UnstyledSliderBasic() { + // Replace this with your app logic for determining dark mode + const isDarkMode = useIsDarkMode(); + + return ( +
+ ({ + className: `h-1.5 w-full py-4 inline-block relative touch-none ${ + disabled + ? 'opacity-50 cursor-default pointer-events-none text-slate-300 dark:text-slate-600' + : 'hover:opacity-100 cursor-pointer text-purple-500 dark:text-purple-400' + }`, + }), + rail: { + className: 'block absolute w-full h-1 rounded-sm bg-current opacity-40', + }, + track: { className: 'block absolute h-1 rounded-sm bg-current' }, + thumb: (_, { active, focused }) => ({ + className: `absolute w-4 h-4 -ml-1.5 -mt-1.5 box-border rounded-full outline-0 border-3 border-solid border-current bg-white hover:shadow-outline-purple ${ + focused || active ? 'shadow-outline-purple' : '' + }`, + }), + }} + defaultValue={10} + /> + ({ + className: `h-1.5 w-full py-4 inline-block relative touch-none ${ + disabled + ? 'opacity-50 cursor-default pointer-events-none text-slate-300 dark:text-slate-600' + : 'hover:opacity-100 cursor-pointer text-purple-500 dark:text-purple-400' + }`, + }), + rail: { + className: 'block absolute w-full h-1 rounded-sm bg-current opacity-40', + }, + track: { className: 'block absolute h-1 rounded-sm bg-current' }, + thumb: (_, { active, focused }) => ({ + className: `absolute w-4 h-4 -ml-1.5 -mt-1.5 box-border rounded-full outline-0 border-3 border-solid border-current bg-white hover:shadow-outline-purple ${ + focused || active ? 'shadow-outline-purple' : '' + }`, + }), + }} + defaultValue={10} + disabled + /> +
+ ); +} diff --git a/docs/data/base/components/slider/UnstyledSliderBasic/tailwind/index.tsx b/docs/data/base/components/slider/UnstyledSliderBasic/tailwind/index.tsx new file mode 100644 index 00000000000000..8b6681e97e3b3d --- /dev/null +++ b/docs/data/base/components/slider/UnstyledSliderBasic/tailwind/index.tsx @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { useTheme } from '@mui/system'; +import Slider from '@mui/base/Slider'; + +function useIsDarkMode() { + const theme = useTheme(); + return theme.palette.mode === 'dark'; +} + +export default function UnstyledSliderBasic() { + // Replace this with your app logic for determining dark mode + const isDarkMode = useIsDarkMode(); + + return ( +
+ ({ + className: `h-1.5 w-full py-4 inline-block relative touch-none ${ + disabled + ? 'opacity-50 cursor-default pointer-events-none text-slate-300 dark:text-slate-600' + : 'hover:opacity-100 cursor-pointer text-purple-500 dark:text-purple-400' + }`, + }), + rail: { + className: 'block absolute w-full h-1 rounded-sm bg-current opacity-40', + }, + track: { className: 'block absolute h-1 rounded-sm bg-current' }, + thumb: (_, { active, focused }) => ({ + className: `absolute w-4 h-4 -ml-1.5 -mt-1.5 box-border rounded-full outline-0 border-3 border-solid border-current bg-white hover:shadow-outline-purple ${ + focused || active ? 'shadow-outline-purple' : '' + }`, + }), + }} + defaultValue={10} + /> + ({ + className: `h-1.5 w-full py-4 inline-block relative touch-none ${ + disabled + ? 'opacity-50 cursor-default pointer-events-none text-slate-300 dark:text-slate-600' + : 'hover:opacity-100 cursor-pointer text-purple-500 dark:text-purple-400' + }`, + }), + rail: { + className: 'block absolute w-full h-1 rounded-sm bg-current opacity-40', + }, + track: { className: 'block absolute h-1 rounded-sm bg-current' }, + thumb: (_, { active, focused }) => ({ + className: `absolute w-4 h-4 -ml-1.5 -mt-1.5 box-border rounded-full outline-0 border-3 border-solid border-current bg-white hover:shadow-outline-purple ${ + focused || active ? 'shadow-outline-purple' : '' + }`, + }), + }} + defaultValue={10} + disabled + /> +
+ ); +} diff --git a/docs/data/base/components/slider/slider.md b/docs/data/base/components/slider/slider.md index 8cb23d347d6877..e641aa37b84368 100644 --- a/docs/data/base/components/slider/slider.md +++ b/docs/data/base/components/slider/slider.md @@ -43,7 +43,7 @@ export default function MyApp() { The following demo shows how to create and style two basic sliders. Notice that both are set to a default value of 10 with the `defaultValue` prop, and the second slider cannot be adjusted due to the `disabled` prop: -{{"demo": "UnstyledSlider.js", "defaultCodeOpen": false}} +{{"demo": "UnstyledSliderBasic", "defaultCodeOpen": false}} ### Anatomy diff --git a/docs/data/base/components/tabs/UnstyledTabsRouting.js b/docs/data/base/components/tabs/UnstyledTabsRouting.js index f194f133d922da..e3e4732e1549a3 100644 --- a/docs/data/base/components/tabs/UnstyledTabsRouting.js +++ b/docs/data/base/components/tabs/UnstyledTabsRouting.js @@ -125,36 +125,7 @@ const RouterLink = React.forwardRef(function RouterLink(props, ref) { }); RouterLink.propTypes = { - ownerState: PropTypes.shape({ - action: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ - current: PropTypes.shape({ - focusVisible: PropTypes.func.isRequired, - }), - }), - ]), - active: PropTypes.bool.isRequired, - children: PropTypes.node, - className: PropTypes.string, - disabled: PropTypes.bool.isRequired, - focusableWhenDisabled: PropTypes.bool, - highlighted: PropTypes.bool.isRequired, - href: PropTypes.string, - onChange: PropTypes.func, - onFocusVisible: PropTypes.func, - selected: PropTypes.bool.isRequired, - slotProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), - slots: PropTypes.shape({ - root: PropTypes.elementType, - }), - tabIndex: PropTypes.number, - to: PropTypes.string, - type: PropTypes.oneOf(['button', 'reset', 'submit']), - value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - }).isRequired, + ownerState: PropTypes.object.isRequired, }; const StyledTab = styled(Tab)` diff --git a/docs/scripts/formattedTSDemos.js b/docs/scripts/formattedTSDemos.js index eb1d5ef79267a6..86245e2f386a88 100644 --- a/docs/scripts/formattedTSDemos.js +++ b/docs/scripts/formattedTSDemos.js @@ -102,7 +102,7 @@ async function transpileFile(tsxPath, program) { const propTypesAST = typescriptToProptypes.parseFromProgram(tsxPath, program, { shouldResolveObject: ({ name }) => { - if (name === 'classes') { + if (name === 'classes' || name === 'ownerState') { return false; } diff --git a/docs/tailwind.config.js b/docs/tailwind.config.js index bbafda154a4c66..46893e46d89c7c 100644 --- a/docs/tailwind.config.js +++ b/docs/tailwind.config.js @@ -10,7 +10,10 @@ module.exports = { theme: { extend: { boxShadow: { - 'outline-purple': '0 0 0 3px #c084fc', + 'outline-purple': '0 0 0 4px rgba(192, 132, 252, 0.25)', + }, + border: { + 3: '3px', }, }, }, diff --git a/packages/mui-base/src/Slider/Slider.tsx b/packages/mui-base/src/Slider/Slider.tsx index 06e866e046abc0..518112f0db7800 100644 --- a/packages/mui-base/src/Slider/Slider.tsx +++ b/packages/mui-base/src/Slider/Slider.tsx @@ -91,7 +91,10 @@ const Slider = React.forwardRef(function Slider = { + const partialOwnerState: Omit< + SliderOwnerState, + 'focusedThumbIndex' | 'activeThumbIndex' | 'marked' | 'dragging' + > = { ...props, marks: marksProp, disabled, @@ -129,6 +132,7 @@ const Slider = React.forwardRef(function Slider 0 && marks.some((mark) => mark.label), dragging, focusedThumbIndex, + activeThumbIndex: active, }; const classes = useUtilityClasses(ownerState); diff --git a/packages/mui-base/src/Slider/Slider.types.ts b/packages/mui-base/src/Slider/Slider.types.ts index 2cccc25e6a8639..8c3280d3e8f21d 100644 --- a/packages/mui-base/src/Slider/Slider.types.ts +++ b/packages/mui-base/src/Slider/Slider.types.ts @@ -12,6 +12,7 @@ export type SliderOwnerState = Simplify< SliderOwnProps & { disabled: boolean; focusedThumbIndex: number; + activeThumbIndex: number; isRtl: boolean; max: number; min: number;