@kidlib/web-audio 0.1.5 → 0.1.6

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.
@@ -31,6 +31,7 @@ export declare class KnobElement extends HTMLElement {
31
31
  attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
32
32
  private injectGlobalStyles;
33
33
  private updateConfigFromAttributes;
34
+ private updateAccessibility;
34
35
  private updateDimensions;
35
36
  private updateColorFromAttribute;
36
37
  private render;
@@ -39,10 +40,12 @@ export declare class KnobElement extends HTMLElement {
39
40
  private dragHandlers?;
40
41
  private lastClickTime;
41
42
  private readonly DOUBLE_CLICK_THRESHOLD;
43
+ private handleKeyDown;
42
44
  private createDraggable;
43
45
  private updateBorder;
44
46
  private dispatchChangeEvent;
45
47
  setValue(value: number): void;
48
+ private updateValue;
46
49
  /**
47
50
  * Sets the knob value using a normalized 0-1 input, automatically handling
48
51
  * the knob's range and curve transformation.
@@ -46,7 +46,7 @@ var e = class e extends HTMLElement {
46
46
  super();
47
47
  }
48
48
  connectedCallback() {
49
- this.injectGlobalStyles(), this.createUtilityFunctions(), this.render(), this.updateColorFromAttribute(), this.setValue(this.config.defaultValue ?? this.config.minValue), this.createDraggable();
49
+ this.injectGlobalStyles(), this.createUtilityFunctions(), this.render(), this.updateColorFromAttribute(), this.updateAccessibility(), this.setValue(this.config.defaultValue ?? this.config.minValue), this.createDraggable(), this.addEventListener("keydown", this.handleKeyDown);
50
50
  }
51
51
  disconnectedCallback() {
52
52
  this.cleanup();
@@ -74,7 +74,7 @@ var e = class e extends HTMLElement {
74
74
  injectGlobalStyles() {
75
75
  if (e.stylesInjected) return;
76
76
  let t = document.createElement("style");
77
- t.id = "knob-element-styles", t.textContent = "\n knob-element {\n display: block;\n box-sizing: border-box;\n --knob-size: 120px;\n --knob-stroke: rgb(234, 234, 234);\n\n width: var(--knob-size, 120px); \n height: var(--knob-size, 120px);\n\n touch-action: none; /* Prevents browser touch gestures */\n user-select: none; /* Prevents text selection during drag */\n border-radius: 50%;\n cursor: grab;\n }\n \n knob-element[disabled] {\n opacity: 0.5;\n pointer-events: none; \n }\n \n knob-element:active {\n cursor: grabbing;\n }\n ", document.head.appendChild(t), e.stylesInjected = !0;
77
+ t.id = "knob-element-styles", t.textContent = "\n knob-element {\n display: block;\n box-sizing: border-box;\n --knob-size: 120px;\n --knob-stroke: rgb(234, 234, 234);\n\n width: var(--knob-size, 120px); \n height: var(--knob-size, 120px);\n\n touch-action: none; /* Prevents browser touch gestures */\n user-select: none; /* Prevents text selection during drag */\n border-radius: 50%;\n cursor: grab;\n }\n \n knob-element[disabled] {\n opacity: 0.5;\n pointer-events: none; \n }\n \n knob-element:active {\n cursor: grabbing;\n }\n\n knob-element:focus-visible {\n outline: 1px solid rgb(255 255 255 / 45%);\n outline-offset: 4px;\n }\n ", document.head.appendChild(t), e.stylesInjected = !0;
78
78
  }
79
79
  updateConfigFromAttributes() {
80
80
  let e = (e, t) => {
@@ -105,7 +105,10 @@ var e = class e extends HTMLElement {
105
105
  allowedValues: r ? [...r].sort((e, t) => e - t) : void 0,
106
106
  snapThresholds: n("snap-thresholds"),
107
107
  disabled: this.hasAttribute("disabled")
108
- }, this.updateDimensions();
108
+ }, this.updateDimensions(), this.updateAccessibility();
109
+ }
110
+ updateAccessibility() {
111
+ this.setAttribute("role", "slider"), this.setAttribute("aria-valuemin", String(this.config.minValue)), this.setAttribute("aria-valuemax", String(this.config.maxValue)), this.setAttribute("aria-valuenow", String(this.currentValue)), this.setAttribute("aria-disabled", String(!!this.config.disabled)), this.tabIndex = this.config.disabled ? -1 : 0;
109
112
  }
