mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.84k stars 32.25k forks source link

Slider mark click not accurate #35861

Open fakhamatia opened 1 year ago

fakhamatia commented 1 year ago

Duplicates

Latest version

Steps to reproduce 🕹

Link to live example:

Steps:

  1. Click on text of mark
  2. The thumb move top of click position not mark exact value

Current behavior 😯

No response

Expected behavior 🤔

No response

Context 🔦

No response

Your environment 🌎

No response

fakhamatia commented 1 year ago

https://codesandbox.io/s/determined-sunset-5mlnxf?file=/demo.js

Screencast from 01-18-2023 05:52:41 PM.webm

mnajdova commented 1 year ago

The mark labels don't have any click events on them. The click is happening on the slider (as a starting even for the dragging). How did you conclude this is the behavior you are expecting? Did you benchmark some other UI libraries and the behavior differs?

fakhamatia commented 1 year ago

@mnajdova Because it's clickable, When I hover the cursor it changes to pointer. I expect work like fast chose instead moving mouse to find right spot, for values most use. I see this in noUiSlider

ptudan commented 1 year ago

When I click on the mark, I expect the value of the slider to be set to exactly the value passed as value in the object in the marks array. I think it is quite odd that it is just a part of the draggable area.

For example

marks = [{value:maxVal/4, label:'25%'}, {value:maxVal/2, label:'50%'} ....]

I want to get exact percentages when I click on the marks. It is a weird user experience to click on 50% and then have the value range from 47-53% depending on where on 50% you clicked!

Is there any way we can just set the value of the slider to the values passed in marks?

ptudan commented 1 year ago

Relevant code snippet to change would be found here I think:

https://github.com/mui/material-ui/blob/master/packages/mui-base/src/SliderUnstyled/SliderUnstyled.tsx#L236

I'm not at all familiar with the internals of MUI so I think this would take me way longer to figure out than active contributors. However this is super annoying so if it doesn't get picked up for a while then I might come back to this.

secretwpn commented 1 year ago

I think this should be considered as a bug. It actually renders slider marks completely useless for my task (displaying bookmarks on a playback timeline) and I can not imagine any other task really when current behavior would be desirable.

SpandanKar commented 1 year ago

I can confirm this issue exists on MUI Slider, the labels should move to the given position on clicking them. all other libraries out there have a similar implementation.

SaulDope commented 1 year ago

This is an issue for my project as well. Definitely agree that the marks are useless in the current state beyond a visual garnish. If a user clicks on them it is honestly worse UX than not having them. If this issue is not fixed, I would at least like a toggle that makes the marks not selectable and purely a visual aid.

wouterh-dev commented 12 months ago

This can be worked around using:

const ClickableSliderMarkLabel = (props: any) => {
  const { labelOnChange, ownerState, ...restProps } = props;

  const markValue = ownerState?.marks[props?.["data-index"]]?.value;

  const noop = useCallback((e: React.SyntheticEvent) => {
    e.stopPropagation();
  }, []);

  const onClick = useCallback(
    (e: React.SyntheticEvent) => {
      e.preventDefault();
      e.stopPropagation();

      if (markValue != null) {
        labelOnChange(e, markValue);
      }
    },
    [labelOnChange, markValue],
  );

  return (
    <SliderMarkLabel
      onMouseDown={noop}
      onTouchStart={noop}
      onClick={onClick}
      sx={useMemo(() => ({
        ...props?.sx,
        userSelect: "none",
      }), [props?.sx])}
      ownerState={ownerState}
      {...restProps}
    />
  );
};

export const MySlider = (props: React.ComponentProps<typeof Slider>) => {
  return (
    <Slider
      slotProps={{
        markLabel: {
          // @ts-ignore
          labelOnChange: props.onChange,
        },
      }}
      slots={{
        markLabel: ClickableSliderMarkLabel,
      }}
      {...props}
    />
  );
};