slider icon indicating copy to clipboard operation
slider copied to clipboard

After clicking Handle, click dragging the Track doesn't work twice.

Open R4VANG3R opened this issue 5 years ago • 5 comments

Trying to click and drag on desktop works very unexpectedly. It will sometimes randomly not work.

rc-slider-bug

Version: 8.7.1 && 9.2.3 Tested on the live example

Steps to reproduce:

  1. Click the handle
  2. Click and drag on the track (nothing will happen)
  3. Click and drag on the track again (now it will show cursor: not-allowed but still not do anything)
  4. Click and drag on the track once again (now it will work as expected)

It will sometimes show the cursor: not-allowed on the second step. If that happens it will start working on the next click & drag

R4VANG3R avatar Mar 16 '20 11:03 R4VANG3R

Having the same issue, I hope this gets fixed.

Ed-zo avatar Apr 03 '20 12:04 Ed-zo

I'm having the same issue and it's driving me crazy. I need to fix this for my use case.

tom-leamon avatar Aug 15 '23 18:08 tom-leamon

I was able to fix this issue. I'll share my solution, but I don't plan on making a pull request. Feel free to add it to the project if you want.

ezgif-2-d7804f4576

  1. Update onSliderMouseDown in Slider.tsx
const onSliderMouseDown: React.MouseEventHandler<HTMLDivElement> = (e) => {
    // ... rest of code

    const nextValue = mergedMin + percent * (mergedMax - mergedMin);
    changeToCloseValue(formatValue(nextValue));
    onStartDrag(e, -1, formatValue(nextValue)); // added this line
};
  1. Update onStartMove in useDrag.ts
const onStartMove: OnStartMove = (e, valueIndex, overwriteValue) => { // added overwriteValue prop
    // ... rest of code
    const onMouseMove = (event: MouseEvent | TouchEvent) => {
      // ... rest of code
      updateCacheValueRef.current(valueIndex, offSetPercent, overwriteValue); // pass overwriteValue 
    };
}
  1. Update updateCacheValue in useDrag.ts
const updateCacheValue = (valueIndex: number, offsetPercent: number, overwriteValue?: number) => {
    if (valueIndex === -1) {
      // Determine the closest index to overwriteValue
      const closestIndex = originValues?.reduce((prevIdx, currVal, currIdx) => {
        return Math.abs(currVal - overwriteValue) < Math.abs(originValues[prevIdx] - overwriteValue) ? currIdx : prevIdx
      }, 0)
    
      // Calculate the offset
      let offset = offsetPercent * (max - min)
    
      // Apply the offset to the overwriteValue
      let newValue = overwriteValue + offset
    
      // Format the new value
      newValue = formatValue(newValue)
    
      // Ensure the new value is within the range [min, max]
      newValue = Math.max(min, Math.min(max, newValue))
    
      const cloneCacheValues = [...originValues]
      cloneCacheValues[closestIndex] = newValue
    
      flushValues(cloneCacheValues)
    }
    
    else {
      // ... rest of code
    }
};

tom-leamon avatar Aug 15 '23 23:08 tom-leamon

Update: also got it working for touch:

// Slider.tsx

const handleStartDrag = (
  clientX: number,
  clientY: number,
  originalEvent: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>
) => {
  const { width, height, left, top, bottom, right } =
    containerRef.current.getBoundingClientRect()

  let percent: number
  switch (direction) {
    case 'btt':
      percent = (bottom - clientY) / height
      break

    case 'ttb':
      percent = (clientY - top) / height
      break

    case 'rtl':
      percent = (right - clientX) / width
      break

    default:
      percent = (clientX - left) / width
  }

  const formattedValue = formatValue(mergedMin + percent * (mergedMax - mergedMin))
  changeToCloseValue(formattedValue)
  onStartDrag(originalEvent, -1, formattedValue)
}

const onSliderMouseDown: React.MouseEventHandler<HTMLDivElement> = (e) => {
  e.preventDefault()
  const { clientX, clientY } = e
  handleStartDrag(clientX, clientY, e)
}

const onSliderTouchStart: React.TouchEventHandler<HTMLDivElement> = (e) => {
  e.preventDefault()
  const touch = e.touches[0]
  const { clientX, clientY } = touch
  handleStartDrag(clientX, clientY, e)
}

// inside render function
<SliderContext.Provider value={context}>
    <div
      ref={containerRef}
      className={classNames(prefixCls, className, {
        [`${prefixCls}-disabled`]: disabled,
        [`${prefixCls}-vertical`]: vertical,
        [`${prefixCls}-horizontal`]: !vertical,
        [`${prefixCls}-with-marks`]: markList.length,
      })}
      style={style}
      onMouseDown={onSliderMouseDown}
      onTouchStart={onSliderTouchStart}
    >
    ...

tom-leamon avatar Sep 26 '23 06:09 tom-leamon