Skip to content

Commit 23f8d89

Browse files
committed
fix(VSlider): keep initial offset from thumb centre when dragging
If you start dragging inside the thumb touch target, it shouldn't snap to be centred on the cursor.
1 parent 9c6a4a6 commit 23f8d89

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

packages/vuetify/src/components/VRangeSlider/VRangeSlider.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export default VSlider.extend({
172172
const thumbRef = this.$refs[refName] as HTMLElement
173173
thumbRef.focus()
174174
},
175-
onSliderMouseDown (e: MouseEvent) {
175+
onSliderMouseDown (e: MouseEvent | TouchEvent) {
176176
const value = this.parseMouseMove(e)
177177

178178
this.reevaluateSelected(value)
@@ -182,7 +182,13 @@ export default VSlider.extend({
182182

183183
if ((e.target as Element)?.matches('.v-slider__thumb-container, .v-slider__thumb-container *')) {
184184
this.thumbPressed = true
185+
const domRect = (e.target as Element).getBoundingClientRect()
186+
const touch = 'touches' in e ? e.touches[0] : e
187+
this.startOffset = this.vertical
188+
? touch.clientY - (domRect.top + domRect.height / 2)
189+
: touch.clientX - (domRect.left + domRect.width / 2)
185190
} else {
191+
this.startOffset = 0
186192
window.clearTimeout(this.mouseTimeout)
187193
this.mouseTimeout = window.setTimeout(() => {
188194
this.thumbPressed = true
@@ -216,7 +222,7 @@ export default VSlider.extend({
216222
this.$emit('change', this.internalValue)
217223
}
218224
},
219-
onMouseMove (e: MouseEvent) {
225+
onMouseMove (e: MouseEvent | TouchEvent) {
220226
const value = this.parseMouseMove(e)
221227

222228
if (e.type === 'mousemove') {

packages/vuetify/src/components/VSlider/VSlider.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export default mixins<options &
9898
isFocused: false,
9999
isActive: false,
100100
noClick: false, // Prevent click event if dragging took place, hack for #7915
101+
startOffset: 0,
101102
}),
102103

103104
computed: {
@@ -448,24 +449,30 @@ export default mixins<options &
448449
[direction]: `${value}%`,
449450
}
450451
},
451-
onSliderMouseDown (e: MouseEvent) {
452+
onSliderMouseDown (e: MouseEvent | TouchEvent) {
452453
e.preventDefault()
453454

454455
this.oldValue = this.internalValue
455456
this.isActive = true
456457

457-
const mouseUpOptions = passiveSupported ? { passive: true, capture: true } : true
458-
const mouseMoveOptions = passiveSupported ? { passive: true } : false
459-
460458
if ((e.target as Element)?.matches('.v-slider__thumb-container, .v-slider__thumb-container *')) {
461459
this.thumbPressed = true
460+
const domRect = (e.target as Element).getBoundingClientRect()
461+
const touch = 'touches' in e ? e.touches[0] : e
462+
this.startOffset = this.vertical
463+
? touch.clientY - (domRect.top + domRect.height / 2)
464+
: touch.clientX - (domRect.left + domRect.width / 2)
462465
} else {
466+
this.startOffset = 0
463467
window.clearTimeout(this.mouseTimeout)
464468
this.mouseTimeout = window.setTimeout(() => {
465469
this.thumbPressed = true
466470
}, 300)
467471
}
468472

473+
const mouseUpOptions = passiveSupported ? { passive: true, capture: true } : true
474+
const mouseMoveOptions = passiveSupported ? { passive: true } : false
475+
469476
const isTouchEvent = 'touches' in e
470477

471478
this.onMouseMove(e)
@@ -491,7 +498,7 @@ export default mixins<options &
491498

492499
this.isActive = false
493500
},
494-
onMouseMove (e: MouseEvent) {
501+
onMouseMove (e: MouseEvent | TouchEvent) {
495502
if (e.type === 'mousemove') {
496503
this.thumbPressed = true
497504
}
@@ -532,19 +539,19 @@ export default mixins<options &
532539

533540
this.$emit('focus', e)
534541
},
535-
parseMouseMove (e: MouseEvent) {
542+
parseMouseMove (e: MouseEvent | TouchEvent) {
536543
const start = this.vertical ? 'top' : 'left'
537544
const length = this.vertical ? 'height' : 'width'
538545
const click = this.vertical ? 'clientY' : 'clientX'
539546

540547
const {
541548
[start]: trackStart,
542549
[length]: trackLength,
543-
} = this.$refs.track.getBoundingClientRect() as any
544-
const clickOffset = 'touches' in e ? (e as any).touches[0][click] : e[click] // Can we get rid of any here?
550+
} = this.$refs.track.getBoundingClientRect()
551+
const clickOffset = 'touches' in e ? e.touches[0][click] : e[click]
545552

546553
// It is possible for left to be NaN, force to number
547-
let clickPos = Math.min(Math.max((clickOffset - trackStart) / trackLength, 0), 1) || 0
554+
let clickPos = Math.min(Math.max((clickOffset - trackStart - this.startOffset) / trackLength, 0), 1) || 0
548555

549556
if (this.vertical) clickPos = 1 - clickPos
550557
if (this.$vuetify.rtl) clickPos = 1 - clickPos

0 commit comments

Comments
 (0)