@statistikzh/leu 0.23.0 → 0.24.1
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/.github/workflows/ci.yml +8 -8
- package/.github/workflows/deploy-github-pages.yaml +2 -2
- package/.github/workflows/publish.yml +37 -0
- package/.github/workflows/release-please.yml +1 -19
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +26 -0
- package/dist/Accordion.js +1 -1
- package/dist/Button.js +1 -1
- package/dist/ButtonGroup.js +1 -1
- package/dist/ChartWrapper.js +1 -1
- package/dist/Checkbox.js +1 -1
- package/dist/CheckboxGroup.js +1 -1
- package/dist/Chip.js +1 -1
- package/dist/ChipGroup.js +1 -1
- package/dist/ChipLink.js +1 -1
- package/dist/ChipRemovable.js +1 -1
- package/dist/ChipSelectable.js +1 -1
- package/dist/Dialog.js +1 -1
- package/dist/Dropdown.js +1 -1
- package/dist/FileInput.d.ts +0 -1
- package/dist/FileInput.js +1 -35
- package/dist/Icon.js +1 -1
- package/dist/Input.js +1 -1
- package/dist/{LeuElement-CWseJvWv.js → LeuElement-jrR2M5pZ.js} +1 -1
- package/dist/Menu.js +1 -1
- package/dist/MenuItem.js +1 -1
- package/dist/Message.js +1 -1
- package/dist/Pagination.js +1 -1
- package/dist/Placeholder.js +1 -1
- package/dist/Popup.js +1 -1
- package/dist/ProgressBar.js +1 -1
- package/dist/Radio.js +1 -1
- package/dist/RadioGroup.js +1 -1
- package/dist/Range.d.ts +83 -20
- package/dist/Range.js +276 -73
- package/dist/ScrollTop.js +2 -25
- package/dist/Select.js +1 -1
- package/dist/Spinner.js +1 -1
- package/dist/Table.js +1 -1
- package/dist/Tag.js +1 -1
- package/dist/VisuallyHidden.js +1 -1
- package/dist/components/file-input/FileInput.d.ts +2 -2
- package/dist/components/file-input/FileInput.d.ts.map +1 -1
- package/dist/components/range/Range.d.ts +84 -20
- package/dist/components/range/Range.d.ts.map +1 -1
- package/dist/components/range/stories/range.stories.d.ts +231 -0
- package/dist/components/range/stories/range.stories.d.ts.map +1 -0
- package/dist/components/range/test/range.test.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/leu-accordion.js +1 -1
- package/dist/leu-button-group.js +1 -1
- package/dist/leu-button.js +1 -1
- package/dist/leu-chart-wrapper.js +1 -1
- package/dist/leu-checkbox-group.js +1 -1
- package/dist/leu-checkbox.js +1 -1
- package/dist/leu-chip-group.js +1 -1
- package/dist/leu-chip-link.js +1 -1
- package/dist/leu-chip-removable.js +1 -1
- package/dist/leu-chip-selectable.js +1 -1
- package/dist/leu-dialog.js +1 -1
- package/dist/leu-dropdown.js +1 -1
- package/dist/leu-file-input.d.ts +0 -1
- package/dist/leu-file-input.js +1 -35
- package/dist/leu-icon.js +1 -1
- package/dist/leu-input.js +1 -1
- package/dist/leu-menu-item.js +1 -1
- package/dist/leu-menu.js +1 -1
- package/dist/leu-message.js +1 -1
- package/dist/leu-pagination.js +1 -1
- package/dist/leu-placeholder.js +1 -1
- package/dist/leu-popup.js +1 -1
- package/dist/leu-progress-bar.js +1 -1
- package/dist/leu-radio-group.js +1 -1
- package/dist/leu-radio.js +1 -1
- package/dist/leu-range.js +3 -1
- package/dist/leu-scroll-top.js +2 -1
- package/dist/leu-select.js +1 -1
- package/dist/leu-spinner.js +1 -1
- package/dist/leu-table.js +1 -1
- package/dist/leu-tag.js +1 -1
- package/dist/leu-visually-hidden.js +1 -1
- package/dist/lib/utils.d.ts +10 -3
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/utils-DBGsNSJW.js +33 -0
- package/dist/vscode.html-custom-data.json +142 -89
- package/dist/vue/index.d.ts +132 -107
- package/dist/web-types.json +269 -169
- package/package.json +6 -2
- package/src/components/file-input/FileInput.ts +2 -2
- package/src/components/range/Range.ts +257 -85
- package/src/components/range/range.css +48 -1
- package/src/components/range/stories/range.stories.ts +185 -0
- package/src/components/range/test/range.test.ts +210 -6
- package/src/lib/utils.ts +13 -3
- package/dist/components/range/stories/range-slider.stories.d.ts +0 -26
- package/dist/components/range/stories/range-slider.stories.d.ts.map +0 -1
- package/src/components/range/stories/range-slider.stories.ts +0 -142
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { html } from "lit"
|
|
1
|
+
import { html, nothing, PropertyValues } from "lit"
|
|
2
|
+
import { property, query } from "lit/decorators.js"
|
|
3
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
2
4
|
|
|
3
|
-
import { property } from "lit/decorators.js"
|
|
4
5
|
import styles from "./range.css"
|
|
5
6
|
import { LeuElement } from "../../lib/LeuElement.js"
|
|
7
|
+
import { clamp, isNumber } from "../../lib/utils.js"
|
|
8
|
+
|
|
9
|
+
type InternalRangeValue = [number, number] | [number]
|
|
6
10
|
|
|
7
11
|
const defaultValueConverter = {
|
|
8
|
-
fromAttribute(value) {
|
|
12
|
+
fromAttribute(value: string) {
|
|
9
13
|
return value.split(",").map((v) => Number(v.trim()))
|
|
10
14
|
},
|
|
11
|
-
toAttribute(value) {
|
|
15
|
+
toAttribute(value: number[]) {
|
|
12
16
|
return value.join(",")
|
|
13
17
|
},
|
|
14
18
|
}
|
|
@@ -26,140 +30,267 @@ export class LeuRange extends LeuElement {
|
|
|
26
30
|
delegatesFocus: true,
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
/**
|
|
34
|
+
* The default value of the range slider.
|
|
35
|
+
* String input is parsed as a comma-separated list of numbers.
|
|
36
|
+
*/
|
|
37
|
+
@property({
|
|
38
|
+
converter: defaultValueConverter,
|
|
39
|
+
attribute: "value",
|
|
40
|
+
reflect: true,
|
|
41
|
+
})
|
|
30
42
|
defaultValue = [50]
|
|
31
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The minimum value of the range slider.
|
|
46
|
+
*/
|
|
32
47
|
@property({ type: Number, reflect: true })
|
|
33
48
|
min: number = 0
|
|
34
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The maximum value of the range slider.
|
|
52
|
+
*/
|
|
35
53
|
@property({ type: Number, reflect: true })
|
|
36
54
|
max: number = 100
|
|
37
55
|
|
|
56
|
+
/**
|
|
57
|
+
* The step size of the range slider.
|
|
58
|
+
*/
|
|
38
59
|
@property({ type: Number, reflect: true })
|
|
39
60
|
step: number = 1
|
|
40
61
|
|
|
41
62
|
@property({ type: String, reflect: true })
|
|
42
63
|
name: string = ""
|
|
43
64
|
|
|
65
|
+
/**
|
|
66
|
+
* The label of the range slider.
|
|
67
|
+
*/
|
|
44
68
|
@property({ type: String, reflect: true })
|
|
45
69
|
label: string = ""
|
|
46
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Whether to hide the label of the range slider.
|
|
73
|
+
* If true, the label will still be available for screen readers
|
|
74
|
+
* and is only visually hidden.
|
|
75
|
+
*/
|
|
76
|
+
@property({ type: Boolean, reflect: true, attribute: "hide-label" })
|
|
77
|
+
hideLabel: boolean = false
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Whether the range slider is disabled.
|
|
81
|
+
*/
|
|
47
82
|
@property({ type: Boolean, reflect: true })
|
|
48
83
|
disabled: boolean = false
|
|
49
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Whether to use a range with two handles.
|
|
87
|
+
*/
|
|
50
88
|
@property({ type: Boolean, reflect: true })
|
|
51
89
|
multiple: boolean = false
|
|
52
90
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Wheter to show tick marks below the range slider.
|
|
93
|
+
* One tick mark per step will be rendered.
|
|
94
|
+
*/
|
|
95
|
+
@property({ type: Boolean, reflect: true, attribute: "show-ticks" })
|
|
96
|
+
showTicks: boolean = false
|
|
56
97
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Whether to show the min and max labels below the range slider.
|
|
100
|
+
*/
|
|
101
|
+
@property({ type: Boolean, reflect: true, attribute: "show-range-labels" })
|
|
102
|
+
showRangeLabels: boolean = false
|
|
62
103
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
104
|
+
/**
|
|
105
|
+
* A prefix to display before the value in the output element(s).
|
|
106
|
+
* Is ignored if a custom valueFormatter is provided.
|
|
107
|
+
*/
|
|
108
|
+
@property({ type: String, reflect: true })
|
|
109
|
+
prefix: string = ""
|
|
67
110
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
111
|
+
/**
|
|
112
|
+
* A suffix to display after the value in the output element(s).
|
|
113
|
+
* Is ignored if a custom valueFormatter is provided.
|
|
114
|
+
*/
|
|
115
|
+
@property({ type: String, reflect: true })
|
|
116
|
+
suffix: string = ""
|
|
71
117
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
output.value = input.value
|
|
79
|
-
})
|
|
80
|
-
}
|
|
118
|
+
/**
|
|
119
|
+
* A custom function to format the value displayed in the output element(s).
|
|
120
|
+
* If provided, the prefix and suffix properties will be ignored.
|
|
121
|
+
*/
|
|
122
|
+
@property({ attribute: false })
|
|
123
|
+
valueFormatter?: (value: number) => string
|
|
81
124
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
125
|
+
protected _value: InternalRangeValue = this.defaultValue.map((v) =>
|
|
126
|
+
this.clampAndRoundValue(v),
|
|
127
|
+
) as InternalRangeValue
|
|
85
128
|
|
|
86
129
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
130
|
+
* The value of the range slider.
|
|
131
|
+
* String input is parsed as a comma-separated list of numbers.
|
|
132
|
+
* In multiple mode, if only a single value is provided, the second handle will be set to the minimum value.
|
|
133
|
+
* In single mode, only the first value will be used.
|
|
90
134
|
*/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
135
|
+
@property({ attribute: false })
|
|
136
|
+
set value(value: string | number | Array<string | number>) {
|
|
137
|
+
let nextValue: Array<number> = []
|
|
138
|
+
|
|
139
|
+
if (typeof value === "string") {
|
|
140
|
+
nextValue = value
|
|
141
|
+
.split(",")
|
|
142
|
+
.map((v) => Number(v.trim()))
|
|
143
|
+
.filter(isNumber)
|
|
144
|
+
} else if (isNumber(value)) {
|
|
145
|
+
nextValue = [value]
|
|
146
|
+
} else if (Array.isArray(value)) {
|
|
147
|
+
nextValue = value.map((v: unknown) => Number(v)).filter(isNumber)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (nextValue.length === 0) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// In multiple mode, we need to ensure that we always have two values.
|
|
155
|
+
// `min` is a fallback for the second value.
|
|
156
|
+
if (this.multiple && nextValue.length === 1) {
|
|
157
|
+
nextValue.unshift(this.min)
|
|
102
158
|
}
|
|
159
|
+
|
|
160
|
+
this._value = nextValue
|
|
161
|
+
.slice(0, this.multiple ? 2 : 1)
|
|
162
|
+
.map((v) => this.clampAndRoundValue(v)) as InternalRangeValue
|
|
103
163
|
}
|
|
104
164
|
|
|
105
|
-
get
|
|
106
|
-
return this.
|
|
165
|
+
get value(): string {
|
|
166
|
+
return this._value.join(",")
|
|
107
167
|
}
|
|
108
168
|
|
|
109
|
-
get
|
|
110
|
-
|
|
169
|
+
get valueAsArray(): InternalRangeValue {
|
|
170
|
+
return this._value.slice() as InternalRangeValue
|
|
171
|
+
}
|
|
111
172
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
173
|
+
get valueLow(): number {
|
|
174
|
+
return Math.min(...this._value)
|
|
175
|
+
}
|
|
115
176
|
|
|
116
|
-
|
|
177
|
+
get valueHigh(): number {
|
|
178
|
+
return Math.max(...this._value)
|
|
117
179
|
}
|
|
118
180
|
|
|
119
|
-
|
|
120
|
-
|
|
181
|
+
@query("#container")
|
|
182
|
+
protected container: HTMLDivElement
|
|
121
183
|
|
|
122
|
-
|
|
123
|
-
|
|
184
|
+
@query("#input-base")
|
|
185
|
+
protected inputBase: HTMLInputElement
|
|
186
|
+
|
|
187
|
+
@query("#input-ghost")
|
|
188
|
+
protected inputGhost: HTMLInputElement | null
|
|
189
|
+
|
|
190
|
+
@query("output[for=input-base]")
|
|
191
|
+
protected outputBase: HTMLOutputElement
|
|
192
|
+
|
|
193
|
+
@query("output[for=input-ghost]")
|
|
194
|
+
protected outputGhost: HTMLOutputElement | null
|
|
195
|
+
|
|
196
|
+
updated() {
|
|
197
|
+
this.updateStyles()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
protected willUpdate(changedProperties: PropertyValues<this>): void {
|
|
201
|
+
// Reflect defaultValue changes to the value property
|
|
202
|
+
// to ensure backwards compatibility with previous versions
|
|
203
|
+
if (changedProperties.has("defaultValue")) {
|
|
204
|
+
this.value = this.defaultValue.map((v) =>
|
|
205
|
+
this.clampAndRoundValue(v),
|
|
206
|
+
) as InternalRangeValue
|
|
124
207
|
}
|
|
125
208
|
|
|
126
|
-
|
|
209
|
+
if (
|
|
210
|
+
changedProperties.has("min") ||
|
|
211
|
+
changedProperties.has("max") ||
|
|
212
|
+
changedProperties.has("step")
|
|
213
|
+
) {
|
|
214
|
+
this._value = this._value.map((v) =>
|
|
215
|
+
this.clampAndRoundValue(v),
|
|
216
|
+
) as InternalRangeValue
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (changedProperties.has("multiple") && this.multiple) {
|
|
220
|
+
// When switching to multiple mode, ensure that we have two values
|
|
221
|
+
if (this._value.length === 1) {
|
|
222
|
+
this._value = [this.min, this._value[0]]
|
|
223
|
+
}
|
|
224
|
+
} else if (changedProperties.has("multiple") && !this.multiple) {
|
|
225
|
+
// When switching to single mode, keep only the lower value
|
|
226
|
+
this._value = [this.valueLow]
|
|
227
|
+
}
|
|
127
228
|
}
|
|
128
229
|
|
|
129
|
-
protected
|
|
130
|
-
|
|
230
|
+
protected updateStyles() {
|
|
231
|
+
const normalizedRange = this.getNormalizedRange()
|
|
232
|
+
this.container?.style.setProperty("--low", normalizedRange[0].toString())
|
|
233
|
+
this.container?.style.setProperty("--high", normalizedRange[1].toString())
|
|
234
|
+
|
|
235
|
+
const inputs = this.multiple
|
|
236
|
+
? [this.inputBase, this.inputGhost]
|
|
237
|
+
: [this.inputBase]
|
|
238
|
+
|
|
239
|
+
inputs.forEach((input) => {
|
|
240
|
+
const output =
|
|
241
|
+
input.id === "input-base" ? this.outputBase : this.outputGhost
|
|
242
|
+
const normalizedValue = this.getNormalizedValue(input.valueAsNumber)
|
|
243
|
+
output.style.setProperty("--value", normalizedValue.toString())
|
|
244
|
+
output.value = this.formatValue(input.valueAsNumber)
|
|
245
|
+
})
|
|
131
246
|
}
|
|
132
247
|
|
|
133
|
-
protected
|
|
134
|
-
|
|
248
|
+
protected clampAndRoundValue(value: number) {
|
|
249
|
+
const clampedValue = clamp(value, this.min, this.max)
|
|
250
|
+
const roundedValue =
|
|
251
|
+
Math.round((clampedValue - this.min) / this.step) * this.step + this.min
|
|
252
|
+
|
|
253
|
+
return roundedValue
|
|
135
254
|
}
|
|
136
255
|
|
|
137
|
-
protected
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
256
|
+
protected handleInput(e: Event & { target: HTMLInputElement }) {
|
|
257
|
+
e.stopPropagation()
|
|
258
|
+
|
|
259
|
+
if (this.multiple) {
|
|
260
|
+
this.value = [this.inputBase.valueAsNumber, this.inputGhost.valueAsNumber]
|
|
261
|
+
} else {
|
|
262
|
+
this.value = [this.inputBase.valueAsNumber]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this.dispatchEvent(
|
|
266
|
+
new CustomEvent("input", {
|
|
267
|
+
composed: true,
|
|
268
|
+
bubbles: true,
|
|
269
|
+
detail: { value: this.value, valueAsArray: this.valueAsArray },
|
|
270
|
+
}),
|
|
271
|
+
)
|
|
142
272
|
}
|
|
143
273
|
|
|
144
|
-
protected
|
|
274
|
+
protected getNormalizedValue(value: number) {
|
|
145
275
|
return (value - this.min) / (this.max - this.min)
|
|
146
276
|
}
|
|
147
277
|
|
|
148
|
-
protected
|
|
278
|
+
protected getNormalizedRange() {
|
|
149
279
|
if (this.multiple) {
|
|
150
280
|
return this.valueAsArray
|
|
151
|
-
.map((value) => this.
|
|
281
|
+
.map((value) => this.getNormalizedValue(value))
|
|
152
282
|
.sort((a, b) => a - b)
|
|
153
283
|
}
|
|
154
284
|
|
|
155
|
-
return [0, this.
|
|
285
|
+
return [0, this.getNormalizedValue(this.valueAsArray[0])]
|
|
156
286
|
}
|
|
157
287
|
|
|
158
288
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
289
|
+
* This event handler is only applied to the "base" input element and only when in "multiple" mode.
|
|
290
|
+
* It handles pointer events on the *track* and the thumb.
|
|
291
|
+
* This method determines if the interaction was closer to the base or the ghost input.
|
|
161
292
|
*/
|
|
162
|
-
protected
|
|
293
|
+
protected handlePointerDown(e: PointerEvent & { target: HTMLInputElement }) {
|
|
163
294
|
const clickValue =
|
|
164
295
|
this.min + ((this.max - this.min) * e.offsetX) / this.offsetWidth
|
|
165
296
|
const middleValue = (this.valueAsArray[0] + this.valueAsArray[1]) / 2
|
|
@@ -172,20 +303,48 @@ export class LeuRange extends LeuElement {
|
|
|
172
303
|
* As the pointerdown event is fired before the input event, we first overwrite the value
|
|
173
304
|
* of the input element that was not clicked on. The active input element will update itself.
|
|
174
305
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
306
|
+
this.inputGhost.value = e.target.value
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
protected formatValue(value: number) {
|
|
311
|
+
if (this.valueFormatter) {
|
|
312
|
+
return this.valueFormatter(value)
|
|
177
313
|
}
|
|
314
|
+
|
|
315
|
+
return `${this.prefix}${value}${this.suffix}`
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
protected renderTicks() {
|
|
319
|
+
if (!this.showTicks) {
|
|
320
|
+
return nothing
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return html`<div class="ticks">
|
|
324
|
+
${Array.from(
|
|
325
|
+
{ length: (this.max - this.min) / this.step + 1 },
|
|
326
|
+
(_, i) => this.min + i * this.step,
|
|
327
|
+
).map(
|
|
328
|
+
(tick) =>
|
|
329
|
+
html`<span
|
|
330
|
+
class="tick"
|
|
331
|
+
style="left: ${this.getNormalizedValue(tick) * 100}%"
|
|
332
|
+
></span>`,
|
|
333
|
+
)}
|
|
334
|
+
</div>`
|
|
178
335
|
}
|
|
179
336
|
|
|
180
337
|
render() {
|
|
181
338
|
const inputs = this.multiple ? ["base", "ghost"] : ["base"]
|
|
182
339
|
|
|
183
|
-
const { multiple, disabled, label,
|
|
340
|
+
const { multiple, disabled, label, valueAsArray } = this
|
|
184
341
|
|
|
185
342
|
return html`
|
|
186
343
|
<div
|
|
187
|
-
|
|
188
|
-
|
|
344
|
+
id="container"
|
|
345
|
+
class="container"
|
|
346
|
+
role=${ifDefined(multiple ? "group" : undefined)}
|
|
347
|
+
aria-labelledby=${ifDefined(multiple ? "group-label" : undefined)}
|
|
189
348
|
>
|
|
190
349
|
${multiple
|
|
191
350
|
? html`<span id="group-label" class="label">${label}</span>`
|
|
@@ -196,7 +355,7 @@ export class LeuRange extends LeuElement {
|
|
|
196
355
|
html`<output
|
|
197
356
|
class="output"
|
|
198
357
|
for="input-${type}"
|
|
199
|
-
value=${
|
|
358
|
+
value=${this.formatValue(valueAsArray[index])}
|
|
200
359
|
></output>`,
|
|
201
360
|
)}
|
|
202
361
|
</div>
|
|
@@ -204,9 +363,9 @@ export class LeuRange extends LeuElement {
|
|
|
204
363
|
${inputs.map(
|
|
205
364
|
(type, index) => html`
|
|
206
365
|
<input
|
|
207
|
-
@input=${
|
|
366
|
+
@input=${this.handleInput}
|
|
208
367
|
@pointerdown=${multiple && !disabled && index === 0
|
|
209
|
-
? this.
|
|
368
|
+
? this.handlePointerDown
|
|
210
369
|
: undefined}
|
|
211
370
|
type="range"
|
|
212
371
|
class="range range--${type}"
|
|
@@ -215,14 +374,27 @@ export class LeuRange extends LeuElement {
|
|
|
215
374
|
min=${this.min}
|
|
216
375
|
max=${this.max}
|
|
217
376
|
step=${this.step}
|
|
218
|
-
aria-label=${
|
|
377
|
+
aria-label=${ifDefined(
|
|
378
|
+
multiple ? RANGE_LABELS[index] : undefined,
|
|
379
|
+
)}
|
|
219
380
|
?disabled=${disabled}
|
|
220
|
-
.value=${
|
|
381
|
+
.value=${valueAsArray[index].toString()}
|
|
221
382
|
/>
|
|
222
383
|
`,
|
|
223
384
|
)}
|
|
385
|
+
${this.renderTicks()}
|
|
224
386
|
</div>
|
|
225
387
|
</div>
|
|
388
|
+
${this.showRangeLabels
|
|
389
|
+
? html`<div class="tick-labels">
|
|
390
|
+
<span class="tick-label tick-label--min"
|
|
391
|
+
>${this.formatValue(this.min)}</span
|
|
392
|
+
>
|
|
393
|
+
<span class="tick-label tick-label--max"
|
|
394
|
+
>${this.formatValue(this.max)}</span
|
|
395
|
+
>
|
|
396
|
+
</div>`
|
|
397
|
+
: nothing}
|
|
226
398
|
`
|
|
227
399
|
}
|
|
228
400
|
}
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
--range-value-color: var(--range-value-color-disabled);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
.container {
|
|
39
|
+
position: relative;
|
|
40
|
+
}
|
|
39
41
|
|
|
40
42
|
.label {
|
|
41
43
|
display: inline-block;
|
|
@@ -44,6 +46,17 @@
|
|
|
44
46
|
font: var(--leu-t-regular-regular-font);
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
:host([hide-label]) .label {
|
|
50
|
+
clip: rect(0 0 0 0);
|
|
51
|
+
border: 0;
|
|
52
|
+
height: 1px;
|
|
53
|
+
margin: -1px !important;
|
|
54
|
+
overflow: hidden;
|
|
55
|
+
padding: 0 !important;
|
|
56
|
+
position: absolute;
|
|
57
|
+
width: 1px;
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
.outputs {
|
|
48
61
|
position: relative;
|
|
49
62
|
height: 1.5rem;
|
|
@@ -68,6 +81,8 @@
|
|
|
68
81
|
|
|
69
82
|
.inputs {
|
|
70
83
|
position: relative;
|
|
84
|
+
z-index: 1;
|
|
85
|
+
height: var(--range-thumb-diameter);
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
.range {
|
|
@@ -178,3 +193,35 @@
|
|
|
178
193
|
.range--ghost::-webkit-slider-runnable-track {
|
|
179
194
|
background: transparent;
|
|
180
195
|
}
|
|
196
|
+
|
|
197
|
+
/* Ticks */
|
|
198
|
+
|
|
199
|
+
.ticks {
|
|
200
|
+
position: absolute;
|
|
201
|
+
inset-block-start: calc(
|
|
202
|
+
var(--range-thumb-diameter) / 2 + var(--range-track-height)
|
|
203
|
+
);
|
|
204
|
+
inset-inline: calc(var(--range-thumb-diameter) / 2);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.tick {
|
|
208
|
+
z-index: -1;
|
|
209
|
+
position: absolute;
|
|
210
|
+
top: 50%;
|
|
211
|
+
width: 2px;
|
|
212
|
+
height: 0.5rem;
|
|
213
|
+
background-color: var(--range-track-background-color);
|
|
214
|
+
transform: translateY(-50%);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.tick-labels {
|
|
218
|
+
display: flex;
|
|
219
|
+
justify-content: space-between;
|
|
220
|
+
color: var(--leu-color-black-60);
|
|
221
|
+
font: var(--leu-t-tiny-regular-font);
|
|
222
|
+
margin-top: 0.25rem;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.tick-label--max {
|
|
226
|
+
text-align: right;
|
|
227
|
+
}
|