@vaadin/slider 25.1.0-alpha3 → 25.1.0-alpha4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -8
- package/src/styles/vaadin-slider-base-styles.js +45 -25
- package/src/vaadin-range-slider.d.ts +2 -1
- package/src/vaadin-range-slider.js +114 -78
- package/src/vaadin-slider-mixin.d.ts +2 -1
- package/src/vaadin-slider-mixin.js +38 -127
- package/src/vaadin-slider.d.ts +2 -1
- package/src/vaadin-slider.js +62 -15
- package/web-types.json +369 -1
- package/web-types.lit.json +141 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/slider",
|
|
3
|
-
"version": "25.1.0-
|
|
3
|
+
"version": "25.1.0-alpha4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -34,19 +34,21 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
37
|
-
"@vaadin/a11y-base": "25.1.0-
|
|
38
|
-
"@vaadin/component-base": "25.1.0-
|
|
39
|
-
"@vaadin/
|
|
37
|
+
"@vaadin/a11y-base": "25.1.0-alpha4",
|
|
38
|
+
"@vaadin/component-base": "25.1.0-alpha4",
|
|
39
|
+
"@vaadin/field-base": "25.1.0-alpha4",
|
|
40
|
+
"@vaadin/vaadin-themable-mixin": "25.1.0-alpha4",
|
|
40
41
|
"lit": "^3.0.0"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"@vaadin/chai-plugins": "25.1.0-
|
|
44
|
-
"@vaadin/test-runner-commands": "25.1.0-
|
|
45
|
-
"@vaadin/testing-helpers": "^2.0.0"
|
|
44
|
+
"@vaadin/chai-plugins": "25.1.0-alpha4",
|
|
45
|
+
"@vaadin/test-runner-commands": "25.1.0-alpha4",
|
|
46
|
+
"@vaadin/testing-helpers": "^2.0.0",
|
|
47
|
+
"@vaadin/vaadin-lumo-styles": "25.1.0-alpha4"
|
|
46
48
|
},
|
|
47
49
|
"web-types": [
|
|
48
50
|
"web-types.json",
|
|
49
51
|
"web-types.lit.json"
|
|
50
52
|
],
|
|
51
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "4fb917150617231c1acf27faabf386560dcd3bc5"
|
|
52
54
|
}
|
|
@@ -8,17 +8,11 @@ import { css } from 'lit';
|
|
|
8
8
|
|
|
9
9
|
export const sliderStyles = css`
|
|
10
10
|
:host {
|
|
11
|
-
display: inline-flex;
|
|
12
|
-
align-items: center;
|
|
13
11
|
box-sizing: border-box;
|
|
14
|
-
position: relative;
|
|
15
|
-
width: 100%;
|
|
16
|
-
height: var(--_thumb-size);
|
|
17
12
|
user-select: none;
|
|
18
13
|
-webkit-user-select: none;
|
|
19
|
-
|
|
20
|
-
--_thumb-
|
|
21
|
-
--_track-size: var(--vaadin-slider-track-size, 0.25lh);
|
|
14
|
+
--_thumb-width: var(--vaadin-slider-thumb-width, 1lh);
|
|
15
|
+
--_thumb-height: var(--vaadin-slider-thumb-height, 1lh);
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
:host([hidden]) {
|
|
@@ -36,32 +30,51 @@ export const sliderStyles = css`
|
|
|
36
30
|
|
|
37
31
|
:host([readonly]) {
|
|
38
32
|
--vaadin-slider-fill-background: var(--vaadin-background-color);
|
|
33
|
+
--_outline-style: dashed;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#controls {
|
|
37
|
+
grid-area: input;
|
|
38
|
+
display: inline-grid;
|
|
39
|
+
align-items: center;
|
|
40
|
+
width: var(--vaadin-field-default-width, 12em);
|
|
41
|
+
max-width: 100%;
|
|
42
|
+
min-width: 100%;
|
|
43
|
+
min-height: var(--_thumb-height);
|
|
44
|
+
--_track-width: calc(100% - var(--_thumb-width));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:host([has-label]) #controls {
|
|
48
|
+
border-block: var(--vaadin-input-field-border-width, 1px) solid transparent;
|
|
49
|
+
padding-block: var(--vaadin-padding-block-container);
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
[part='track'] {
|
|
42
53
|
box-sizing: border-box;
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
grid-row: 1;
|
|
55
|
+
grid-column: track-start / track-end;
|
|
56
|
+
display: grid;
|
|
57
|
+
grid-template-columns: subgrid;
|
|
58
|
+
align-items: center;
|
|
45
59
|
width: 100%;
|
|
60
|
+
height: var(--vaadin-slider-track-height, 0.25lh);
|
|
46
61
|
background: var(--vaadin-slider-track-background, var(--vaadin-background-container));
|
|
47
|
-
border-radius:
|
|
62
|
+
border-radius: var(--vaadin-slider-track-border-radius, var(--vaadin-radius-m));
|
|
48
63
|
}
|
|
49
64
|
|
|
50
65
|
[part='track-fill'] {
|
|
51
66
|
box-sizing: border-box;
|
|
52
|
-
|
|
53
|
-
height:
|
|
67
|
+
grid-column: fill-start / fill-end;
|
|
68
|
+
height: 100%;
|
|
54
69
|
background: var(--vaadin-slider-fill-background, var(--vaadin-text-color));
|
|
55
|
-
border-start-start-radius: inherit;
|
|
56
|
-
border-end-start-radius: inherit;
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
[part~='thumb'] {
|
|
60
|
-
position: absolute;
|
|
61
73
|
box-sizing: border-box;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
grid-row: 1;
|
|
75
|
+
grid-column: thumb1;
|
|
76
|
+
width: var(--_thumb-width);
|
|
77
|
+
height: var(--_thumb-height);
|
|
65
78
|
background: var(--vaadin-slider-fill-background, var(--vaadin-text-color));
|
|
66
79
|
border-radius: 50%;
|
|
67
80
|
touch-action: none;
|
|
@@ -72,13 +85,20 @@ export const sliderStyles = css`
|
|
|
72
85
|
border: dashed 1px var(--vaadin-border-color);
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
|
|
88
|
+
:host([readonly]) [part='track-fill'] {
|
|
89
|
+
border-inline-end: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
::slotted(input) {
|
|
77
|
-
|
|
93
|
+
grid-row: 1;
|
|
94
|
+
grid-column: track-start / track-end;
|
|
95
|
+
appearance: none;
|
|
96
|
+
width: 100%;
|
|
97
|
+
height: 100%;
|
|
78
98
|
font: inherit;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
margin: 0;
|
|
100
|
+
background: transparent;
|
|
101
|
+
outline: 0;
|
|
102
|
+
-webkit-tap-highlight-color: transparent;
|
|
83
103
|
}
|
|
84
104
|
`;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
|
|
7
7
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
8
|
+
import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
|
|
8
9
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
9
10
|
import { SliderMixin } from './vaadin-slider-mixin.js';
|
|
10
11
|
|
|
@@ -39,7 +40,7 @@ export interface RangeSliderEventMap extends HTMLElementEventMap, RangeSliderCus
|
|
|
39
40
|
* @fires {Event} change - Fired when the user commits a value change.
|
|
40
41
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
41
42
|
*/
|
|
42
|
-
declare class RangeSlider extends SliderMixin(FocusMixin(ThemableMixin(ElementMixin(HTMLElement)))) {
|
|
43
|
+
declare class RangeSlider extends FieldMixin(SliderMixin(FocusMixin(ThemableMixin(ElementMixin(HTMLElement))))) {
|
|
43
44
|
/**
|
|
44
45
|
* The value of the slider.
|
|
45
46
|
*/
|
|
@@ -11,6 +11,8 @@ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
|
11
11
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
12
12
|
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
13
13
|
import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
|
|
14
|
+
import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
|
|
15
|
+
import { field } from '@vaadin/field-base/src/styles/field-base-styles.js';
|
|
14
16
|
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
|
|
15
17
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
16
18
|
import { sliderStyles } from './styles/vaadin-slider-base-styles.js';
|
|
@@ -30,12 +32,13 @@ import { SliderMixin } from './vaadin-slider-mixin.js';
|
|
|
30
32
|
* @customElement
|
|
31
33
|
* @extends HTMLElement
|
|
32
34
|
* @mixes ElementMixin
|
|
35
|
+
* @mixes FieldMixin
|
|
33
36
|
* @mixes FocusMixin
|
|
34
37
|
* @mixes SliderMixin
|
|
35
38
|
* @mixes ThemableMixin
|
|
36
39
|
*/
|
|
37
|
-
class RangeSlider extends
|
|
38
|
-
FocusMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))),
|
|
40
|
+
class RangeSlider extends FieldMixin(
|
|
41
|
+
SliderMixin(FocusMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))),
|
|
39
42
|
) {
|
|
40
43
|
static get is() {
|
|
41
44
|
return 'vaadin-range-slider';
|
|
@@ -43,6 +46,7 @@ class RangeSlider extends SliderMixin(
|
|
|
43
46
|
|
|
44
47
|
static get styles() {
|
|
45
48
|
return [
|
|
49
|
+
field,
|
|
46
50
|
sliderStyles,
|
|
47
51
|
css`
|
|
48
52
|
:host([focus-ring][start-focused]) [part~='thumb-start'],
|
|
@@ -51,8 +55,56 @@ class RangeSlider extends SliderMixin(
|
|
|
51
55
|
outline-offset: 1px;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
#controls {
|
|
59
|
+
grid-template-columns:
|
|
60
|
+
[track-start]
|
|
61
|
+
calc(var(--start-value) * var(--_track-width))
|
|
62
|
+
[thumb1]
|
|
63
|
+
0
|
|
64
|
+
[fill-start]
|
|
65
|
+
calc((var(--end-value) - var(--start-value)) * var(--_track-width))
|
|
66
|
+
[fill-end thumb2]
|
|
67
|
+
0
|
|
68
|
+
calc((1 - var(--end-value)) * var(--_track-width))
|
|
69
|
+
var(--_thumb-width)
|
|
70
|
+
[track-end];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[part='track-fill'] {
|
|
74
|
+
margin-inline-start: var(--_thumb-width);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
[part~='thumb-end'] {
|
|
78
|
+
grid-column: thumb2;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
:host([readonly]) [part='track-fill'] {
|
|
82
|
+
border-inline-start: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
::slotted(input:last-of-type) {
|
|
86
|
+
clip-path: inset(
|
|
87
|
+
0 0 0
|
|
88
|
+
clamp(
|
|
89
|
+
0%,
|
|
90
|
+
var(--_thumb-width) / 2 + var(--start-value) * var(--_track-width) +
|
|
91
|
+
(var(--end-value) - var(--start-value)) * var(--_track-width) / 2,
|
|
92
|
+
100%
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
:host([dir='rtl']) ::slotted(input:last-of-type) {
|
|
98
|
+
clip-path: inset(
|
|
99
|
+
0
|
|
100
|
+
clamp(
|
|
101
|
+
0%,
|
|
102
|
+
var(--_thumb-width) / 2 + var(--start-value) * var(--_track-width) +
|
|
103
|
+
(var(--end-value) - var(--start-value)) * var(--_track-width) / 2,
|
|
104
|
+
100%
|
|
105
|
+
)
|
|
106
|
+
0 0
|
|
107
|
+
);
|
|
56
108
|
}
|
|
57
109
|
`,
|
|
58
110
|
];
|
|
@@ -62,6 +114,10 @@ class RangeSlider extends SliderMixin(
|
|
|
62
114
|
return 'sliderComponent';
|
|
63
115
|
}
|
|
64
116
|
|
|
117
|
+
static get lumoInjector() {
|
|
118
|
+
return { ...super.lumoInjector, includeBaseStyles: true };
|
|
119
|
+
}
|
|
120
|
+
|
|
65
121
|
static get properties() {
|
|
66
122
|
return {
|
|
67
123
|
/**
|
|
@@ -84,18 +140,29 @@ class RangeSlider extends SliderMixin(
|
|
|
84
140
|
const endPercent = this.__getPercentFromValue(endValue);
|
|
85
141
|
|
|
86
142
|
return html`
|
|
87
|
-
<div
|
|
88
|
-
<div
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
143
|
+
<div class="vaadin-slider-container">
|
|
144
|
+
<div part="label" @click="${this.focus}">
|
|
145
|
+
<slot name="label"></slot>
|
|
146
|
+
<span part="required-indicator" aria-hidden="true"></span>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div id="controls" style="${styleMap({ '--start-value': startPercent, '--end-value': endPercent })}">
|
|
150
|
+
<div part="track">
|
|
151
|
+
<div part="track-fill"></div>
|
|
152
|
+
</div>
|
|
153
|
+
<div part="thumb thumb-start"></div>
|
|
154
|
+
<div part="thumb thumb-end"></div>
|
|
155
|
+
<slot name="input"></slot>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div part="helper-text">
|
|
159
|
+
<slot name="helper"></slot>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<div part="error-message">
|
|
163
|
+
<slot name="error-message"></slot>
|
|
164
|
+
</div>
|
|
95
165
|
</div>
|
|
96
|
-
<div part="thumb thumb-start" style="${styleMap({ insetInlineStart: `${startPercent}%` })}"></div>
|
|
97
|
-
<div part="thumb thumb-end" style="${styleMap({ insetInlineStart: `${endPercent}%` })}"></div>
|
|
98
|
-
<slot name="input"></slot>
|
|
99
166
|
`;
|
|
100
167
|
}
|
|
101
168
|
|
|
@@ -113,6 +180,7 @@ class RangeSlider extends SliderMixin(
|
|
|
113
180
|
|
|
114
181
|
const inputs = this.querySelectorAll('[slot="input"]');
|
|
115
182
|
this._inputElements = [...inputs];
|
|
183
|
+
this.ariaTarget = this;
|
|
116
184
|
}
|
|
117
185
|
|
|
118
186
|
/**
|
|
@@ -139,7 +207,7 @@ class RangeSlider extends SliderMixin(
|
|
|
139
207
|
.disabled="${this.disabled}"
|
|
140
208
|
tabindex="${this.disabled ? -1 : 0}"
|
|
141
209
|
@keydown="${this.__onKeyDown}"
|
|
142
|
-
@input="${this.
|
|
210
|
+
@input="${this.__onStartInput}"
|
|
143
211
|
@change="${this.__onChange}"
|
|
144
212
|
/>
|
|
145
213
|
<input
|
|
@@ -153,7 +221,7 @@ class RangeSlider extends SliderMixin(
|
|
|
153
221
|
.disabled="${this.disabled}"
|
|
154
222
|
tabindex="${this.disabled ? -1 : 0}"
|
|
155
223
|
@keydown="${this.__onKeyDown}"
|
|
156
|
-
@input="${this.
|
|
224
|
+
@input="${this.__onEndInput}"
|
|
157
225
|
@change="${this.__onChange}"
|
|
158
226
|
/>
|
|
159
227
|
`,
|
|
@@ -191,6 +259,19 @@ class RangeSlider extends SliderMixin(
|
|
|
191
259
|
super.focus(options);
|
|
192
260
|
}
|
|
193
261
|
|
|
262
|
+
/**
|
|
263
|
+
* @protected
|
|
264
|
+
* @override
|
|
265
|
+
*/
|
|
266
|
+
blur() {
|
|
267
|
+
if (this._inputElements) {
|
|
268
|
+
const focusedInput = this._inputElements.find((input) => isElementFocused(input));
|
|
269
|
+
if (focusedInput) {
|
|
270
|
+
focusedInput.blur();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
194
275
|
/**
|
|
195
276
|
* Override method inherited from `FocusMixin` to set
|
|
196
277
|
* state attributes indicating which thumb has focus.
|
|
@@ -206,78 +287,33 @@ class RangeSlider extends SliderMixin(
|
|
|
206
287
|
this.toggleAttribute('end-focused', isElementFocused(this._inputElements[1]));
|
|
207
288
|
}
|
|
208
289
|
|
|
209
|
-
/**
|
|
210
|
-
* @param {PointerEvent} event
|
|
211
|
-
* @private
|
|
212
|
-
*/
|
|
213
|
-
__focusInput(event) {
|
|
214
|
-
const index = this.__getThumbIndex(event);
|
|
215
|
-
this._inputElements[index].focus();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
290
|
/** @private */
|
|
219
291
|
__commitValue() {
|
|
220
292
|
this.value = [...this.__value];
|
|
221
293
|
}
|
|
222
294
|
|
|
223
|
-
/**
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (event.type === 'input') {
|
|
229
|
-
return this._inputElements.indexOf(event.target);
|
|
295
|
+
/** @private */
|
|
296
|
+
__onStartInput(event) {
|
|
297
|
+
// Use second input value as first input max limit
|
|
298
|
+
if (parseFloat(event.target.value) > this.__value[1]) {
|
|
299
|
+
event.target.value = this.__value[1];
|
|
230
300
|
}
|
|
231
301
|
|
|
232
|
-
|
|
302
|
+
const value = event.target.value;
|
|
303
|
+
this.__updateValue(value, 0);
|
|
304
|
+
this.__commitValue();
|
|
233
305
|
}
|
|
234
306
|
|
|
235
|
-
/**
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
__getClosestThumb(event) {
|
|
241
|
-
let closestThumb;
|
|
242
|
-
|
|
243
|
-
// If both thumbs are at the start, use the second thumb,
|
|
244
|
-
// and if both are at tne end, use the first one instead.
|
|
245
|
-
if (this.__value[0] === this.__value[1]) {
|
|
246
|
-
const { min, max } = this.__getConstraints();
|
|
247
|
-
if (this.__value[0] === min) {
|
|
248
|
-
return 1;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (this.__value[0] === max) {
|
|
252
|
-
return 0;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const percent = this.__getEventPercent(event);
|
|
257
|
-
const value = this.__getValueFromPercent(percent);
|
|
258
|
-
|
|
259
|
-
// First thumb position from the "end"
|
|
260
|
-
const index = this.__value.findIndex((v) => value - v < 0);
|
|
261
|
-
|
|
262
|
-
// Pick the first one
|
|
263
|
-
if (index === 0) {
|
|
264
|
-
closestThumb = index;
|
|
265
|
-
} else if (index === -1) {
|
|
266
|
-
// Pick the last one (position is past all the thumbs)
|
|
267
|
-
closestThumb = this.__value.length - 1;
|
|
268
|
-
} else {
|
|
269
|
-
const lastStart = this.__value[index - 1];
|
|
270
|
-
const firstEnd = this.__value[index];
|
|
271
|
-
// Pick the first one from the "start" unless thumbs are stacked on top of each other
|
|
272
|
-
if (Math.abs(lastStart - value) < Math.abs(firstEnd - value)) {
|
|
273
|
-
closestThumb = index - 1;
|
|
274
|
-
} else {
|
|
275
|
-
// Pick the last one from the "end"
|
|
276
|
-
closestThumb = index;
|
|
277
|
-
}
|
|
307
|
+
/** @private */
|
|
308
|
+
__onEndInput(event) {
|
|
309
|
+
// Use first input value as second input min limit
|
|
310
|
+
if (parseFloat(event.target.value) < this.__value[0]) {
|
|
311
|
+
event.target.value = this.__value[0];
|
|
278
312
|
}
|
|
279
313
|
|
|
280
|
-
|
|
314
|
+
const value = event.target.value;
|
|
315
|
+
this.__updateValue(value, 1);
|
|
316
|
+
this.__commitValue();
|
|
281
317
|
}
|
|
282
318
|
|
|
283
319
|
/** @private */
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
7
|
import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
|
|
8
|
+
import type { SlotStylesMixinClass } from '@vaadin/component-base/src/slot-styles-mixin.js';
|
|
8
9
|
|
|
9
10
|
export declare function SliderMixin<T extends Constructor<HTMLElement>>(
|
|
10
11
|
base: T,
|
|
11
|
-
): Constructor<DisabledMixinClass> & Constructor<SliderMixinClass> & T;
|
|
12
|
+
): Constructor<DisabledMixinClass> & Constructor<SliderMixinClass> & Constructor<SlotStylesMixinClass> & T;
|
|
12
13
|
|
|
13
14
|
export declare class SliderMixinClass {
|
|
14
15
|
/**
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
|
|
7
|
+
import { SlotStylesMixin } from '@vaadin/component-base/src/slot-styles-mixin.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @polymerMixin
|
|
10
11
|
* @mixes DisabledMixin
|
|
12
|
+
* @mixes SlotStylesMixin
|
|
11
13
|
*/
|
|
12
14
|
export const SliderMixin = (superClass) =>
|
|
13
|
-
class SliderMixinClass extends DisabledMixin(superClass) {
|
|
15
|
+
class SliderMixinClass extends SlotStylesMixin(DisabledMixin(superClass)) {
|
|
14
16
|
static get properties() {
|
|
15
17
|
return {
|
|
16
18
|
/**
|
|
@@ -56,17 +58,39 @@ export const SliderMixin = (superClass) =>
|
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
/** @protected */
|
|
62
|
+
get slotStyles() {
|
|
63
|
+
const tag = this.localName;
|
|
64
|
+
|
|
65
|
+
return [
|
|
66
|
+
`
|
|
67
|
+
${tag} > input::-webkit-slider-runnable-track {
|
|
68
|
+
height: 100%;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
${tag} > input::-webkit-slider-thumb {
|
|
72
|
+
appearance: none;
|
|
73
|
+
width: var(--_thumb-width);
|
|
74
|
+
height: 100%;
|
|
75
|
+
/* iOS needs these */
|
|
76
|
+
background: transparent;
|
|
77
|
+
box-shadow: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
${tag} > input::-moz-range-thumb {
|
|
81
|
+
border: 0;
|
|
82
|
+
background: transparent;
|
|
83
|
+
width: var(--_thumb-width);
|
|
84
|
+
height: 100%;
|
|
85
|
+
}
|
|
86
|
+
`,
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
59
90
|
constructor() {
|
|
60
91
|
super();
|
|
61
92
|
|
|
62
|
-
this.__onPointerMove = this.__onPointerMove.bind(this);
|
|
63
|
-
this.__onPointerUp = this.__onPointerUp.bind(this);
|
|
64
|
-
|
|
65
|
-
// Use separate mousedown listener for focusing the input, as
|
|
66
|
-
// pointerdown fires too early and the global `keyboardActive`
|
|
67
|
-
// flag isn't updated yet, which incorrectly shows focus-ring
|
|
68
93
|
this.addEventListener('mousedown', (e) => this.__onMouseDown(e));
|
|
69
|
-
this.addEventListener('pointerdown', (e) => this.__onPointerDown(e));
|
|
70
94
|
}
|
|
71
95
|
|
|
72
96
|
/** @protected */
|
|
@@ -76,14 +100,6 @@ export const SliderMixin = (superClass) =>
|
|
|
76
100
|
this.__lastCommittedValue = this.value;
|
|
77
101
|
}
|
|
78
102
|
|
|
79
|
-
/**
|
|
80
|
-
* @param {Event} event
|
|
81
|
-
* @return {number}
|
|
82
|
-
*/
|
|
83
|
-
__getThumbIndex(_event) {
|
|
84
|
-
return 0;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
103
|
/**
|
|
88
104
|
* @param {number} value
|
|
89
105
|
* @param {number} index
|
|
@@ -128,39 +144,8 @@ export const SliderMixin = (superClass) =>
|
|
|
128
144
|
*/
|
|
129
145
|
__getPercentFromValue(value) {
|
|
130
146
|
const { min, max } = this.__getConstraints();
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* @param {number} percent
|
|
136
|
-
* @return {number}
|
|
137
|
-
* @private
|
|
138
|
-
*/
|
|
139
|
-
__getValueFromPercent(percent) {
|
|
140
|
-
const { min, max } = this.__getConstraints();
|
|
141
|
-
return min + percent * (max - min);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* @param {PointerEvent} event
|
|
146
|
-
* @return {number}
|
|
147
|
-
* @private
|
|
148
|
-
*/
|
|
149
|
-
__getEventPercent(event) {
|
|
150
|
-
const offset = event.offsetX;
|
|
151
|
-
const size = this.offsetWidth;
|
|
152
|
-
const safeOffset = Math.min(Math.max(offset, 0), size);
|
|
153
|
-
return safeOffset / size;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* @param {PointerEvent} event
|
|
158
|
-
* @return {number}
|
|
159
|
-
* @private
|
|
160
|
-
*/
|
|
161
|
-
__getEventValue(event) {
|
|
162
|
-
const percent = this.__getEventPercent(event);
|
|
163
|
-
return this.__getValueFromPercent(percent);
|
|
147
|
+
const safeValue = Math.min(Math.max(value, min), max);
|
|
148
|
+
return (safeValue - min) / (max - min);
|
|
164
149
|
}
|
|
165
150
|
|
|
166
151
|
/**
|
|
@@ -168,80 +153,16 @@ export const SliderMixin = (superClass) =>
|
|
|
168
153
|
* @private
|
|
169
154
|
*/
|
|
170
155
|
__onMouseDown(event) {
|
|
171
|
-
|
|
172
|
-
if (!part || (!part.startsWith('track') && !part.startsWith('thumb'))) {
|
|
156
|
+
if (!event.composedPath().includes(this.$.controls)) {
|
|
173
157
|
return;
|
|
174
158
|
}
|
|
175
159
|
|
|
176
|
-
// Prevent
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
this.__focusInput(event);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @param {PointerEvent} event
|
|
184
|
-
* @private
|
|
185
|
-
*/
|
|
186
|
-
__onPointerDown(event) {
|
|
187
|
-
if (this.disabled || this.readonly || event.button !== 0) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Only handle pointerdown on the thumb, track or track-fill
|
|
192
|
-
const part = event.composedPath()[0].getAttribute('part');
|
|
193
|
-
if (!part || (!part.startsWith('track') && !part.startsWith('thumb'))) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
this.setPointerCapture(event.pointerId);
|
|
198
|
-
this.addEventListener('pointermove', this.__onPointerMove);
|
|
199
|
-
this.addEventListener('pointerup', this.__onPointerUp);
|
|
200
|
-
this.addEventListener('pointercancel', this.__onPointerUp);
|
|
201
|
-
|
|
202
|
-
this.__thumbIndex = this.__getThumbIndex(event);
|
|
203
|
-
|
|
204
|
-
// Update value on track click
|
|
205
|
-
if (part.startsWith('track')) {
|
|
206
|
-
const newValue = this.__getEventValue(event);
|
|
207
|
-
this.__updateValue(newValue, this.__thumbIndex);
|
|
208
|
-
this.__commitValue();
|
|
160
|
+
// Prevent modifying value when readonly
|
|
161
|
+
if (this.readonly) {
|
|
162
|
+
event.preventDefault();
|
|
209
163
|
}
|
|
210
164
|
}
|
|
211
165
|
|
|
212
|
-
/**
|
|
213
|
-
* @param {PointerEvent} event
|
|
214
|
-
* @private
|
|
215
|
-
*/
|
|
216
|
-
__onPointerMove(event) {
|
|
217
|
-
const newValue = this.__getEventValue(event);
|
|
218
|
-
this.__updateValue(newValue, this.__thumbIndex);
|
|
219
|
-
this.__commitValue();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* @param {PointerEvent} event
|
|
224
|
-
* @private
|
|
225
|
-
*/
|
|
226
|
-
__onPointerUp(event) {
|
|
227
|
-
this.__thumbIndex = null;
|
|
228
|
-
|
|
229
|
-
this.releasePointerCapture(event.pointerId);
|
|
230
|
-
this.removeEventListener('pointermove', this.__onPointerMove);
|
|
231
|
-
this.removeEventListener('pointerup', this.__onPointerUp);
|
|
232
|
-
this.removeEventListener('pointercancel', this.__onPointerUp);
|
|
233
|
-
|
|
234
|
-
this.__detectAndDispatchChange();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* @param {Event} event
|
|
239
|
-
* @private
|
|
240
|
-
*/
|
|
241
|
-
__focusInput(_event) {
|
|
242
|
-
this.focus({ focusVisible: false });
|
|
243
|
-
}
|
|
244
|
-
|
|
245
166
|
/** @private */
|
|
246
167
|
__detectAndDispatchChange() {
|
|
247
168
|
if (JSON.stringify(this.__lastCommittedValue) !== JSON.stringify(this.value)) {
|
|
@@ -250,16 +171,6 @@ export const SliderMixin = (superClass) =>
|
|
|
250
171
|
}
|
|
251
172
|
}
|
|
252
173
|
|
|
253
|
-
/**
|
|
254
|
-
* @param {Event} event
|
|
255
|
-
* @private
|
|
256
|
-
*/
|
|
257
|
-
__onInput(event) {
|
|
258
|
-
const index = this.__getThumbIndex(event);
|
|
259
|
-
this.__updateValue(event.target.value, index);
|
|
260
|
-
this.__commitValue();
|
|
261
|
-
}
|
|
262
|
-
|
|
263
174
|
/**
|
|
264
175
|
* @param {Event} event
|
|
265
176
|
* @private
|