From 35de512d05f8b80790f318cbb9c333940e3c3771 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Sun, 5 Jun 2022 22:24:39 +0700 Subject: [PATCH 01/13] fix slider to use joy related classnames --- packages/mui-joy/src/Slider/Slider.tsx | 378 +++++++++++-------- packages/mui-joy/src/Slider/SliderProps.ts | 23 +- packages/mui-joy/src/Slider/sliderClasses.ts | 12 +- 3 files changed, 243 insertions(+), 170 deletions(-) diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index 0c8a74c0afacb8..5131b822412ec7 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -1,41 +1,50 @@ -import PropTypes from 'prop-types'; import * as React from 'react'; +import clsx from 'clsx'; +import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { OverridableComponent } from '@mui/types'; -import { unstable_capitalize as capitalize } from '@mui/utils'; import { shouldForwardProp } from '@mui/system'; -import { - SliderUnstyled, - SliderValueLabelUnstyled, - unstable_composeClasses as composeClasses, -} from '@mui/base'; -import { Theme, useThemeProps } from '../styles'; -import styled from '../styles/styled'; -import shouldSpreadAdditionalProps from '../utils/shouldSpreadAdditionalProps'; +import { useSlider } from '@mui/base/SliderUnstyled'; +import { useThemeProps, styled, Theme } from '../styles'; import sliderClasses, { getSliderUtilityClass } from './sliderClasses'; import { SliderProps, SliderTypeMap } from './SliderProps'; -const useUtilityClasses = (ownerState: SliderProps) => { - const { disabled, orientation, track, size, color } = ownerState; +type OwnerState = SliderProps & { + dragging: boolean; + marked: boolean; +}; + +const valueToPercent = (value: number, min: number, max: number) => + ((value - min) * 100) / (max - min); + +const Identity = (x: any) => x; + +const useUtilityClasses = (ownerState: OwnerState) => { + const { disabled, dragging, marked, orientation, track, classes } = ownerState; const slots = { root: [ 'root', disabled && 'disabled', + dragging && 'dragging', + marked && 'marked', orientation === 'vertical' && 'vertical', track === 'inverted' && 'trackInverted', track === false && 'trackFalse', - color && `color${capitalize(color)}`, - size && `size${capitalize(size)}`, ], rail: ['rail'], track: ['track'], mark: ['mark'], + markActive: ['markActive'], markLabel: ['markLabel'], + markLabelActive: ['markLabelActive'], valueLabel: ['valueLabel'], + valueLabelOpen: ['valueLabelOpen'], thumb: ['thumb', disabled && 'disabled'], + active: ['active'], + focusVisible: ['focusVisible'], }; - return composeClasses(slots, getSliderUtilityClass, {}); + return composeClasses(slots, getSliderUtilityClass, classes); }; const sliderColorVariables = @@ -231,7 +240,7 @@ const SliderMark = styled('span', { // `markActive` is injected by SliderUnstyled, should not spread to DOM shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'markActive', overridesResolver: (props, styles) => styles.mark, -})<{ ownerState: SliderProps; 'data-index': number; style: React.CSSProperties }>( +})<{ ownerState: SliderProps & { markActive: boolean }; 'data-index': number }>( ({ ownerState, ...props }) => { return { position: 'absolute', @@ -256,18 +265,18 @@ const SliderMark = styled('span', { transform: 'translate(-50%, calc(var(--Slider-mark-size) / 2))', ...(props['data-index'] === 0 && { // data-index is from SliderUnstyled - transform: `translate(-50%, min(var(--Slider-mark-size), 3px))`, + transform: `translate(-50%, calc(min(var(--Slider-mark-size), 3px) * -1))`, }), - ...(props.style?.left === '100%' && { + ...(props.style?.bottom === '100%' && { // workaround for detecting last mark - transform: `translate(-50%, calc(var(--Slider-mark-size) * -1 - min(var(--Slider-mark-size), 3px)))`, + transform: `translate(-50%, calc(var(--Slider-mark-size) * 1 + min(var(--Slider-mark-size), 3px)))`, }), }), }; }, ); -const SliderValueLabel = styled(SliderValueLabelUnstyled, { +const SliderValueLabel = styled('span', { name: 'JoySlider', slot: 'ValueLabel', overridesResolver: (props, styles) => styles.valueLabel, @@ -321,8 +330,9 @@ const SliderValueLabel = styled(SliderValueLabelUnstyled, { transform: 'translateY(calc((var(--Slider-thumb-size) + var(--Slider-valueLabel-arrowSize)) * -1)) scale(1)', }, - [`& .${sliderClasses.valueLabelCircle}`]: { - display: 'inline-flex', + '& > span': { + display: 'flex', + alignItems: 'center', zIndex: 1, }, })); @@ -348,21 +358,54 @@ const SliderMarkLabel = styled('span', { position: 'absolute', whiteSpace: 'nowrap', ...(ownerState.orientation === 'horizontal' && { - top: 'calc(50% + (max(var(--Slider-track-size), var(--Slider-thumb-size)) / 2))', + top: 'calc(50% + 4px + (max(var(--Slider-track-size), var(--Slider-thumb-size)) / 2))', transform: 'translateX(-50%)', }), ...(ownerState.orientation === 'vertical' && { - left: 36, + left: 'calc(50% + 8px + (max(var(--Slider-track-size), var(--Slider-thumb-size)) / 2))', transform: 'translateY(50%)', }), })); +const SliderInput = styled('input', { + name: 'JoySlider', + slot: 'Input', + overridesResolver: (props, styles) => styles.input, +})<{ ownerState: SliderProps }>({}); + const Slider = React.forwardRef(function Slider(inProps, ref) { - const props = useThemeProps({ props: inProps, name: 'JoySlider' }); + const props = useThemeProps({ + props: inProps, + name: 'JoySlider', + }); const { - component = 'span', - components = {}, + 'aria-label': ariaLabel, + 'aria-valuetext': ariaValuetext, + className, + component, componentsProps = {}, + classes: classesProp, + disableSwap = false, + disabled = false, + defaultValue, + getAriaLabel, + getAriaValueText, + marks: marksProp = false, + max = 100, + min = 0, + name, + onChange, + onChangeCommitted, + onMouseDown, + orientation = 'horizontal', + scale = Identity, + step = 1, + tabIndex, + track = 'normal', + value: valueProp, + valueLabelDisplay = 'off', + valueLabelFormat = Identity, + isRtl = false, color = 'primary', size = 'md', ...other @@ -370,135 +413,174 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { const ownerState = { ...props, - size, + marks: marksProp, + classes: classesProp, + disabled, + defaultValue, + isRtl, + max, + min, + orientation, + scale, + step, + track, + valueLabelDisplay, + valueLabelFormat, color, + size, + } as OwnerState; + + const { + axisProps, + getRootProps, + getHiddenInputProps, + getThumbProps, + open, + active, + axis, + range, + focusVisible, + dragging, + marks, + values, + trackOffset, + trackLeap, + } = useSlider({ ...ownerState, ref }); + + ownerState.marked = marks.length > 0 && marks.some((mark) => mark.label); + ownerState.dragging = dragging; + + const trackStyle = { + ...axisProps[axis].offset(trackOffset), + ...axisProps[axis].leap(trackLeap), }; + const hiddenInputProps = getHiddenInputProps(); + const classes = useUtilityClasses(ownerState); return ( - + {...getRootProps(onMouseDown ? { onMouseDown } : {})} + as={component} + ownerState={ownerState} + className={clsx(classes.root, className)} + > + + + {marks + .filter((mark) => mark.value >= min && mark.value <= max) + .map((mark, index) => { + const percent = valueToPercent(mark.value, min, max); + const style = axisProps[axis].offset(percent); + + let markActive; + if (track === false) { + markActive = values.indexOf(mark.value) !== -1; + } else { + markActive = + (track === 'normal' && + (range + ? mark.value >= values[0] && mark.value <= values[values.length - 1] + : mark.value <= values[0])) || + (track === 'inverted' && + (range + ? mark.value <= values[0] || mark.value >= values[values.length - 1] + : mark.value >= values[0])); + } + + return ( + + + {mark.label != null ? ( + + {mark.label} + + ) : null} + + ); + })} + {values.map((value, index) => { + const percent = valueToPercent(value, min, max); + const style = axisProps[axis].offset(percent); + return ( + + {/* @ts-expect-error TODO: revisit the null type in useSlider */} + + {valueLabelDisplay !== 'off' ? ( + + {value} + + ) : null} + + ); + })} + ); }) as OverridableComponent; -Slider.propTypes /* remove-proptypes */ = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit TypeScript types and run "yarn proptypes" | - // ---------------------------------------------------------------------- - /** - * @ignore - */ - children: PropTypes.node, - /** - * The color of the component. It supports those theme colors that make sense for this component. - * @default 'primary' - */ - color: PropTypes.oneOf(['danger', 'info', 'neutral', 'primary', 'success', 'warning']), - /** - * The component used for the root node. - * Either a string to use a HTML element or a component. - */ - component: PropTypes.elementType, - /** - * The components used for each slot inside the Slider. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Input: PropTypes.elementType, - Mark: PropTypes.elementType, - MarkLabel: PropTypes.elementType, - Rail: PropTypes.elementType, - Root: PropTypes.elementType, - Thumb: PropTypes.elementType, - Track: PropTypes.elementType, - ValueLabel: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Slider. - * @default {} - */ - componentsProps: PropTypes.shape({ - input: PropTypes.object, - mark: PropTypes.object, - markLabel: PropTypes.object, - rail: PropTypes.object, - root: PropTypes.object, - thumb: PropTypes.object, - track: PropTypes.object, - valueLabel: PropTypes.shape({ - className: PropTypes.string, - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - style: PropTypes.object, - value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]), - valueLabelDisplay: PropTypes.oneOf(['auto', 'off', 'on']), - }), - }), - /** - * The size of the component. - * It accepts theme values between 'sm' and 'lg'. - * @default 'md' - */ - size: PropTypes.oneOf(['sm', 'md', 'lg']), - /** - * The system prop that allows defining system overrides as well as additional CSS styles. - */ - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), -} as any; - export default Slider; diff --git a/packages/mui-joy/src/Slider/SliderProps.ts b/packages/mui-joy/src/Slider/SliderProps.ts index 8c40676b12b84b..105f297a06df03 100644 --- a/packages/mui-joy/src/Slider/SliderProps.ts +++ b/packages/mui-joy/src/Slider/SliderProps.ts @@ -3,9 +3,18 @@ import { OverridableStringUnion, OverrideProps } from '@mui/types'; import * as React from 'react'; import { ColorPaletteProp, SxProps } from '../styles/types'; -export type SliderSlot = 'root' | 'mark' | 'markLabel' | 'rail' | 'track' | 'thumb' | 'valueLabel'; +export type SliderSlot = + | 'root' + | 'mark' + | 'markLabel' + | 'rail' + | 'track' + | 'thumb' + | 'valueLabel' + | 'input'; export interface SliderPropsColorOverrides {} + export interface SliderPropsSizeOverrides {} export type SliderTypeMap< @@ -32,18 +41,6 @@ export type SliderTypeMap< defaultComponent: D; }>; -export type SliderRootProps = NonNullable['root']; -export type SliderMarkProps = NonNullable['mark']; -export type SliderMarkLabelProps = NonNullable< - SliderTypeMap['props']['componentsProps'] ->['markLabel']; -export type SliderRailProps = NonNullable['rail']; -export type SliderTrackProps = NonNullable['track']; -export type SliderThumbProps = NonNullable['thumb']; -export type SliderValueLabelProps = NonNullable< - SliderTypeMap['props']['componentsProps'] ->['valueLabel']; - export type SliderProps< D extends React.ElementType = SliderTypeMap['defaultComponent'], P = { component?: React.ElementType }, diff --git a/packages/mui-joy/src/Slider/sliderClasses.ts b/packages/mui-joy/src/Slider/sliderClasses.ts index cf16691afb96e7..59faaa155be846 100644 --- a/packages/mui-joy/src/Slider/sliderClasses.ts +++ b/packages/mui-joy/src/Slider/sliderClasses.ts @@ -1,4 +1,4 @@ -import { generateUtilityClass, generateUtilityClasses } from '@mui/base'; +import { generateUtilityClass, generateUtilityClasses } from '../className'; export interface SliderClasses { /** Class name applied to the root element. */ @@ -25,10 +25,6 @@ export interface SliderClasses { valueLabel: string; /** Class name applied to the thumb label element if it's open. */ valueLabelOpen: string; - /** Class name applied to the thumb label's circle element. */ - valueLabelCircle: string; - /** Class name applied to the thumb label's label element. */ - valueLabelLabel: string; /** Class name applied to the mark element. */ mark: string; /** Class name applied to the mark element when it is active. */ @@ -58,10 +54,10 @@ export interface SliderClasses { export type SliderClassKey = keyof SliderClasses; export function getSliderUtilityClass(slot: string): string { - return generateUtilityClass('MuiSlider', slot); + return generateUtilityClass('JoySlider', slot); } -const sliderClasses: SliderClasses = generateUtilityClasses('MuiSlider', [ +const sliderClasses: SliderClasses = generateUtilityClasses('JoySlider', [ 'root', 'disabled', 'dragging', @@ -77,8 +73,6 @@ const sliderClasses: SliderClasses = generateUtilityClasses('MuiSlider', [ 'thumb', 'valueLabel', 'valueLabelOpen', - 'valueLabelCircle', - 'valueLabelLabel', 'colorPrimary', 'colorNeutral', 'colorDanger', From f20a399e6ff9884aa579998b2b4b736e3f43b018 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 13:10:54 +0700 Subject: [PATCH 02/13] fix useSlider result types --- packages/mui-base/src/SliderUnstyled/useSlider.ts | 4 ++-- packages/mui-joy/src/Slider/sliderClasses.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-base/src/SliderUnstyled/useSlider.ts b/packages/mui-base/src/SliderUnstyled/useSlider.ts index 0e57074be29cbd..6622a043d93282 100644 --- a/packages/mui-base/src/SliderUnstyled/useSlider.ts +++ b/packages/mui-base/src/SliderUnstyled/useSlider.ts @@ -681,14 +681,14 @@ export default function useSlider(parameters: UseSliderParameters) { return { active, - axis, + axis: axis as keyof typeof axisProps, axisProps, dragging, focusVisible, getHiddenInputProps, getRootProps, getThumbProps, - marks, + marks: marks as Mark[], open, range, trackLeap, diff --git a/packages/mui-joy/src/Slider/sliderClasses.ts b/packages/mui-joy/src/Slider/sliderClasses.ts index 59faaa155be846..393b4630fd7aab 100644 --- a/packages/mui-joy/src/Slider/sliderClasses.ts +++ b/packages/mui-joy/src/Slider/sliderClasses.ts @@ -1,4 +1,4 @@ -import { generateUtilityClass, generateUtilityClasses } from '../className'; +import { generateUtilityClass, generateUtilityClasses } from '@mui/base'; export interface SliderClasses { /** Class name applied to the root element. */ From b947c4d4c7ee22b2794e67999777d253c73b9d41 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 13:37:01 +0700 Subject: [PATCH 03/13] add thumb start, end classname --- packages/mui-joy/src/Slider/Slider.tsx | 24 +++++++++++--------- packages/mui-joy/src/Slider/sliderClasses.ts | 6 +++++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index 5131b822412ec7..6cceeeb47b245d 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -40,6 +40,8 @@ const useUtilityClasses = (ownerState: OwnerState) => { valueLabel: ['valueLabel'], valueLabelOpen: ['valueLabelOpen'], thumb: ['thumb', disabled && 'disabled'], + thumbStart: ['thumbStart'], + thumbEnd: ['thumbEnd'], active: ['active'], focusVisible: ['focusVisible'], }; @@ -306,7 +308,7 @@ const SliderValueLabel = styled('span', { whiteSpace: 'nowrap', fontFamily: theme.vars.fontFamily.body, fontWeight: theme.vars.fontWeight.md, - bottom: '2px', + bottom: 0, transformOrigin: 'bottom center', transform: 'translateY(calc((var(--Slider-thumb-size) + var(--Slider-valueLabel-arrowSize)) * -1)) scale(0)', @@ -320,21 +322,19 @@ const SliderValueLabel = styled('span', { position: 'absolute', content: '""', bottom: 0, - width: 'var(--Slider-valueLabel-arrowSize)', - height: 'var(--Slider-valueLabel-arrowSize)', + border: 'calc(var(--Slider-valueLabel-arrowSize) / 2) solid', + borderColor: theme.vars.palette.background.tooltip, + borderRightColor: 'transparent', + borderBottomColor: 'transparent', + borderLeftColor: 'transparent', left: '50%', - transform: 'translate(-50%, 50%) rotate(45deg)', - backgroundColor: 'inherit', + transform: 'translate(-50%, 100%)', + backgroundColor: 'transparent', }, [`&.${sliderClasses.valueLabelOpen}`]: { transform: 'translateY(calc((var(--Slider-thumb-size) + var(--Slider-valueLabel-arrowSize)) * -1)) scale(1)', }, - '& > span': { - display: 'flex', - alignItems: 'center', - zIndex: 1, - }, })); const SliderMarkLabel = styled('span', { @@ -540,6 +540,8 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { className={clsx(classes.thumb, componentsProps.thumb?.className, { [classes.active]: active === index, [classes.focusVisible]: focusVisible === index, + [classes.thumbStart]: percent === 0, + [classes.thumbEnd]: percent === 100, })} style={{ ...style, @@ -573,7 +575,7 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { open === index || active === index || valueLabelDisplay === 'on', })} > - {value} + {value} ) : null} diff --git a/packages/mui-joy/src/Slider/sliderClasses.ts b/packages/mui-joy/src/Slider/sliderClasses.ts index 393b4630fd7aab..8023a51c4282c0 100644 --- a/packages/mui-joy/src/Slider/sliderClasses.ts +++ b/packages/mui-joy/src/Slider/sliderClasses.ts @@ -21,6 +21,10 @@ export interface SliderClasses { trackInverted: string; /** Class name applied to the thumb element. */ thumb: string; + /** Class name applied to the thumb element if percent is 0. */ + thumbStart: string; + /** Class name applied to the thumb element if percent is 100. */ + thumbEnd: string; /** Class name applied to the thumb label element. */ valueLabel: string; /** Class name applied to the thumb label element if it's open. */ @@ -71,6 +75,8 @@ const sliderClasses: SliderClasses = generateUtilityClasses('JoySlider', [ 'markActive', 'markLabel', 'thumb', + 'thumbStart', + 'thumbEnd', 'valueLabel', 'valueLabelOpen', 'colorPrimary', From c941359f6919dede01977ae9cb0c7e4246302359 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 13:53:09 +0700 Subject: [PATCH 04/13] Add label on edges demo --- .../joy/components/slider/EdgeLabelSlider.js | 43 +++++++++++++++++++ docs/data/joy/components/slider/slider.md | 6 +++ packages/mui-joy/src/Slider/Slider.tsx | 3 +- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 docs/data/joy/components/slider/EdgeLabelSlider.js diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.js b/docs/data/joy/components/slider/EdgeLabelSlider.js new file mode 100644 index 00000000000000..24db15f947a99c --- /dev/null +++ b/docs/data/joy/components/slider/EdgeLabelSlider.js @@ -0,0 +1,43 @@ +import * as React from 'react'; +import Box from '@mui/joy/Box'; +import Slider, { sliderClasses } from '@mui/joy/Slider'; + +function valueText(value) { + return `$${value}`; +} + +export default function EdgeLabelSlider() { + return ( + + + + ); +} diff --git a/docs/data/joy/components/slider/slider.md b/docs/data/joy/components/slider/slider.md index 99a6c74bf56919..8944fe7c8d5ba8 100644 --- a/docs/data/joy/components/slider/slider.md +++ b/docs/data/joy/components/slider/slider.md @@ -31,6 +31,12 @@ You can force the thumb label to be always visible with `valueLabelDisplay="on"` {{"demo": "AlwaysVisibleLabelSlider.js"}} +### Keep label at edges + +For horizontal slider on mobile viewports, the value label might be offset from the track. Apply the style to keep the label at the start/end edges: + +{{"demo": "EdgeLabelSlider.js"}} + ## Range slider By passing an array of values to the `value` prop, you can use the `Slider` to set the start and end of a range. diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index 6cceeeb47b245d..230c0e345a76bd 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -321,9 +321,10 @@ const SliderValueLabel = styled('span', { display: 'var(--Slider-valueLabel-arrowDisplay)', position: 'absolute', content: '""', + color: theme.vars.palette.background.tooltip, bottom: 0, border: 'calc(var(--Slider-valueLabel-arrowSize) / 2) solid', - borderColor: theme.vars.palette.background.tooltip, + borderColor: 'currentColor', borderRightColor: 'transparent', borderBottomColor: 'transparent', borderLeftColor: 'transparent', From 522f7e16f52d7078c9d0030595cce654bad9a7e4 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 14:09:24 +0700 Subject: [PATCH 05/13] add tsx demo --- .../joy/components/slider/EdgeLabelSlider.tsx | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/data/joy/components/slider/EdgeLabelSlider.tsx diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.tsx b/docs/data/joy/components/slider/EdgeLabelSlider.tsx new file mode 100644 index 00000000000000..c7103b828f3ad4 --- /dev/null +++ b/docs/data/joy/components/slider/EdgeLabelSlider.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import Box from '@mui/joy/Box'; +import Slider, { sliderClasses } from '@mui/joy/Slider'; + +function valueText(value: number) { + return `$${value}`; +} + +export default function EdgeLabelSlider() { + return ( + + + + ); +} From 567b574543a23d2394f1abfc9639ab28c01395bb Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 14:10:24 +0700 Subject: [PATCH 06/13] run proptypes --- packages/mui-joy/src/Slider/Slider.tsx | 217 +++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index 230c0e345a76bd..69df395b44911c 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import PropTypes from 'prop-types'; import clsx from 'clsx'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { OverridableComponent } from '@mui/types'; @@ -379,6 +380,7 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { props: inProps, name: 'JoySlider', }); + const { 'aria-label': ariaLabel, 'aria-valuetext': ariaValuetext, @@ -586,4 +588,219 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { ); }) as OverridableComponent; +Slider.propTypes /* remove-proptypes */ = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * The label of the slider. + */ + 'aria-label': PropTypes.string, + /** + * A string value that provides a user-friendly name for the current value of the slider. + */ + 'aria-valuetext': PropTypes.string, + /** + * @ignore + */ + children: PropTypes.node, + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + /** + * @ignore + */ + className: PropTypes.string, + /** + * The color of the component. It supports those theme colors that make sense for this component. + * @default 'primary' + */ + color: PropTypes.oneOf(['danger', 'info', 'neutral', 'primary', 'success', 'warning']), + /** + * The component used for the root node. + * Either a string to use a HTML element or a component. + */ + component: PropTypes.elementType, + /** + * The props used for each slot inside the Slider. + * @default {} + */ + componentsProps: PropTypes.shape({ + input: PropTypes.object, + mark: PropTypes.object, + markLabel: PropTypes.object, + rail: PropTypes.object, + root: PropTypes.object, + thumb: PropTypes.object, + track: PropTypes.object, + valueLabel: PropTypes.shape({ + className: PropTypes.string, + components: PropTypes.shape({ + Root: PropTypes.elementType, + }), + style: PropTypes.object, + value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]), + valueLabelDisplay: PropTypes.oneOf(['auto', 'off', 'on']), + }), + }), + /** + * The default value. Use when the component is not controlled. + */ + defaultValue: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]), + /** + * If `true`, the component is disabled. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, the active thumb doesn't swap when moving pointer over a thumb while dragging another thumb. + * @default false + */ + disableSwap: PropTypes.bool, + /** + * Accepts a function which returns a string value that provides a user-friendly name for the thumb labels of the slider. + * This is important for screen reader users. + * @param {number} index The thumb label's index to format. + * @returns {string} + */ + getAriaLabel: PropTypes.func, + /** + * Accepts a function which returns a string value that provides a user-friendly name for the current value of the slider. + * This is important for screen reader users. + * @param {number} value The thumb label's value to format. + * @param {number} index The thumb label's index to format. + * @returns {string} + */ + getAriaValueText: PropTypes.func, + /** + * Indicates whether the theme context has rtl direction. It is set automatically. + * @default false + */ + isRtl: PropTypes.bool, + /** + * Marks indicate predetermined values to which the user can move the slider. + * If `true` the marks are spaced according the value of the `step` prop. + * If an array, it should contain objects with `value` and an optional `label` keys. + * @default false + */ + marks: PropTypes.oneOfType([ + PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.node, + value: PropTypes.number.isRequired, + }), + ), + PropTypes.bool, + ]), + /** + * The maximum allowed value of the slider. + * Should not be equal to min. + * @default 100 + */ + max: PropTypes.number, + /** + * The minimum allowed value of the slider. + * Should not be equal to max. + * @default 0 + */ + min: PropTypes.number, + /** + * Name attribute of the hidden `input` element. + */ + name: PropTypes.string, + /** + * Callback function that is fired when the slider's value changed. + * + * @param {Event} event The event source of the callback. + * You can pull out the new value by accessing `event.target.value` (any). + * **Warning**: This is a generic event not a change event. + * @param {number | number[]} value The new value. + * @param {number} activeThumb Index of the currently moved thumb. + */ + onChange: PropTypes.func, + /** + * Callback function that is fired when the `mouseup` is triggered. + * + * @param {React.SyntheticEvent | Event} event The event source of the callback. **Warning**: This is a generic event not a change event. + * @param {number | number[]} value The new value. + */ + onChangeCommitted: PropTypes.func, + /** + * @ignore + */ + onMouseDown: PropTypes.func, + /** + * The component orientation. + * @default 'horizontal' + */ + orientation: PropTypes.oneOf(['horizontal', 'vertical']), + /** + * A transformation function, to change the scale of the slider. + * @default (x) => x + */ + scale: PropTypes.func, + /** + * The size of the component. + * It accepts theme values between 'sm' and 'lg'. + * @default 'md' + */ + size: PropTypes.oneOf(['sm', 'md', 'lg']), + /** + * The granularity with which the slider can step through values. (A "discrete" slider.) + * The `min` prop serves as the origin for the valid values. + * We recommend (max - min) to be evenly divisible by the step. + * + * When step is `null`, the thumb can only be slid onto marks provided with the `marks` prop. + * @default 1 + */ + step: PropTypes.number, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Tab index attribute of the hidden `input` element. + */ + tabIndex: PropTypes.number, + /** + * The track presentation: + * + * - `normal` the track will render a bar representing the slider value. + * - `inverted` the track will render a bar representing the remaining slider value. + * - `false` the track will render without a bar. + * @default 'normal' + */ + track: PropTypes.oneOf(['inverted', 'normal', false]), + /** + * The value of the slider. + * For ranged sliders, provide an array with two values. + */ + value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]), + /** + * Controls when the value label is displayed: + * + * - `auto` the value label will display when the thumb is hovered or focused. + * - `on` will display persistently. + * - `off` will never display. + * @default 'off' + */ + valueLabelDisplay: PropTypes.oneOf(['auto', 'off', 'on']), + /** + * The format function the value label's value. + * + * When a function is provided, it should have the following signature: + * + * - {number} value The value label's value to format + * - {number} index The value label's index to format + * @default (x) => x + */ + valueLabelFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), +} as any; + export default Slider; From b6155de3e7282976e403e10ed677fa6bf06352e2 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 14:10:51 +0700 Subject: [PATCH 07/13] remove defaultValue --- docs/data/joy/components/slider/EdgeLabelSlider.js | 1 - docs/data/joy/components/slider/EdgeLabelSlider.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.js b/docs/data/joy/components/slider/EdgeLabelSlider.js index 24db15f947a99c..5a83661fa45605 100644 --- a/docs/data/joy/components/slider/EdgeLabelSlider.js +++ b/docs/data/joy/components/slider/EdgeLabelSlider.js @@ -12,7 +12,6 @@ export default function EdgeLabelSlider() { Date: Tue, 7 Jun 2022 14:13:06 +0700 Subject: [PATCH 08/13] display multiple labels --- docs/data/joy/components/slider/EdgeLabelSlider.js | 4 +++- docs/data/joy/components/slider/EdgeLabelSlider.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.js b/docs/data/joy/components/slider/EdgeLabelSlider.js index 5a83661fa45605..d0f4d702760301 100644 --- a/docs/data/joy/components/slider/EdgeLabelSlider.js +++ b/docs/data/joy/components/slider/EdgeLabelSlider.js @@ -10,8 +10,10 @@ export default function EdgeLabelSlider() { return ( 'Amount'} getAriaValueText={valueText} marks valueLabelDisplay="on" diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.tsx b/docs/data/joy/components/slider/EdgeLabelSlider.tsx index e1dfe98963d1a2..51ac9c289bd434 100644 --- a/docs/data/joy/components/slider/EdgeLabelSlider.tsx +++ b/docs/data/joy/components/slider/EdgeLabelSlider.tsx @@ -10,8 +10,10 @@ export default function EdgeLabelSlider() { return ( 'Amount'} getAriaValueText={valueText} marks valueLabelDisplay="on" From b59f7960ecc7f4bd4e6a044b0a9ba6e2e12103d1 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 7 Jun 2022 14:26:50 +0700 Subject: [PATCH 09/13] refine --- packages/mui-joy/src/Slider/Slider.tsx | 78 ++++++++++++-------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index 69df395b44911c..10d420cfb1d22d 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import { unstable_composeClasses as composeClasses } from '@mui/utils'; +import { + unstable_composeClasses as composeClasses, + unstable_capitalize as capitalize, +} from '@mui/utils'; import { OverridableComponent } from '@mui/types'; -import { shouldForwardProp } from '@mui/system'; import { useSlider } from '@mui/base/SliderUnstyled'; import { useThemeProps, styled, Theme } from '../styles'; import sliderClasses, { getSliderUtilityClass } from './sliderClasses'; @@ -20,7 +22,7 @@ const valueToPercent = (value: number, min: number, max: number) => const Identity = (x: any) => x; const useUtilityClasses = (ownerState: OwnerState) => { - const { disabled, dragging, marked, orientation, track, classes } = ownerState; + const { disabled, dragging, marked, orientation, track, color, size } = ownerState; const slots = { root: [ @@ -31,6 +33,8 @@ const useUtilityClasses = (ownerState: OwnerState) => { orientation === 'vertical' && 'vertical', track === 'inverted' && 'trackInverted', track === false && 'trackFalse', + color && `color${capitalize(color)}`, + size && `size${capitalize(size)}`, ], rail: ['rail'], track: ['track'], @@ -47,7 +51,7 @@ const useUtilityClasses = (ownerState: OwnerState) => { focusVisible: ['focusVisible'], }; - return composeClasses(slots, getSliderUtilityClass, classes); + return composeClasses(slots, getSliderUtilityClass, {}); }; const sliderColorVariables = @@ -240,44 +244,36 @@ const SliderThumb = styled('span', { const SliderMark = styled('span', { name: 'JoySlider', slot: 'Mark', - // `markActive` is injected by SliderUnstyled, should not spread to DOM - shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'markActive', overridesResolver: (props, styles) => styles.mark, -})<{ ownerState: SliderProps & { markActive: boolean }; 'data-index': number }>( - ({ ownerState, ...props }) => { - return { - position: 'absolute', - width: 'var(--Slider-mark-size)', - height: 'var(--Slider-mark-size)', - borderRadius: 'var(--Slider-mark-size)', - backgroundColor: 'var(--Slider-mark-background)', - ...(ownerState.orientation === 'horizontal' && { - top: '50%', - transform: `translate(calc(var(--Slider-mark-size) / -2), -50%)`, - ...(props['data-index'] === 0 && { - // data-index is from SliderUnstyled - transform: `translate(min(var(--Slider-mark-size), 3px), -50%)`, - }), - ...(props.style?.left === '100%' && { - // workaround for detecting last mark - transform: `translate(calc(var(--Slider-mark-size) * -1 - min(var(--Slider-mark-size), 3px)), -50%)`, - }), +})<{ ownerState: SliderProps & { percent: number } }>(({ ownerState }) => { + return { + position: 'absolute', + width: 'var(--Slider-mark-size)', + height: 'var(--Slider-mark-size)', + borderRadius: 'var(--Slider-mark-size)', + backgroundColor: 'var(--Slider-mark-background)', + ...(ownerState.orientation === 'horizontal' && { + top: '50%', + transform: `translate(calc(var(--Slider-mark-size) / -2), -50%)`, + ...(ownerState.percent === 0 && { + transform: `translate(min(var(--Slider-mark-size), 3px), -50%)`, }), - ...(ownerState.orientation === 'vertical' && { - left: '50%', - transform: 'translate(-50%, calc(var(--Slider-mark-size) / 2))', - ...(props['data-index'] === 0 && { - // data-index is from SliderUnstyled - transform: `translate(-50%, calc(min(var(--Slider-mark-size), 3px) * -1))`, - }), - ...(props.style?.bottom === '100%' && { - // workaround for detecting last mark - transform: `translate(-50%, calc(var(--Slider-mark-size) * 1 + min(var(--Slider-mark-size), 3px)))`, - }), + ...(ownerState.percent === 100 && { + transform: `translate(calc(var(--Slider-mark-size) * -1 - min(var(--Slider-mark-size), 3px)), -50%)`, }), - }; - }, -); + }), + ...(ownerState.orientation === 'vertical' && { + left: '50%', + transform: 'translate(-50%, calc(var(--Slider-mark-size) / 2))', + ...(ownerState.percent === 0 && { + transform: `translate(-50%, calc(min(var(--Slider-mark-size), 3px) * -1))`, + }), + ...(ownerState.percent === 100 && { + transform: `translate(-50%, calc(var(--Slider-mark-size) * 1 + min(var(--Slider-mark-size), 3px)))`, + }), + }), + }; +}); const SliderValueLabel = styled('span', { name: 'JoySlider', @@ -342,8 +338,6 @@ const SliderValueLabel = styled('span', { const SliderMarkLabel = styled('span', { name: 'JoySlider', slot: 'MarkLabel', - // `markLabelActive` is injected by SliderUnstyled, should not spread to DOM - shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'markLabelActive', overridesResolver: (props, styles) => styles.markLabel, })<{ ownerState: SliderProps }>(({ theme, ownerState }) => ({ fontFamily: theme.vars.fontFamily.body, @@ -507,7 +501,7 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { Date: Thu, 9 Jun 2022 15:45:11 +0700 Subject: [PATCH 10/13] remove TemplateCollection from regression --- test/regressions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/regressions/index.js b/test/regressions/index.js index e88bdf8240997a..2ea37a842ac992 100644 --- a/test/regressions/index.js +++ b/test/regressions/index.js @@ -28,7 +28,7 @@ importRegressionFixtures.keys().forEach((path) => { }, []); const blacklist = [ - 'docs-joy-templates/TemplateCollection.png', + 'docs-joy-getting-started-templates/TemplateCollection.png', 'docs-joy-core-features-automatic-adjustment/ListThemes.png', 'docs-components-alert/TransitionAlerts.png', // Needs interaction 'docs-components-app-bar/BackToTop.png', // Needs interaction From d0cb560e26c203c04e821c77df16ef865ed91e73 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Thu, 9 Jun 2022 16:05:40 +0700 Subject: [PATCH 11/13] add focus style --- packages/mui-joy/src/Slider/Slider.tsx | 59 ++++++++++++-------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index ffdb4b75e4c252..292f6fc6b27629 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -209,37 +209,34 @@ const SliderThumb = styled('span', { name: 'JoySlider', slot: 'Thumb', overridesResolver: (props, styles) => styles.thumb, -})<{ ownerState: SliderProps }>(({ ownerState }) => { - return [ - { - position: 'absolute', - boxSizing: 'border-box', - outline: 0, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - width: 'var(--Slider-thumb-width)', - height: 'var(--Slider-thumb-size)', - borderRadius: 'var(--Slider-thumb-radius)', - boxShadow: 'var(--Slider-thumb-shadow)', - border: '2px solid', - borderColor: 'var(--Slider-thumb-color)', - color: 'var(--Slider-thumb-color)', - backgroundColor: 'var(--Slider-thumb-background)', - // TODO: discuss the transition approach in a separate PR. This value is copied from mui-material Slider. - transition: - 'box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,left 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,bottom 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms', - ...(ownerState.orientation === 'horizontal' && { - top: '50%', - transform: 'translate(-50%, -50%)', - }), - ...(ownerState.orientation === 'vertical' && { - left: '50%', - transform: 'translate(-50%, 50%)', - }), - }, - ]; -}); +})<{ ownerState: SliderProps }>(({ ownerState, theme }) => ({ + position: 'absolute', + boxSizing: 'border-box', + outline: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: 'var(--Slider-thumb-width)', + height: 'var(--Slider-thumb-size)', + borderRadius: 'var(--Slider-thumb-radius)', + boxShadow: 'var(--Slider-thumb-shadow)', + border: '2px solid', + borderColor: 'var(--Slider-thumb-color)', + color: 'var(--Slider-thumb-color)', + backgroundColor: 'var(--Slider-thumb-background)', + // TODO: discuss the transition approach in a separate PR. This value is copied from mui-material Slider. + transition: + 'box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,left 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,bottom 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms', + [theme.focus.selector]: theme.focus.default, + ...(ownerState.orientation === 'horizontal' && { + top: '50%', + transform: 'translate(-50%, -50%)', + }), + ...(ownerState.orientation === 'vertical' && { + left: '50%', + transform: 'translate(-50%, 50%)', + }), +})); const SliderMark = styled('span', { name: 'JoySlider', From 094a17797b72b85281b08cb44f0d9b9b041956ef Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 13 Jun 2022 11:11:42 +0700 Subject: [PATCH 12/13] remove thumbStart and thumbEnd --- packages/mui-joy/src/Slider/Slider.tsx | 4 ---- packages/mui-joy/src/Slider/sliderClasses.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/mui-joy/src/Slider/Slider.tsx b/packages/mui-joy/src/Slider/Slider.tsx index 292f6fc6b27629..898e08cceb71f2 100644 --- a/packages/mui-joy/src/Slider/Slider.tsx +++ b/packages/mui-joy/src/Slider/Slider.tsx @@ -45,8 +45,6 @@ const useUtilityClasses = (ownerState: OwnerState) => { valueLabel: ['valueLabel'], valueLabelOpen: ['valueLabelOpen'], thumb: ['thumb', disabled && 'disabled'], - thumbStart: ['thumbStart'], - thumbEnd: ['thumbEnd'], active: ['active'], focusVisible: ['focusVisible'], }; @@ -534,8 +532,6 @@ const Slider = React.forwardRef(function Slider(inProps, ref) { className={clsx(classes.thumb, componentsProps.thumb?.className, { [classes.active]: active === index, [classes.focusVisible]: focusVisible === index, - [classes.thumbStart]: percent === 0, - [classes.thumbEnd]: percent === 100, })} style={{ ...style, diff --git a/packages/mui-joy/src/Slider/sliderClasses.ts b/packages/mui-joy/src/Slider/sliderClasses.ts index 8023a51c4282c0..8ab9451a2a23f1 100644 --- a/packages/mui-joy/src/Slider/sliderClasses.ts +++ b/packages/mui-joy/src/Slider/sliderClasses.ts @@ -21,10 +21,6 @@ export interface SliderClasses { trackInverted: string; /** Class name applied to the thumb element. */ thumb: string; - /** Class name applied to the thumb element if percent is 0. */ - thumbStart: string; - /** Class name applied to the thumb element if percent is 100. */ - thumbEnd: string; /** Class name applied to the thumb label element. */ valueLabel: string; /** Class name applied to the thumb label element if it's open. */ From 2efa3737020c24dd973846d4de796f423197d244 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 13 Jun 2022 11:11:54 +0700 Subject: [PATCH 13/13] fix demo --- .../joy/components/slider/EdgeLabelSlider.js | 57 ++++++++++++------- .../joy/components/slider/EdgeLabelSlider.tsx | 57 ++++++++++++------- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.js b/docs/data/joy/components/slider/EdgeLabelSlider.js index d0f4d702760301..e9cff3393c1fe3 100644 --- a/docs/data/joy/components/slider/EdgeLabelSlider.js +++ b/docs/data/joy/components/slider/EdgeLabelSlider.js @@ -3,7 +3,7 @@ import Box from '@mui/joy/Box'; import Slider, { sliderClasses } from '@mui/joy/Slider'; function valueText(value) { - return `$${value}`; + return `${value}°C`; } export default function EdgeLabelSlider() { @@ -11,30 +11,49 @@ export default function EdgeLabelSlider() { 'Amount'} getAriaValueText={valueText} - marks + marks={[ + { + value: 0, + label: '0°C', + }, + { + value: 100, + label: '100°C', + }, + ]} valueLabelDisplay="on" sx={{ - [`& .${sliderClasses.thumbStart} .${sliderClasses.valueLabel}`]: { - left: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width - borderBottomLeftRadius: 0, - '&::before': { - left: 0, - transform: 'translateY(100%)', - borderLeftColor: 'currentColor', + // Need both of the selectors to make it works on the server-side and client-side + [`& [style*="left:0%"], & [style*="left: 0%"]`]: { + [`&.${sliderClasses.markLabel}`]: { + transform: 'none', + }, + [`& .${sliderClasses.valueLabel}`]: { + left: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width + borderBottomLeftRadius: 0, + '&::before': { + left: 0, + transform: 'translateY(100%)', + borderLeftColor: 'currentColor', + }, }, }, - [`& .${sliderClasses.thumbEnd} .${sliderClasses.valueLabel}`]: { - right: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width - borderBottomRightRadius: 0, - '&::before': { - left: 'initial', - right: 0, - transform: 'translateY(100%)', - borderRightColor: 'currentColor', + [`& [style*="left:100%"], & [style*="left: 100%"]`]: { + [`&.${sliderClasses.markLabel}`]: { + transform: 'translateX(-100%)', + }, + [`& .${sliderClasses.valueLabel}`]: { + right: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width + borderBottomRightRadius: 0, + '&::before': { + left: 'initial', + right: 0, + transform: 'translateY(100%)', + borderRightColor: 'currentColor', + }, }, }, }} diff --git a/docs/data/joy/components/slider/EdgeLabelSlider.tsx b/docs/data/joy/components/slider/EdgeLabelSlider.tsx index 51ac9c289bd434..506f92174f7386 100644 --- a/docs/data/joy/components/slider/EdgeLabelSlider.tsx +++ b/docs/data/joy/components/slider/EdgeLabelSlider.tsx @@ -3,7 +3,7 @@ import Box from '@mui/joy/Box'; import Slider, { sliderClasses } from '@mui/joy/Slider'; function valueText(value: number) { - return `$${value}`; + return `${value}°C`; } export default function EdgeLabelSlider() { @@ -11,30 +11,49 @@ export default function EdgeLabelSlider() { 'Amount'} getAriaValueText={valueText} - marks + marks={[ + { + value: 0, + label: '0°C', + }, + { + value: 100, + label: '100°C', + }, + ]} valueLabelDisplay="on" sx={{ - [`& .${sliderClasses.thumbStart} .${sliderClasses.valueLabel}`]: { - left: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width - borderBottomLeftRadius: 0, - '&::before': { - left: 0, - transform: 'translateY(100%)', - borderLeftColor: 'currentColor', + // Need both of the selectors to make it works on the server-side and client-side + [`& [style*="left:0%"], & [style*="left: 0%"]`]: { + [`&.${sliderClasses.markLabel}`]: { + transform: 'none', + }, + [`& .${sliderClasses.valueLabel}`]: { + left: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width + borderBottomLeftRadius: 0, + '&::before': { + left: 0, + transform: 'translateY(100%)', + borderLeftColor: 'currentColor', + }, }, }, - [`& .${sliderClasses.thumbEnd} .${sliderClasses.valueLabel}`]: { - right: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width - borderBottomRightRadius: 0, - '&::before': { - left: 'initial', - right: 0, - transform: 'translateY(100%)', - borderRightColor: 'currentColor', + [`& [style*="left:100%"], & [style*="left: 100%"]`]: { + [`&.${sliderClasses.markLabel}`]: { + transform: 'translateX(-100%)', + }, + [`& .${sliderClasses.valueLabel}`]: { + right: 'calc(var(--Slider-thumb-size) / 2 - 2px)', // 2px is the thumb border width + borderBottomRightRadius: 0, + '&::before': { + left: 'initial', + right: 0, + transform: 'translateY(100%)', + borderRightColor: 'currentColor', + }, }, }, }}