@patchbayhq/ui 0.1.0
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/README.md +17 -0
- package/dist/api.d.ts +843 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +418 -0
- package/dist/api.js.map +1 -0
- package/dist/components/adsr.d.ts +2 -0
- package/dist/components/adsr.d.ts.map +1 -0
- package/dist/components/adsr.js +213 -0
- package/dist/components/adsr.js.map +1 -0
- package/dist/components/menu.d.ts +7 -0
- package/dist/components/menu.d.ts.map +1 -0
- package/dist/components/menu.js +136 -0
- package/dist/components/menu.js.map +1 -0
- package/dist/components/sequencers.d.ts +2 -0
- package/dist/components/sequencers.d.ts.map +1 -0
- package/dist/components/sequencers.js +477 -0
- package/dist/components/sequencers.js.map +1 -0
- package/dist/components/slider.d.ts +5 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +502 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/sequencers.d.ts +93 -0
- package/dist/sequencers.d.ts.map +1 -0
- package/dist/sequencers.js +240 -0
- package/dist/sequencers.js.map +1 -0
- package/dist/styles.css +1476 -0
- package/dist/tailwind.css +31 -0
- package/dist/theme.d.ts +52 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +65 -0
- package/dist/theme.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adsr.js","sourceRoot":"","sources":["../../src/components/adsr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../src/components/menu.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAIF,wBAAgB,SAAS,CAAC,IAAI,GAAE,UAAqB,GAAG,IAAI,CAO3D"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const controllerKey = "__menuController";
|
|
2
|
+
export function initMenus(root = document) {
|
|
3
|
+
root.querySelectorAll("[data-menu]").forEach((element) => {
|
|
4
|
+
if (!element[controllerKey]) {
|
|
5
|
+
element[controllerKey] = new MenuController(element);
|
|
6
|
+
}
|
|
7
|
+
element[controllerKey]?.sync();
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
class MenuController {
|
|
11
|
+
root;
|
|
12
|
+
activeIndex = 0;
|
|
13
|
+
button;
|
|
14
|
+
list;
|
|
15
|
+
constructor(root) {
|
|
16
|
+
this.root = root;
|
|
17
|
+
this.button = root.querySelector(".menu__button");
|
|
18
|
+
this.list = root.querySelector(".menu__list");
|
|
19
|
+
this.button?.addEventListener("click", () => this.toggle());
|
|
20
|
+
this.button?.addEventListener("keydown", (event) => this.handleKeydown(event));
|
|
21
|
+
this.options.forEach((option, index) => {
|
|
22
|
+
option.addEventListener("click", () => this.commit(index));
|
|
23
|
+
option.addEventListener("mouseenter", () => {
|
|
24
|
+
this.activeIndex = index;
|
|
25
|
+
this.sync();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
this.root.addEventListener("focusout", (event) => {
|
|
29
|
+
if (event.relatedTarget instanceof Node &&
|
|
30
|
+
this.root.contains(event.relatedTarget)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.setOpen(false);
|
|
34
|
+
});
|
|
35
|
+
this.sync();
|
|
36
|
+
}
|
|
37
|
+
get options() {
|
|
38
|
+
return Array.from(this.root.querySelectorAll(".menu__option"));
|
|
39
|
+
}
|
|
40
|
+
sync() {
|
|
41
|
+
const options = this.options;
|
|
42
|
+
const selectedIndex = Math.max(0, options.findIndex((option) => option.dataset.value === this.value));
|
|
43
|
+
const selected = options[selectedIndex] ?? options[0];
|
|
44
|
+
this.activeIndex = Math.min(this.activeIndex, Math.max(options.length - 1, 0));
|
|
45
|
+
if (selected && !this.root.dataset.value) {
|
|
46
|
+
this.root.dataset.value = selected.dataset.value ?? selected.textContent ?? "";
|
|
47
|
+
}
|
|
48
|
+
if (this.button) {
|
|
49
|
+
const value = this.button.querySelector(".menu__value");
|
|
50
|
+
if (value && selected) {
|
|
51
|
+
value.textContent = selected.textContent ?? "";
|
|
52
|
+
}
|
|
53
|
+
this.button.setAttribute("aria-expanded", String(this.open));
|
|
54
|
+
}
|
|
55
|
+
if (this.list) {
|
|
56
|
+
this.list.hidden = !this.open;
|
|
57
|
+
this.list.setAttribute("aria-activedescendant", options[this.activeIndex]?.id ?? "");
|
|
58
|
+
}
|
|
59
|
+
options.forEach((option, index) => {
|
|
60
|
+
const selectedOption = option === selected;
|
|
61
|
+
option.classList.toggle("is-active", index === this.activeIndex);
|
|
62
|
+
option.classList.toggle("is-selected", selectedOption);
|
|
63
|
+
option.setAttribute("aria-selected", String(selectedOption));
|
|
64
|
+
option.id ||= `${this.list?.id ?? "menu"}-option-${index}`;
|
|
65
|
+
if (!option.dataset.value) {
|
|
66
|
+
option.dataset.value = option.textContent ?? "";
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
get open() {
|
|
71
|
+
return this.root.dataset.open === "true";
|
|
72
|
+
}
|
|
73
|
+
get value() {
|
|
74
|
+
return this.root.dataset.value ?? "";
|
|
75
|
+
}
|
|
76
|
+
setOpen(open) {
|
|
77
|
+
if (open) {
|
|
78
|
+
this.root.dataset.open = "true";
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
delete this.root.dataset.open;
|
|
82
|
+
}
|
|
83
|
+
this.sync();
|
|
84
|
+
}
|
|
85
|
+
toggle() {
|
|
86
|
+
this.setOpen(!this.open);
|
|
87
|
+
}
|
|
88
|
+
firstEnabledIndex(startIndex, direction) {
|
|
89
|
+
const options = this.options;
|
|
90
|
+
for (let offset = 0; offset < options.length; offset += 1) {
|
|
91
|
+
const index = (startIndex + offset * direction + options.length) % options.length;
|
|
92
|
+
if (!options[index]?.disabled)
|
|
93
|
+
return index;
|
|
94
|
+
}
|
|
95
|
+
return this.activeIndex;
|
|
96
|
+
}
|
|
97
|
+
handleKeydown(event) {
|
|
98
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
const direction = event.key === "ArrowDown" ? 1 : -1;
|
|
101
|
+
this.activeIndex = this.firstEnabledIndex(this.activeIndex + direction, direction);
|
|
102
|
+
this.setOpen(true);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
if (this.open) {
|
|
108
|
+
this.commit(this.activeIndex);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.setOpen(true);
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (event.key === "Escape") {
|
|
116
|
+
this.setOpen(false);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
commit(index) {
|
|
120
|
+
const option = this.options[index];
|
|
121
|
+
if (!option || option.disabled)
|
|
122
|
+
return;
|
|
123
|
+
this.root.dataset.value = option.dataset.value ?? option.textContent ?? "";
|
|
124
|
+
this.activeIndex = index;
|
|
125
|
+
this.setOpen(false);
|
|
126
|
+
this.root.dispatchEvent(new CustomEvent("menu-change", {
|
|
127
|
+
bubbles: true,
|
|
128
|
+
detail: {
|
|
129
|
+
label: option.textContent ?? "",
|
|
130
|
+
source: "user",
|
|
131
|
+
value: this.root.dataset.value,
|
|
132
|
+
},
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.js","sourceRoot":"","sources":["../../src/components/menu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequencers.d.ts","sourceRoot":"","sources":["../../src/components/sequencers.ts"],"names":[],"mappings":"AA4BA,wBAAgB,uBAAuB,IAAI,IAAI,CAQ9C"}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { createGridState, createStepKeyChange, createStepSequencerState, cycleGridDirection, gridRowFromY, stepKeys, stepLaneCount, stepNoteAccent, stepStepCount, stepStepsPerBar, setStepLoopEnd, setStepLoopStart, toggleGridCell, toggleStepNote, } from "../sequencers";
|
|
2
|
+
export function defineSequencerElements() {
|
|
3
|
+
if (!customElements.get("sequencer-grid")) {
|
|
4
|
+
customElements.define("sequencer-grid", GridElement);
|
|
5
|
+
}
|
|
6
|
+
if (!customElements.get("step-sequencer")) {
|
|
7
|
+
customElements.define("step-sequencer", StepElement);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
class GridElement extends HTMLElement {
|
|
11
|
+
static observedAttributes = ["cells", "directions", "measure-size"];
|
|
12
|
+
state = createGridState();
|
|
13
|
+
get cells() {
|
|
14
|
+
return this.state.cells.map((cell) => ({ ...cell }));
|
|
15
|
+
}
|
|
16
|
+
set cells(cells) {
|
|
17
|
+
this.updateState({ cells });
|
|
18
|
+
}
|
|
19
|
+
get directions() {
|
|
20
|
+
return [...this.state.directions];
|
|
21
|
+
}
|
|
22
|
+
set directions(directions) {
|
|
23
|
+
this.updateState({ directions });
|
|
24
|
+
}
|
|
25
|
+
get measureSize() {
|
|
26
|
+
return this.state.measureSize;
|
|
27
|
+
}
|
|
28
|
+
set measureSize(measureSize) {
|
|
29
|
+
this.updateState({ measureSize });
|
|
30
|
+
}
|
|
31
|
+
connectedCallback() {
|
|
32
|
+
this.classList.add("grid");
|
|
33
|
+
this.setAttribute("role", this.getAttribute("role") ?? "group");
|
|
34
|
+
this.render();
|
|
35
|
+
}
|
|
36
|
+
attributeChangedCallback() {
|
|
37
|
+
this.syncStateFromAttributes();
|
|
38
|
+
if (this.isConnected) {
|
|
39
|
+
this.render();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
updateState(next) {
|
|
43
|
+
this.state = createGridState({ ...this.state, ...next });
|
|
44
|
+
if (this.isConnected) {
|
|
45
|
+
this.render();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
syncStateFromAttributes() {
|
|
49
|
+
this.state = createGridState({
|
|
50
|
+
...this.state,
|
|
51
|
+
cells: jsonAttribute(this, "cells") ?? this.state.cells,
|
|
52
|
+
directions: jsonAttribute(this, "directions") ??
|
|
53
|
+
this.state.directions,
|
|
54
|
+
measureSize: numberAttribute(this, "measure-size") ?? this.state.measureSize,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
render() {
|
|
58
|
+
this.style.setProperty("--grid-columns", String(this.state.cells.length));
|
|
59
|
+
this.replaceChildren();
|
|
60
|
+
this.state.cells.forEach((cell, index) => {
|
|
61
|
+
const button = document.createElement("button");
|
|
62
|
+
const column = index + 1;
|
|
63
|
+
const row = gridRowFromY(cell.y);
|
|
64
|
+
button.type = "button";
|
|
65
|
+
button.className = cell.active
|
|
66
|
+
? "grid__cell is-active"
|
|
67
|
+
: "grid__cell";
|
|
68
|
+
button.dataset.gridCell = String(column);
|
|
69
|
+
button.dataset.gridColumn = String(column);
|
|
70
|
+
button.dataset.gridRole = "cell";
|
|
71
|
+
button.dataset.gridState = cell.active ? "active" : "inactive";
|
|
72
|
+
button.dataset.gridY = cell.y.toFixed(4);
|
|
73
|
+
button.style.setProperty("--grid-marker-y", `${cell.y * 100}%`);
|
|
74
|
+
button.setAttribute("aria-pressed", String(cell.active));
|
|
75
|
+
button.setAttribute("aria-label", cell.active
|
|
76
|
+
? `Grid column ${column}, row ${row}`
|
|
77
|
+
: `Grid column ${column}, inactive`);
|
|
78
|
+
button.addEventListener("pointerdown", (event) => this.handleCellPointer(event, column));
|
|
79
|
+
button.addEventListener("keydown", (event) => this.handleCellKeydown(event, column, cell.y));
|
|
80
|
+
this.append(button);
|
|
81
|
+
});
|
|
82
|
+
this.state.directions.forEach((direction, index) => {
|
|
83
|
+
const button = document.createElement("button");
|
|
84
|
+
const column = index + 1;
|
|
85
|
+
button.type = "button";
|
|
86
|
+
button.className = `grid__direction is-direction-${direction}`;
|
|
87
|
+
button.dataset.gridDirection = direction;
|
|
88
|
+
button.dataset.gridDirectionControl = String(column);
|
|
89
|
+
button.dataset.gridDirectionValue = gridDirectionValue(direction);
|
|
90
|
+
button.dataset.gridRole = "direction";
|
|
91
|
+
button.setAttribute("aria-label", `Grid direction ${column}: ${direction}`);
|
|
92
|
+
button.title = direction;
|
|
93
|
+
button.addEventListener("click", () => this.handleDirectionClick(column));
|
|
94
|
+
this.append(button);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
handleCellPointer(event, column) {
|
|
98
|
+
if (event.button !== 0)
|
|
99
|
+
return;
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
const button = event.currentTarget;
|
|
102
|
+
const rect = button.getBoundingClientRect();
|
|
103
|
+
const y = rect.height > 0
|
|
104
|
+
? (event.clientY - rect.top) / rect.height
|
|
105
|
+
: (this.state.cells[column - 1]?.y ?? 0.5);
|
|
106
|
+
const { change, state } = toggleGridCell(this.state, column, y);
|
|
107
|
+
this.state = state;
|
|
108
|
+
this.render();
|
|
109
|
+
this.dispatchGridChange(change);
|
|
110
|
+
}
|
|
111
|
+
handleCellKeydown(event, column, y) {
|
|
112
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
113
|
+
return;
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
const { change, state } = toggleGridCell(this.state, column, y);
|
|
116
|
+
this.state = state;
|
|
117
|
+
this.render();
|
|
118
|
+
this.dispatchGridChange(change);
|
|
119
|
+
}
|
|
120
|
+
handleDirectionClick(column) {
|
|
121
|
+
const { change, state } = cycleGridDirection(this.state, column);
|
|
122
|
+
this.state = state;
|
|
123
|
+
this.render();
|
|
124
|
+
this.dispatchGridChange(change);
|
|
125
|
+
}
|
|
126
|
+
dispatchGridChange(detail) {
|
|
127
|
+
this.dispatchEvent(new CustomEvent("grid-change", {
|
|
128
|
+
bubbles: true,
|
|
129
|
+
composed: true,
|
|
130
|
+
detail,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
class StepElement extends HTMLElement {
|
|
135
|
+
static observedAttributes = ["active-key", "bars", "loop", "notes"];
|
|
136
|
+
keyPressAbortController;
|
|
137
|
+
loopDragAbortController;
|
|
138
|
+
pressedKey = null;
|
|
139
|
+
state = createStepSequencerState();
|
|
140
|
+
get activeKey() {
|
|
141
|
+
return this.state.activeKey;
|
|
142
|
+
}
|
|
143
|
+
set activeKey(activeKey) {
|
|
144
|
+
this.updateState({ activeKey });
|
|
145
|
+
}
|
|
146
|
+
get notes() {
|
|
147
|
+
return this.state.notes.map((note) => ({ ...note }));
|
|
148
|
+
}
|
|
149
|
+
set notes(notes) {
|
|
150
|
+
this.updateState({ notes });
|
|
151
|
+
}
|
|
152
|
+
get loop() {
|
|
153
|
+
return { ...this.state.loop };
|
|
154
|
+
}
|
|
155
|
+
set loop(loop) {
|
|
156
|
+
this.updateState({ loop });
|
|
157
|
+
}
|
|
158
|
+
get bars() {
|
|
159
|
+
return this.state.bars;
|
|
160
|
+
}
|
|
161
|
+
set bars(bars) {
|
|
162
|
+
this.updateState({ bars });
|
|
163
|
+
}
|
|
164
|
+
connectedCallback() {
|
|
165
|
+
this.classList.add("step-sequencer");
|
|
166
|
+
this.setAttribute("role", this.getAttribute("role") ?? "group");
|
|
167
|
+
this.render();
|
|
168
|
+
}
|
|
169
|
+
disconnectedCallback() {
|
|
170
|
+
this.keyPressAbortController?.abort();
|
|
171
|
+
this.loopDragAbortController?.abort();
|
|
172
|
+
this.keyPressAbortController = undefined;
|
|
173
|
+
this.loopDragAbortController = undefined;
|
|
174
|
+
this.pressedKey = null;
|
|
175
|
+
}
|
|
176
|
+
attributeChangedCallback() {
|
|
177
|
+
this.syncStateFromAttributes();
|
|
178
|
+
if (this.isConnected) {
|
|
179
|
+
this.render();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
updateState(next) {
|
|
183
|
+
this.state = createStepSequencerState({ ...this.state, ...next });
|
|
184
|
+
if (this.isConnected) {
|
|
185
|
+
this.render();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
syncStateFromAttributes() {
|
|
189
|
+
this.state = createStepSequencerState({
|
|
190
|
+
...this.state,
|
|
191
|
+
activeKey: this.getAttribute("active-key") ??
|
|
192
|
+
this.state.activeKey,
|
|
193
|
+
bars: numberAttribute(this, "bars") ?? this.state.bars,
|
|
194
|
+
loop: jsonAttribute(this, "loop") ?? this.state.loop,
|
|
195
|
+
notes: jsonAttribute(this, "notes") ?? this.state.notes,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
render() {
|
|
199
|
+
this.replaceChildren();
|
|
200
|
+
const displayKey = this.pressedKey ?? this.state.activeKey;
|
|
201
|
+
this.dataset.activeKey = this.state.activeKey;
|
|
202
|
+
this.dataset.activeKeyIndex = String(stepKeys.indexOf(this.state.activeKey) + 1);
|
|
203
|
+
if (this.pressedKey) {
|
|
204
|
+
this.dataset.pressedKey = this.pressedKey;
|
|
205
|
+
this.dataset.pressedKeyIndex = String(stepKeys.indexOf(this.pressedKey) + 1);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
delete this.dataset.pressedKey;
|
|
209
|
+
delete this.dataset.pressedKeyIndex;
|
|
210
|
+
}
|
|
211
|
+
this.dataset.loopStart = String(this.state.loop.start);
|
|
212
|
+
this.dataset.loopEnd = String(this.state.loop.end);
|
|
213
|
+
this.dataset.loopLength = String(this.state.loop.end - this.state.loop.start + 1);
|
|
214
|
+
this.dataset.loopBar = String(Math.floor((this.state.loop.start - 1) / stepStepsPerBar) + 1);
|
|
215
|
+
this.setAttribute("aria-label", `Step sequencer, key ${displayKey}, loop steps ${this.state.loop.start} through ${this.state.loop.end}`);
|
|
216
|
+
this.append(this.renderLoopRuler(), this.renderLabels(), this.renderKeys(), this.renderRoll());
|
|
217
|
+
}
|
|
218
|
+
renderLabels() {
|
|
219
|
+
const labels = document.createElement("div");
|
|
220
|
+
const activeKey = document.createElement("span");
|
|
221
|
+
const displayKey = this.pressedKey ?? this.state.activeKey;
|
|
222
|
+
labels.className = "step-sequencer__labels";
|
|
223
|
+
activeKey.textContent = displayKey;
|
|
224
|
+
labels.append(activeKey);
|
|
225
|
+
return labels;
|
|
226
|
+
}
|
|
227
|
+
renderKeys() {
|
|
228
|
+
const keys = document.createElement("div");
|
|
229
|
+
keys.className = "step-sequencer__keys";
|
|
230
|
+
keys.setAttribute("role", "group");
|
|
231
|
+
keys.setAttribute("aria-label", "Pitch keys");
|
|
232
|
+
stepKeys.forEach((key, index) => {
|
|
233
|
+
const button = document.createElement("span");
|
|
234
|
+
const tone = key.includes("#") ? "black" : "white";
|
|
235
|
+
const pressed = key === this.pressedKey;
|
|
236
|
+
button.className = tone === "black" ? "is-black" : "is-white";
|
|
237
|
+
button.dataset.stepKey = String(index + 1);
|
|
238
|
+
button.dataset.stepKeyState = pressed ? "pressed" : "idle";
|
|
239
|
+
button.dataset.stepKeyTone = tone;
|
|
240
|
+
button.setAttribute("aria-label", `Key ${key}`);
|
|
241
|
+
button.setAttribute("aria-pressed", String(pressed));
|
|
242
|
+
button.setAttribute("role", "button");
|
|
243
|
+
button.setAttribute("tabindex", "0");
|
|
244
|
+
button.classList.toggle("is-active", pressed);
|
|
245
|
+
button.addEventListener("pointerdown", (event) => this.handleKeyPointerDown(event, key));
|
|
246
|
+
button.addEventListener("keydown", (event) => this.handleKeyKeydown(event, key));
|
|
247
|
+
button.addEventListener("keyup", (event) => this.handleKeyKeyup(event, key));
|
|
248
|
+
button.addEventListener("blur", () => this.releaseKey(key));
|
|
249
|
+
keys.append(button);
|
|
250
|
+
});
|
|
251
|
+
return keys;
|
|
252
|
+
}
|
|
253
|
+
renderRoll() {
|
|
254
|
+
const roll = document.createElement("div");
|
|
255
|
+
roll.className = "step-sequencer__roll";
|
|
256
|
+
roll.setAttribute("role", "grid");
|
|
257
|
+
roll.setAttribute("aria-label", "Step notes");
|
|
258
|
+
roll.setAttribute("aria-rowcount", String(stepLaneCount));
|
|
259
|
+
roll.setAttribute("aria-colcount", String(stepStepCount));
|
|
260
|
+
Array.from({ length: stepStepCount * stepLaneCount }, (_, index) => {
|
|
261
|
+
const step = (index % stepStepCount) + 1;
|
|
262
|
+
const lane = Math.floor(index / stepStepCount) + 1;
|
|
263
|
+
const note = this.state.notes.find((candidate) => candidate.step === step && candidate.lane === lane);
|
|
264
|
+
const accent = stepNoteAccent(step);
|
|
265
|
+
const button = document.createElement("button");
|
|
266
|
+
button.type = "button";
|
|
267
|
+
button.dataset.stepBarStart = String(accent === "blue");
|
|
268
|
+
button.setAttribute("aria-label", `Step ${step}, lane ${lane}`);
|
|
269
|
+
button.setAttribute("aria-colindex", String(step));
|
|
270
|
+
button.setAttribute("aria-rowindex", String(lane));
|
|
271
|
+
button.setAttribute("aria-pressed", String(Boolean(note)));
|
|
272
|
+
button.setAttribute("aria-selected", String(Boolean(note)));
|
|
273
|
+
button.setAttribute("role", "gridcell");
|
|
274
|
+
button.className = note ? "is-active" : "";
|
|
275
|
+
button.addEventListener("click", () => this.handleNoteToggle(step, lane));
|
|
276
|
+
if (note) {
|
|
277
|
+
const marker = document.createElement("span");
|
|
278
|
+
marker.className = ["step-sequencer__note", `is-${accent}`].join(" ");
|
|
279
|
+
marker.dataset.stepNoteAccent = accent;
|
|
280
|
+
button.append(marker);
|
|
281
|
+
}
|
|
282
|
+
roll.append(button);
|
|
283
|
+
});
|
|
284
|
+
return roll;
|
|
285
|
+
}
|
|
286
|
+
renderLoopRuler() {
|
|
287
|
+
const ruler = document.createElement("div");
|
|
288
|
+
const track = document.createElement("div");
|
|
289
|
+
const range = document.createElement("div");
|
|
290
|
+
const startHandle = this.renderLoopHandle("start");
|
|
291
|
+
const endHandle = this.renderLoopHandle("end");
|
|
292
|
+
ruler.className = "step-sequencer__loop-ruler";
|
|
293
|
+
ruler.dataset.stepLoopRuler = "true";
|
|
294
|
+
ruler.setAttribute("role", "group");
|
|
295
|
+
ruler.setAttribute("aria-label", "Loop selector");
|
|
296
|
+
track.className = "step-sequencer__loop-track";
|
|
297
|
+
track.dataset.stepLoopTrack = "true";
|
|
298
|
+
range.className = "step-sequencer__loop-range";
|
|
299
|
+
range.dataset.stepLoopRange = "true";
|
|
300
|
+
range.dataset.stepLoopStart = String(this.state.loop.start);
|
|
301
|
+
range.dataset.stepLoopEnd = String(this.state.loop.end);
|
|
302
|
+
range.dataset.stepLoopLength = String(this.state.loop.end - this.state.loop.start + 1);
|
|
303
|
+
range.style.gridColumn = `${this.state.loop.start} / ${this.state.loop.end + 1}`;
|
|
304
|
+
range.setAttribute("aria-label", `Loop steps ${this.state.loop.start} through ${this.state.loop.end}`);
|
|
305
|
+
range.append(startHandle, endHandle);
|
|
306
|
+
ruler.append(track, range);
|
|
307
|
+
return ruler;
|
|
308
|
+
}
|
|
309
|
+
renderLoopHandle(edge) {
|
|
310
|
+
const handle = document.createElement("button");
|
|
311
|
+
const arrow = document.createElement("span");
|
|
312
|
+
const label = document.createElement("span");
|
|
313
|
+
const step = edge === "start" ? this.state.loop.start : this.state.loop.end;
|
|
314
|
+
const direction = edge === "start" ? "right" : "left";
|
|
315
|
+
handle.type = "button";
|
|
316
|
+
handle.className = `step-sequencer__loop-handle is-${edge}`;
|
|
317
|
+
handle.dataset.stepLoopHandle = edge;
|
|
318
|
+
arrow.className = `step-sequencer__loop-arrow is-${direction}`;
|
|
319
|
+
arrow.dataset.stepLoopArrow = direction;
|
|
320
|
+
arrow.setAttribute("aria-hidden", "true");
|
|
321
|
+
label.className = "step-sequencer__loop-label";
|
|
322
|
+
label.textContent = String(step);
|
|
323
|
+
handle.append(...(edge === "start" ? [label, arrow] : [arrow, label]));
|
|
324
|
+
handle.setAttribute("aria-label", `${edge === "start" ? "Loop start" : "Loop end"} step ${step}`);
|
|
325
|
+
handle.addEventListener("pointerdown", (event) => this.handleLoopPointerDown(event, edge));
|
|
326
|
+
handle.addEventListener("keydown", (event) => this.handleLoopHandleKeydown(event, edge));
|
|
327
|
+
return handle;
|
|
328
|
+
}
|
|
329
|
+
handleKeyPointerDown(event, key) {
|
|
330
|
+
if (event.button !== 0)
|
|
331
|
+
return;
|
|
332
|
+
event.preventDefault();
|
|
333
|
+
this.pressKey(key);
|
|
334
|
+
this.watchPointerRelease(key);
|
|
335
|
+
}
|
|
336
|
+
handleKeyKeydown(event, key) {
|
|
337
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
338
|
+
return;
|
|
339
|
+
event.preventDefault();
|
|
340
|
+
if (!event.repeat) {
|
|
341
|
+
this.pressKey(key);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
handleKeyKeyup(event, key) {
|
|
345
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
346
|
+
return;
|
|
347
|
+
event.preventDefault();
|
|
348
|
+
this.releaseKey(key);
|
|
349
|
+
}
|
|
350
|
+
pressKey(key) {
|
|
351
|
+
if (this.pressedKey === key)
|
|
352
|
+
return;
|
|
353
|
+
if (this.pressedKey) {
|
|
354
|
+
this.releaseKey();
|
|
355
|
+
}
|
|
356
|
+
this.pressedKey = key;
|
|
357
|
+
this.render();
|
|
358
|
+
this.dispatchStepChange(createStepKeyChange(this.state, key, true));
|
|
359
|
+
}
|
|
360
|
+
releaseKey(key = this.pressedKey) {
|
|
361
|
+
if (!this.pressedKey || (key && this.pressedKey !== key))
|
|
362
|
+
return;
|
|
363
|
+
const releasedKey = this.pressedKey;
|
|
364
|
+
this.keyPressAbortController?.abort();
|
|
365
|
+
this.keyPressAbortController = undefined;
|
|
366
|
+
this.pressedKey = null;
|
|
367
|
+
this.render();
|
|
368
|
+
this.dispatchStepChange(createStepKeyChange(this.state, releasedKey, false));
|
|
369
|
+
}
|
|
370
|
+
watchPointerRelease(key) {
|
|
371
|
+
this.keyPressAbortController?.abort();
|
|
372
|
+
this.keyPressAbortController = new AbortController();
|
|
373
|
+
window.addEventListener("pointerup", () => this.releaseKey(key), {
|
|
374
|
+
once: true,
|
|
375
|
+
signal: this.keyPressAbortController.signal,
|
|
376
|
+
});
|
|
377
|
+
window.addEventListener("pointercancel", () => this.releaseKey(key), {
|
|
378
|
+
once: true,
|
|
379
|
+
signal: this.keyPressAbortController.signal,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
handleLoopPointerDown(event, edge) {
|
|
383
|
+
if (event.button !== 0)
|
|
384
|
+
return;
|
|
385
|
+
event.preventDefault();
|
|
386
|
+
this.updateLoopEdgeFromClientX(edge, event.clientX);
|
|
387
|
+
this.watchLoopDrag(edge);
|
|
388
|
+
}
|
|
389
|
+
handleLoopHandleKeydown(event, edge) {
|
|
390
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight")
|
|
391
|
+
return;
|
|
392
|
+
event.preventDefault();
|
|
393
|
+
const delta = event.key === "ArrowLeft" ? -1 : 1;
|
|
394
|
+
const step = edge === "start"
|
|
395
|
+
? this.state.loop.start + delta
|
|
396
|
+
: this.state.loop.end + delta;
|
|
397
|
+
this.updateLoopEdge(edge, step);
|
|
398
|
+
}
|
|
399
|
+
watchLoopDrag(edge) {
|
|
400
|
+
this.loopDragAbortController?.abort();
|
|
401
|
+
this.loopDragAbortController = new AbortController();
|
|
402
|
+
window.addEventListener("pointermove", (event) => this.updateLoopEdgeFromClientX(edge, event.clientX), { signal: this.loopDragAbortController.signal });
|
|
403
|
+
window.addEventListener("pointerup", () => {
|
|
404
|
+
this.loopDragAbortController?.abort();
|
|
405
|
+
this.loopDragAbortController = undefined;
|
|
406
|
+
}, { once: true, signal: this.loopDragAbortController.signal });
|
|
407
|
+
window.addEventListener("pointercancel", () => {
|
|
408
|
+
this.loopDragAbortController?.abort();
|
|
409
|
+
this.loopDragAbortController = undefined;
|
|
410
|
+
}, { once: true, signal: this.loopDragAbortController.signal });
|
|
411
|
+
}
|
|
412
|
+
updateLoopEdgeFromClientX(edge, clientX) {
|
|
413
|
+
const step = this.loopStepFromClientX(clientX);
|
|
414
|
+
this.updateLoopEdge(edge, step);
|
|
415
|
+
}
|
|
416
|
+
loopStepFromClientX(clientX) {
|
|
417
|
+
const ruler = this.querySelector(".step-sequencer__loop-ruler");
|
|
418
|
+
const rect = ruler?.getBoundingClientRect();
|
|
419
|
+
if (!rect || rect.width <= 0) {
|
|
420
|
+
return this.state.loop.end;
|
|
421
|
+
}
|
|
422
|
+
const progress = (clientX - rect.left) / rect.width;
|
|
423
|
+
return Math.min(stepStepCount, Math.max(1, Math.floor(progress * stepStepCount) + 1));
|
|
424
|
+
}
|
|
425
|
+
updateLoopEdge(edge, step) {
|
|
426
|
+
const previousLoop = this.state.loop;
|
|
427
|
+
const { change, state } = edge === "start"
|
|
428
|
+
? setStepLoopStart(this.state, step)
|
|
429
|
+
: setStepLoopEnd(this.state, step);
|
|
430
|
+
if (previousLoop.start === state.loop.start &&
|
|
431
|
+
previousLoop.end === state.loop.end) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
this.state = state;
|
|
435
|
+
this.render();
|
|
436
|
+
this.dispatchStepChange(change);
|
|
437
|
+
}
|
|
438
|
+
handleNoteToggle(step, lane) {
|
|
439
|
+
const { change, state } = toggleStepNote(this.state, step, lane);
|
|
440
|
+
this.state = state;
|
|
441
|
+
this.render();
|
|
442
|
+
this.dispatchStepChange(change);
|
|
443
|
+
}
|
|
444
|
+
dispatchStepChange(detail) {
|
|
445
|
+
this.dispatchEvent(new CustomEvent("step-change", {
|
|
446
|
+
bubbles: true,
|
|
447
|
+
composed: true,
|
|
448
|
+
detail,
|
|
449
|
+
}));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function gridDirectionValue(direction) {
|
|
453
|
+
if (direction === "left")
|
|
454
|
+
return "-1";
|
|
455
|
+
if (direction === "off")
|
|
456
|
+
return "0";
|
|
457
|
+
return "1";
|
|
458
|
+
}
|
|
459
|
+
function numberAttribute(element, name) {
|
|
460
|
+
const value = element.getAttribute(name);
|
|
461
|
+
if (value === null || value.trim() === "")
|
|
462
|
+
return undefined;
|
|
463
|
+
const number = Number(value);
|
|
464
|
+
return Number.isFinite(number) ? number : undefined;
|
|
465
|
+
}
|
|
466
|
+
function jsonAttribute(element, name) {
|
|
467
|
+
const value = element.getAttribute(name);
|
|
468
|
+
if (!value)
|
|
469
|
+
return undefined;
|
|
470
|
+
try {
|
|
471
|
+
return JSON.parse(value);
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
return undefined;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
//# sourceMappingURL=sequencers.js.map
|