Skip to content

Commit 0996a0d

Browse files
authored
feat: update track fill and thumb position on value change (#10954)
1 parent fc0b528 commit 0996a0d

File tree

10 files changed

+440
-31
lines changed

10 files changed

+440
-31
lines changed

dev/range-slider.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Range Slider</title>
8+
<script type="module" src="./common.js"></script>
9+
</head>
10+
<body>
11+
<vaadin-range-slider></vaadin-range-slider>
12+
13+
<script type="module">
14+
import '@vaadin/slider/vaadin-range-slider.js';
15+
</script>
16+
</body>
17+
</html>

dev/slider.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Slider</title>
88
<script type="module" src="./common.js"></script>
9+
</head>
10+
<body>
11+
<vaadin-slider></vaadin-slider>
12+
913
<script type="module">
1014
import '@vaadin/slider';
1115
</script>
12-
</head>
13-
<body>
14-
<vaadin-slider min="0" max="100" value="50"></vaadin-slider>
1516
</body>
1617
</html>

packages/slider/src/styles/vaadin-slider-base-styles.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,49 @@ import { css } from 'lit';
88

99
export const sliderStyles = css`
1010
:host {
11-
display: block;
11+
display: inline-flex;
12+
align-items: center;
13+
box-sizing: border-box;
14+
position: relative;
15+
width: 100%;
16+
height: var(--_thumb-size);
17+
user-select: none;
18+
-webkit-user-select: none;
19+
border-radius: var(--vaadin-slider-track-border-radius, var(--vaadin-radius-m));
20+
--_thumb-size: var(--vaadin-slider-thumb-size, 1lh);
21+
--_track-size: var(--vaadin-slider-track-size, 0.25lh);
1222
}
1323
1424
:host([hidden]) {
1525
display: none !important;
1626
}
27+
28+
[part='track'] {
29+
box-sizing: border-box;
30+
position: absolute;
31+
height: var(--_track-size);
32+
width: 100%;
33+
background: var(--vaadin-slider-track-background, var(--vaadin-background-container));
34+
border-radius: inherit;
35+
}
36+
37+
[part='track-fill'] {
38+
box-sizing: border-box;
39+
position: absolute;
40+
height: var(--_track-size);
41+
background: var(--vaadin-slider-fill-background, var(--vaadin-text-color));
42+
border-start-start-radius: inherit;
43+
border-end-start-radius: inherit;
44+
}
45+
46+
[part~='thumb'] {
47+
position: absolute;
48+
box-sizing: border-box;
49+
width: var(--_thumb-size);
50+
height: var(--_thumb-size);
51+
transform: translateX(-50%);
52+
background: var(--vaadin-slider-fill-background, var(--vaadin-text-color));
53+
border-radius: 50%;
54+
touch-action: none;
55+
}
1756
`;

packages/slider/src/vaadin-range-slider.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
55
*/
66
import { html, LitElement } from 'lit';
7+
import { styleMap } from 'lit/directives/style-map.js';
78
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
89
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
910
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
@@ -42,7 +43,7 @@ class RangeSlider extends SliderMixin(ElementMixin(ThemableMixin(PolylitMixin(Lu
4243
*/
4344
value: {
4445
type: Array,
45-
value: () => [],
46+
value: () => [0, 100],
4647
notify: true,
4748
sync: true,
4849
},
@@ -51,14 +52,43 @@ class RangeSlider extends SliderMixin(ElementMixin(ThemableMixin(PolylitMixin(Lu
5152

5253
/** @protected */
5354
render() {
55+
const [startValue, endValue] = this.__value;
56+
57+
const startPercent = this.__getPercentFromValue(startValue);
58+
const endPercent = this.__getPercentFromValue(endValue);
59+
5460
return html`
5561
<div part="track">
56-
<div part="track-fill"></div>
62+
<div
63+
part="track-fill"
64+
style="${styleMap({
65+
insetInlineStart: `${startPercent}%`,
66+
insetInlineEnd: `${100 - endPercent}%`,
67+
})}"
68+
></div>
5769
</div>
58-
<div part="thumb thumb-start"></div>
59-
<div part="thumb thumb-end"></div>
70+
<div part="thumb thumb-start" style="${styleMap({ insetInlineStart: `${startPercent}%` })}"></div>
71+
<div part="thumb thumb-end" style="${styleMap({ insetInlineStart: `${endPercent}%` })}"></div>
6072
`;
6173
}
74+
75+
constructor() {
76+
super();
77+
78+
this.__value = [...this.value];
79+
}
80+
81+
/** @protected */
82+
updated(props) {
83+
super.updated(props);
84+
85+
if (props.has('value') || props.has('min') || props.has('max')) {
86+
const value = Array.isArray(this.value) ? this.value : [];
87+
value.forEach((value, idx) => {
88+
this.__updateValue(value, idx);
89+
});
90+
}
91+
}
6292
}
6393

6494
defineCustomElement(RangeSlider);

packages/slider/src/vaadin-slider-mixin.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ export const SliderMixin = (superClass) =>
1616
*/
1717
min: {
1818
type: Number,
19+
sync: true,
1920
},
2021

2122
/**
2223
* The maximum allowed value.
2324
*/
2425
max: {
2526
type: Number,
27+
sync: true,
2628
},
2729

2830
/**
@@ -31,6 +33,62 @@ export const SliderMixin = (superClass) =>
3133
step: {
3234
type: Number,
3335
},
36+
37+
/** @private */
38+
__value: {
39+
type: Array,
40+
sync: true,
41+
},
42+
};
43+
}
44+
45+
constructor() {
46+
super();
47+
48+
this.__thumbIndex = 0;
49+
}
50+
51+
/**
52+
* @param {number} value
53+
* @param {number} index
54+
* @private
55+
*/
56+
__updateValue(value, index = this.__thumbIndex) {
57+
const { min, max } = this.__getConstraints();
58+
const step = this.step || 1;
59+
60+
const minValue = this.__value[index - 1] || min;
61+
const maxValue = this.__value[index + 1] || max;
62+
63+
const safeValue = Math.min(Math.max(value, minValue), maxValue);
64+
65+
const offset = safeValue - min;
66+
const nearestOffset = Math.round(offset / step) * step;
67+
const nearestValue = min + nearestOffset;
68+
69+
const newValue = Math.round(nearestValue);
70+
71+
this.__value = this.__value.with(index, newValue);
72+
}
73+
74+
/**
75+
* @return {{ min: number, max: number}}
76+
* @private
77+
*/
78+
__getConstraints() {
79+
return {
80+
min: this.min || 0,
81+
max: this.max || 100,
3482
};
3583
}
84+
85+
/**
86+
* @param {number} value
87+
* @return {number}
88+
* @protected
89+
*/
90+
__getPercentFromValue(value) {
91+
const { min, max } = this.__getConstraints();
92+
return (100 * (value - min)) / (max - min);
93+
}
3694
};

packages/slider/src/vaadin-slider.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
55
*/
66
import { html, LitElement } from 'lit';
7+
import { styleMap } from 'lit/directives/style-map.js';
78
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
89
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
910
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
@@ -42,6 +43,7 @@ class Slider extends SliderMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInj
4243
*/
4344
value: {
4445
type: Number,
46+
value: 0,
4547
notify: true,
4648
sync: true,
4749
},
@@ -50,13 +52,37 @@ class Slider extends SliderMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInj
5052

5153
/** @protected */
5254
render() {
55+
const [value] = this.__value;
56+
const percent = this.__getPercentFromValue(value);
57+
5358
return html`
5459
<div part="track">
55-
<div part="track-fill"></div>
60+
<div
61+
part="track-fill"
62+
style="${styleMap({
63+
insetInlineStart: 0,
64+
insetInlineEnd: `${100 - percent}%`,
65+
})}"
66+
></div>
5667
</div>
57-
<div part="thumb"></div>
68+
<div part="thumb" style="${styleMap({ insetInlineStart: `${percent}%` })}"></div>
5869
`;
5970
}
71+
72+
constructor() {
73+
super();
74+
75+
this.__value = [this.value];
76+
}
77+
78+
/** @protected */
79+
updated(props) {
80+
super.updated(props);
81+
82+
if (props.has('value') || props.has('min') || props.has('max')) {
83+
this.__updateValue(this.value);
84+
}
85+
}
6086
}
6187

6288
defineCustomElement(Slider);

0 commit comments

Comments
 (0)