1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
export { SliderInput }
import { makeElement } from '../lib'
const dflt = {
min: 0,
max: 100,
step: 1,
}
type Attribute = 'min' | 'max' | 'step'
class SliderInput extends HTMLElement {
/* value a string since javascript kind of expects that */
#value = "0";
min = 0;
max = 100;
step = 1;
readonly slider: HTMLInputElement;
readonly textIn: HTMLInputElement;
constructor(min?: number, max?: number, step?: number, value?: number) {
super();
this.min = min || parseFloat(this.getAttribute('min') || "" + dflt['min']);
this.max = max || parseFloat(this.getAttribute('max') || "" + dflt['max']);
this.step = step || parseFloat(this.getAttribute('step') || "" + dflt['step']);
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range#value
const defaultValue
= (this.max < this.min)
? this.min
: this.min + (this.max - this.min) / 2;
this.slider = makeElement('input', {
type: 'range',
min: this.min,
max: this.max,
step: this.step,
value: this.value,
}) as HTMLInputElement
this.textIn = makeElement('input', {
type: 'number',
min: this.min,
max: this.max,
step: this.step,
value: this.value,
}) as HTMLInputElement
this.slider.addEventListener('input', e => this.propagate(e));
this.textIn.addEventListener('input', e => this.propagate(e));
/* MUST be after sub components are bound */
this.value = "" + (value || this.getAttribute('value') || defaultValue);
}
connectedCallback() {
this.replaceChildren(this.slider, this.textIn);
}
static get observedAttributes(): Attribute[] {
return ['min', 'max', 'step']
}
attributeChangedCallback(name: Attribute, _?: string, to?: string): void {
if (to) {
this.slider.setAttribute(name, to);
this.textIn.setAttribute(name, to);
} else {
this.slider.removeAttribute(name);
this.textIn.removeAttribute(name);
}
this[name] = parseFloat(to || "" + dflt[name])
}
propagate(e: Event) {
this.value = (e.target as HTMLInputElement).value;
if (e instanceof InputEvent && this.oninput) {
this.oninput(e);
}
}
set value(value: string) {
this.slider.value = value;
this.textIn.value = value;
this.#value = value;
}
get value(): string {
return this.#value;
}
/* TODO do we want to implement this?
* oninput directly on the component already works
* /
addEventListener(type: string, proc: ((e: Event) => void)) {
}
*/
}
|