110
113
  updateDimensions() {
111
114
  let e = this.getAttribute("width"), t = this.getAttribute("height");
@@ -122,7 +125,7 @@ var e = class e extends HTMLElement {
122
125
  this.innerHTML = "\n <svg class=\"ac-knob\" width=\"100%\" height=\"100%\" viewBox=\"0 0 100 100\">\n <path class=\"knob-path\" \n fill=\"none\" \n stroke=\"var(--knob-stroke)\" \n stroke-width=\"5\" \n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M50,50 L50,2\"\n />\n </svg>\n ", this.pathElement = this.querySelector(".knob-path");
123
126
  }
124
127
  cleanup() {
125
- this.dragHandlers && (this.removeEventListener("mousedown", this.dragHandlers.start), this.removeEventListener("touchstart", this.dragHandlers.start), document.removeEventListener("mousemove", this.dragHandlers.move), document.removeEventListener("mouseup", this.dragHandlers.end), document.removeEventListener("touchmove", this.dragHandlers.move), document.removeEventListener("touchend", this.dragHandlers.end));
128
+ this.removeEventListener("keydown", this.handleKeyDown), this.dragHandlers && (this.removeEventListener("mousedown", this.dragHandlers.start), this.removeEventListener("touchstart", this.dragHandlers.start), document.removeEventListener("mousemove", this.dragHandlers.move), document.removeEventListener("mouseup", this.dragHandlers.end), document.removeEventListener("touchmove", this.dragHandlers.move), document.removeEventListener("touchend", this.dragHandlers.end));
126
129
  }
127
130
  createUtilityFunctions() {
128
131
  let t = this.config.curve || 1;
@@ -148,39 +151,56 @@ var e = class e extends HTMLElement {
148
151
  dragHandlers;
149
152
  lastClickTime = 0;
150
153
  DOUBLE_CLICK_THRESHOLD = 300;
154
+ handleKeyDown = (e) => {
155
+ if (this.config.disabled) return;
156
+ let t = e.key === "ArrowUp" || e.key === "ArrowRight" ? 1 : e.key === "ArrowDown" || e.key === "ArrowLeft" ? -1 : 0, n;
157
+ if (e.key === "Home") n = this.config.minValue;
158
+ else if (e.key === "End") n = this.config.maxValue;
159
+ else if (t && this.config.allowedValues?.length) {
160
+ let e = this.config.allowedValues;
161
+ n = t > 0 ? e.find((e) => e > this.currentValue) ?? e[e.length - 1] : [...e].reverse().find((e) => e < this.currentValue) ?? e[0];
162
+ } else if (t) {
163
+ let e = this.config.maxValue - this.config.minValue, r = this.hasAttribute("snap-increment") && this.config.snapIncrement > 0, i = r ? this.config.snapIncrement : e * .01, a = this.currentValue + t * i;
164
+ n = r ? this.applySnapping(a) : a;
165
+ } else return;
166
+ e.preventDefault(), e.stopPropagation(), this.updateValue(n, "user");
167
+ };
151
168
  createDraggable() {
152
- let t = "pointerLockElement" in document && "requestPointerLock" in HTMLElement.prototype, n = !1, r = 0, i = 0, a = 0, o = !1, s = (e) => {
153
- r = e.clientY, o = document.pointerLockElement === this, !(!t || document.pointerLockElement) && this.requestPointerLock().then(() => {
154
- o = document.pointerLockElement === this;
169
+ let t = "pointerLockElement" in document && "requestPointerLock" in HTMLElement.prototype, n = !1, r = 0, i = 0, a = 0, o = 0, s = !1, c = !1, l = (e) => {
170
+ r = e.clientY, i = r, s = document.pointerLockElement === this, !(!t || document.pointerLockElement) && this.requestPointerLock().then(() => {
171
+ s = document.pointerLockElement === this;
155
172
  }, () => {
156
- o = !1;
173
+ s = !1;
157
174
  });
158
- }, c = (e) => {
175
+ }, u = (e) => {
159
176
  if (this.config.disabled) return;
160
- let t = Date.now(), c = t - this.lastClickTime;
161
- if (c < this.DOUBLE_CLICK_THRESHOLD && c > 0) {
162
- this.resetToDefault();
177
+ let t = Date.now(), u = t - this.lastClickTime;
178
+ if (u < this.DOUBLE_CLICK_THRESHOLD && u > 0) {
179
+ this.updateValue(this.config.defaultValue, "user");
163
180
  return;
164
181
  }
165
- this.lastClickTime = t, n = !0, i = this.currentRotation, a = 0, "touches" in e ? (r = e.touches[0].clientY, o = !1) : s(e);
166
- }, l = (t) => {
182
+ this.lastClickTime = t, n = !0, a = this.currentRotation, o = 0, c = "shiftKey" in e && e.shiftKey, "touches" in e ? (r = e.touches[0].clientY, i = r, s = !1) : l(e);
183
+ }, d = (t) => {
167
184
  if (!n) return;
168
- let s;
169
- if (o && document.pointerLockElement) a += t.movementY, s = -a * 2;
170
- else {
171
- let e = "touches" in t ? t.touches[0].clientY : t.clientY;
172
- s = (r - e) * 2;
185
+ if (this.config.disabled) {
186
+ f();
187
+ return;
173
188
  }
174
- let c = i + s, l = e.clamp(c, this.config.minRotation, this.config.maxRotation), u = this.rotationToValue(l), d = this.applySnapping(u);
175
- this.currentValue = d, this.currentRotation = d === u ? l : this.valueToRotation(d), this.updateBorder(), this.dispatchChangeEvent("user"), t.preventDefault();
176
- }, u = () => {
177
- n = !1, o && document.pointerLockElement && document.exitPointerLock(), o = !1;
189
+ let l = "touches" in t ? t.touches[0].clientY : t.clientY, u = "shiftKey" in t && t.shiftKey;
190
+ u !== c && (c = u, a = this.currentRotation, r = i, o = 0);
191
+ let d, p = c ? .2 : 2;
192
+ s && document.pointerLockElement ? (o += t.movementY, d = -o * p) : d = (r - l) * p, i = l;
193
+ let m = a + d, h = e.clamp(m, this.config.minRotation, this.config.maxRotation), g = this.rotationToValue(h), _ = this.applySnapping(g);
194
+ this.currentValue = _, this.setAttribute("aria-valuenow", String(this.currentValue)), this.currentRotation = _ === g ? h : this.valueToRotation(_), this.updateBorder(), this.dispatchChangeEvent("user"), t.preventDefault();
178
195
  };
196
+ function f() {
197
+ n = !1, s && document.pointerLockElement && document.exitPointerLock(), s = !1;
198
+ }
179
199
  this.dragHandlers = {
180
- start: c,
181
- move: l,
182
- end: u
183
- }, this.addEventListener("mousedown", c), this.addEventListener("touchstart", c, { passive: !1 }), document.addEventListener("mousemove", l), document.addEventListener("mouseup", u), document.addEventListener("touchmove", l, { passive: !1 }), document.addEventListener("touchend", u);
200
+ start: u,
201
+ move: d,
202
+ end: f
203
+ }, this.addEventListener("mousedown", u), this.addEventListener("touchstart", u, { passive: !1 }), document.addEventListener("mousemove", d), document.addEventListener("mouseup", f), document.addEventListener("touchmove", d, { passive: !1 }), document.addEventListener("touchend", f);
184
204
  }
185
205
  updateBorder() {
186
206
  if (this.pathElement) {
@@ -202,8 +222,11 @@ var e = class e extends HTMLElement {
202
222
  });
203
223
  this.dispatchEvent(r);
204
224
  }
205
- setValue(t) {
206
- !this.valueToRotation || !this.pathElement || (this.currentValue = e.clamp(t, this.config.minValue, this.config.maxValue), this.currentRotation = this.valueToRotation(this.currentValue), this.updateBorder(), this.dispatchChangeEvent());
225
+ setValue(e) {
226
+ this.updateValue(e, "programmatic");
227
+ }
228
+ updateValue(t, n) {
229
+ !this.valueToRotation || !this.pathElement || (this.currentValue = e.clamp(t, this.config.minValue, this.config.maxValue), this.currentRotation = this.valueToRotation(this.currentValue), this.updateBorder(), this.setAttribute("aria-valuenow", String(this.currentValue)), this.dispatchChangeEvent(n));
207
230
  }
208
231
  setValueNormalized(e) {
209
232
  let { minRotation: t, maxRotation: n } = this.config, r = t + Math.max(0, Math.min(1, e)) * (n - t), i = this.rotationToValue(r);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kidlib/web-audio",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "High-level Web Audio primitives for musical instruments and tools.",
5
5
  "license": "MIT",
6
6
  "repository": {