Skip to content

Commit ad4959f

Browse files
author
Sebastian Schürmann
committed
feature(component-webaudio): cleanup and simple things
1 parent 292de16 commit ad4959f

File tree

2 files changed

+102
-52
lines changed

2 files changed

+102
-52
lines changed

packages/component-webaudio/src/wa-knob.ts

+80-47
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class WAKnob extends HTMLElement {
66
private _min: number = 0;
77
private _max: number = 127;
88
private _default: number = 0;
9+
private _defaultExplicitlySet: boolean = false;
910

1011
static get observedAttributes() {
1112
return ['value', 'min', 'max', 'default'];
@@ -22,10 +23,9 @@ class WAKnob extends HTMLElement {
2223
}
2324

2425
set value(val: number) {
25-
const newValue = this.constrainValue(val);
26+
const newValue = this._constrainValue(val);
2627
if (newValue !== this._value) {
2728
this._value = newValue;
28-
this.setAttribute('value', newValue.toString());
2929
this.render();
3030
}
3131
}
@@ -35,42 +35,111 @@ class WAKnob extends HTMLElement {
3535
}
3636

3737
set min(val: number) {
38-
this._min = val;
39-
this.value = this._value; // Recheck constraints
38+
// only set if there is a change
39+
if (val !== this._min) {
40+
this._min = val;
41+
// Update default if it wasn't explicitly set
42+
if (!this._defaultExplicitlySet) {
43+
this._default = val;
44+
}
45+
// Recheck value constraints
46+
this.value = this._value;
47+
this.render();
48+
}
4049
}
4150

4251
get max() {
4352
return this._max;
4453
}
4554

4655
set max(val: number) {
47-
this._max = val;
48-
this.value = this._value; // Recheck constraints
56+
if (val !== this._max) {
57+
this._max = val;
58+
// Recheck value constraints
59+
this.value = this._value;
60+
}
4961
}
5062

5163
get default() {
5264
return this._default;
5365
}
5466

5567
set default(val: number) {
56-
this._default = val;
57-
if (this._value === 0) {
58-
this.value = val;
68+
const newValue = this._constrainValue(val);
69+
if (newValue !== this._default) {
70+
this._default = newValue;
71+
this._defaultExplicitlySet = true;
72+
this.render();
5973
}
6074
}
6175

62-
private constrainValue(val: number): number {
76+
private _constrainValue(val: number): number {
6377
return Math.min(this._max, Math.max(this._min, val));
6478
}
6579

80+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
81+
if (oldValue === newValue) return;
82+
83+
const numValue = parseFloat(newValue || '0');
84+
const constrainedValue = this._constrainValue(numValue);
85+
86+
switch (name) {
87+
case 'value':
88+
if (constrainedValue !== numValue) {
89+
// If the value was constrained, update the attribute
90+
this.setAttribute('value', constrainedValue.toString());
91+
} else {
92+
this.value = numValue;
93+
}
94+
break;
95+
case 'min':
96+
this.min = numValue;
97+
break;
98+
case 'max':
99+
this.max = numValue;
100+
break;
101+
case 'default':
102+
this.default = numValue;
103+
break;
104+
}
105+
}
106+
107+
connectedCallback() {
108+
// Initialize from attributes if present
109+
if (this.hasAttribute('min')) {
110+
this.min = parseFloat(this.getAttribute('min') || '0');
111+
}
112+
if (this.hasAttribute('max')) {
113+
this.max = parseFloat(this.getAttribute('max') || '127');
114+
}
115+
if (this.hasAttribute('default')) {
116+
this.default = parseFloat(this.getAttribute('default') || this._min.toString());
117+
} else {
118+
// If no default attribute, use min
119+
this._default = this._min;
120+
}
121+
if (this.hasAttribute('value')) {
122+
this.value = parseFloat(this.getAttribute('value') || this._default.toString());
123+
} else {
124+
// If no value attribute, use default
125+
this.value = this._default;
126+
}
127+
128+
// Set initial attributes for HTML use
129+
this.setAttribute('value', this._value.toString());
130+
this.setAttribute('min', this._min.toString());
131+
this.setAttribute('max', this._max.toString());
132+
this.setAttribute('default', this._default.toString());
133+
}
134+
66135
private render() {
67136
if (!this.shadowRoot) return;
68137

69138
// Calculate rotation angle based on value
70139
const range = this._max - this._min;
71140
const normalizedValue = (this._value - this._min) / range;
72141
const angle = normalizedValue * 270 - 135; // -135 to +135 degrees range
73-
142+
74143
this.shadowRoot.innerHTML = `
75144
<style>
76145
.knob-body {
@@ -115,42 +184,6 @@ class WAKnob extends HTMLElement {
115184
</div>
116185
`;
117186
}
118-
119-
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
120-
if (oldValue === newValue) return;
121-
122-
switch (name) {
123-
case 'value': {
124-
const val = parseFloat(newValue || '0');
125-
const constrained = this.constrainValue(val);
126-
this._value = constrained;
127-
this.setAttribute('value', constrained.toString());
128-
this.render();
129-
break;
130-
}
131-
case 'min':
132-
this.min = parseFloat(newValue || '0');
133-
break;
134-
case 'max':
135-
this.max = parseFloat(newValue || '127');
136-
break;
137-
case 'default':
138-
this.default = parseFloat(newValue || '0');
139-
break;
140-
}
141-
}
142-
143-
connectedCallback() {
144-
// Set to default value if no value was specified
145-
if (this._value === 0 && this._default !== 0) {
146-
this.value = this._default;
147-
}
148-
this.setAttribute('value', this._value.toString());
149-
this.setAttribute('default', this._default.toString());
150-
this.setAttribute('min', this._min.toString());
151-
this.setAttribute('max', this._max.toString());
152-
this.render();
153-
}
154187
}
155188

156189
customElements.define('wa-knob', WAKnob);

packages/component-webaudio/test/wa-knob.attr.test.ts

+22-5
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ const __dirname = dirname(__filename);
99

1010
const widgetPath = resolve(__dirname, '../src/wa-knob.ts');
1111

12-
describe('set value', () => {
12+
describe('wa-knob attributes', () => {
1313
let mountContext: MountContext;
14-
let widget: HTMLElement;
14+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
15+
let widget: any;
1516

1617
before(async () => {
1718
const helper = new TestHelper();
@@ -28,15 +29,31 @@ describe('set value', () => {
2829
mountContext.jsdom.window.close();
2930
});
3031

31-
it('gets the right value', () => {
32+
it('value attribute', () => {
3233
assert.strictEqual(widget.getAttribute('value'), '20');
3334
});
3435

35-
it('gets the right min', () => {
36+
it('value property', () => {
37+
assert.strictEqual(widget.value, 20);
38+
})
39+
40+
it('min attribute', () => {
3641
assert.strictEqual(widget.getAttribute('min'), '10');
3742
});
3843

39-
it('gets the right max', () => {
44+
it('min property', () => {
45+
assert.equal(widget.min, 10);
46+
});
47+
48+
it('max attribute', () => {
4049
assert.strictEqual(widget.getAttribute('max'), '30');
4150
});
51+
52+
it('max property', () => {
53+
assert.strictEqual(widget.max, 30);
54+
});
55+
56+
it('default adheres to min and max', () => {
57+
assert.strictEqual(widget.getAttribute('default'), '10');
58+
});
4259
});

0 commit comments

Comments
 (0)