Skip to content

Commit 1ddeb32

Browse files
committed
fix(VSlider): correct display and interaction when reversed or rtl
fixes #18389 fixes #18312
1 parent a62b5d6 commit 1ddeb32

File tree

4 files changed

+19
-28
lines changed

4 files changed

+19
-28
lines changed

packages/vuetify/src/components/VSlider/VSliderThumb.sass

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@
9696

9797
+tools.ltr()
9898
left: calc(var(--v-slider-thumb-position) - var(--v-slider-thumb-size) / 2)
99+
right: unset
99100
+tools.rtl()
101+
left: unset
100102
right: calc(var(--v-slider-thumb-position) - var(--v-slider-thumb-size) / 2)
101103

102104
.v-slider-thumb__label-container

packages/vuetify/src/components/VSlider/VSliderThumb.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export const VSliderThumb = genericComponent<VSliderThumbSlots>()({
6565

6666
setup (props, { slots, emit }) {
6767
const slider = inject(VSliderSymbol)
68-
const { rtlClasses } = useRtl()
68+
const { isRtl, rtlClasses } = useRtl()
6969
if (!slider) throw new Error('[Vuetify] v-slider-thumb must be used inside v-slider or v-range-slider')
7070

7171
const {
@@ -75,12 +75,13 @@ export const VSliderThumb = genericComponent<VSliderThumbSlots>()({
7575
thumbSize,
7676
thumbLabel,
7777
direction,
78+
isReversed,
79+
vertical,
7880
readonly,
7981
elevation,
80-
horizontalDirection,
8182
mousePressed,
8283
decimals,
83-
isNotVerticalAndReversed,
84+
indexFromEnd,
8485
} = slider
8586

8687
const { textColorClasses, textColorStyles } = useTextColor(thumbColor)
@@ -101,7 +102,9 @@ export const VSliderThumb = genericComponent<VSliderThumbSlots>()({
101102
const _step = step.value || 0.1
102103
const steps = (props.max - props.min) / _step
103104
if ([left, right, down, up].includes(e.key)) {
104-
const increase = horizontalDirection.value === 'rtl' ? [left, up] : [right, up]
105+
const increase = vertical.value
106+
? [isRtl.value ? left : right, isReversed.value ? down : up]
107+
: indexFromEnd.value !== isRtl.value ? [left, up] : [right, up]
105108
const direction = increase.includes(e.key) ? 1 : -1
106109
const multiplier = e.shiftKey ? 2 : (e.ctrlKey ? 1 : 0)
107110

@@ -125,7 +128,7 @@ export const VSliderThumb = genericComponent<VSliderThumbSlots>()({
125128
}
126129

127130
useRender(() => {
128-
const positionPercentage = convertToUnit(isNotVerticalAndReversed.value ? 100 - props.position : props.position, '%')
131+
const positionPercentage = convertToUnit(indexFromEnd.value ? 100 - props.position : props.position, '%')
129132
const { elevationClasses } = useElevation(computed(() => !disabled.value ? elevation.value : undefined))
130133

131134
return (

packages/vuetify/src/components/VSlider/VSliderTrack.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
4747

4848
const {
4949
color,
50-
horizontalDirection,
5150
parsedTicks,
5251
rounded,
5352
showTicks,
@@ -58,7 +57,7 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
5857
vertical,
5958
min,
6059
max,
61-
isNotVerticalAndReversed,
60+
indexFromEnd,
6261
} = slider
6362

6463
const { roundedClasses } = useRounded(rounded)
@@ -73,12 +72,12 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
7372
backgroundColorStyles: trackColorStyles,
7473
} = useBackgroundColor(trackColor)
7574

76-
const startDir = computed(() => `inset-${vertical.value ? 'block-end' : 'inline-start'}`)
75+
const startDir = computed(() => `inset-${vertical.value ? 'block' : 'inline'}-${indexFromEnd.value ? 'end' : 'start'}`)
7776
const endDir = computed(() => vertical.value ? 'height' : 'width')
7877

7978
const backgroundStyles = computed(() => {
8079
return {
81-
[startDir.value]: isNotVerticalAndReversed.value && '0%',
80+
[startDir.value]: '0%',
8281
[endDir.value]: '100%',
8382
}
8483
})
@@ -87,7 +86,7 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
8786

8887
const trackFillStyles = computed(() => {
8988
return {
90-
[startDir.value]: isNotVerticalAndReversed.value && convertToUnit(props.start, '%'),
89+
[startDir.value]: convertToUnit(props.start, '%'),
9190
[endDir.value]: convertToUnit(trackFillWidth.value, '%'),
9291
}
9392
})
@@ -98,7 +97,6 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
9897
const ticks = vertical.value ? parsedTicks.value.slice().reverse() : parsedTicks.value
9998

10099
return ticks.map((tick, index) => {
101-
const directionProperty = vertical.value ? 'bottom' : 'margin-inline-start'
102100
const directionValue = tick.value !== min.value && tick.value !== max.value ? convertToUnit(tick.position, '%') : undefined
103101

104102
return (
@@ -112,7 +110,7 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
112110
'v-slider-track__tick--last': tick.value === max.value,
113111
},
114112
]}
115-
style={{ [directionProperty]: directionValue }}
113+
style={{ [startDir.value]: directionValue }}
116114
>
117115
{
118116
(tick.label || slots['tick-label']) && (
@@ -138,7 +136,6 @@ export const VSliderTrack = genericComponent<VSliderTrackSlots>()({
138136
{
139137
'--v-slider-track-size': convertToUnit(trackSize.value),
140138
'--v-slider-tick-size': convertToUnit(tickSize.value),
141-
direction: !vertical.value ? horizontalDirection.value : undefined,
142139
},
143140
props.style,
144141
]}

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ type SliderProvide = {
5252
parsedTicks: Ref<Tick[]>
5353
hasLabels: Ref<boolean>
5454
isReversed: Ref<boolean>
55-
isNotVerticalAndReversed: Ref<boolean>
56-
horizontalDirection: Ref<'ltr' | 'rtl'>
55+
indexFromEnd: Ref<boolean>
5756
}
5857

5958
export const VSliderSymbol: InjectionKey<SliderProvide> = Symbol.for('vuetify:v-slider')
@@ -182,16 +181,7 @@ export const useSlider = ({
182181
const { isRtl } = useRtl()
183182
const isReversed = toRef(props, 'reverse')
184183
const vertical = computed(() => props.direction === 'vertical')
185-
const isNotVerticalAndReversed = computed(() => vertical.value !== isReversed.value)
186-
const horizontalDirection = computed(() => {
187-
let hd: 'ltr' | 'rtl' = isRtl.value ? 'rtl' : 'ltr'
188-
189-
if (isNotVerticalAndReversed.value) {
190-
hd = hd === 'rtl' ? 'ltr' : 'rtl'
191-
}
192-
193-
return hd
194-
})
184+
const indexFromEnd = computed(() => vertical.value !== isReversed.value)
195185

196186
const { min, max, step, decimals, roundValue } = steps
197187

@@ -226,7 +216,7 @@ export const useSlider = ({
226216
// It is possible for left to be NaN, force to number
227217
let clickPos = Math.min(Math.max((clickOffset - trackStart - startOffset.value) / trackLength, 0), 1) || 0
228218

229-
if (isNotVerticalAndReversed.value || horizontalDirection.value === 'rtl') clickPos = 1 - clickPos
219+
if (vertical ? indexFromEnd.value : indexFromEnd.value !== isRtl.value) clickPos = 1 - clickPos
230220

231221
return roundValue(min.value + clickPos * (max.value - min.value))
232222
}
@@ -331,9 +321,8 @@ export const useSlider = ({
331321
direction: toRef(props, 'direction'),
332322
elevation: toRef(props, 'elevation'),
333323
hasLabels,
334-
horizontalDirection,
335324
isReversed,
336-
isNotVerticalAndReversed,
325+
indexFromEnd,
337326
min,
338327
max,
339328
mousePressed,

0 commit comments

Comments
 (0)