solid-pianoroll 0.0.14 → 0.0.15

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/dist/cjs/index.js CHANGED
@@ -29,9 +29,9 @@ function styleInject(css, ref) {
29
29
  }
30
30
  }
31
31
 
32
- var css_248z$3 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
33
- var styles$3 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
34
- styleInject(css_248z$3);
32
+ var css_248z$4 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
33
+ var styles$4 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
34
+ styleInject(css_248z$4);
35
35
 
36
36
  const PianoRollContext = solidJs.createContext();
37
37
  const PianoRollContextProvider = PianoRollContext.Provider;
@@ -40,30 +40,11 @@ const usePianoRollContext = () => {
40
40
  if (!context) throw new Error("No PianoRollContext found");
41
41
  return context;
42
42
  };
43
- const splitContextProps = allProps => solidJs.splitProps(allProps, ["condensed", "duration", "gridDivision", "notes", "position", "ppq", "snapToGrid", "verticalPosition", "verticalZoom", "zoom", "onInsertNote", "onNoteChange", "onPositionChange", "onRemoveNote", "onVerticalPositionChange", "onVerticalZoomChange", "onZoomChange"]);
43
+ const splitContextProps = allProps => solidJs.splitProps(allProps, ["mode", "duration", "gridDivision", "tracks", "position", "ppq", "snapToGrid", "verticalPosition", "verticalZoom", "zoom", "onInsertNote", "onNoteChange", "onPositionChange", "onRemoveNote", "onVerticalPositionChange", "onVerticalZoomChange", "onZoomChange", "showAllTracks", "selectedTrackIndex", "onSelectedTrackIndexChange"]);
44
44
 
45
- const _tmpl$$8 = /*#__PURE__*/web.template(`<input max="500" min="1" step="0.01">`, 1);
46
- const HorizontalZoomControl = props => {
47
- const context = usePianoRollContext();
48
- return (() => {
49
- const _el$ = _tmpl$$8.cloneNode(true);
50
- web.spread(_el$, web.mergeProps(props, {
51
- get value() {
52
- return context.zoom;
53
- },
54
- "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
55
- "type": "range",
56
- get style() {
57
- return {
58
- "margin-left": "50px",
59
- "margin-right": "16px",
60
- ...(typeof props.style === "object" && props.style)
61
- };
62
- }
63
- }), false, false);
64
- return _el$;
65
- })();
66
- };
45
+ var css_248z$3 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\n width: 50px;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n}\n\n.PianoRollKeys-module_whiteAndNextIsWhite__PN1O8 {\n border-top-width: 0.1px;\n}\n\n.PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q {\n border-bottom-width: 0.1px;\n}\n";
46
+ var styles$3 = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","Key":"PianoRollKeys-module_Key__jybNC","black":"PianoRollKeys-module_black__7rncB","white":"PianoRollKeys-module_white__fR2Lm","whiteAndNextIsWhite":"PianoRollKeys-module_whiteAndNextIsWhite__PN1O8","whiteAndPreviousIsWhite":"PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q"};
47
+ styleInject(css_248z$3);
67
48
 
68
49
  function createViewPortDimension(getState) {
69
50
  const getStateWithFunctions = () => ({
@@ -137,6 +118,65 @@ const useViewPortDimension = name => {
137
118
  return viewPort;
138
119
  };
139
120
 
121
+ const _tmpl$$8 = /*#__PURE__*/web.template(`<div></div>`, 2);
122
+ const PianoRollKeys = () => {
123
+ const viewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
124
+ return (() => {
125
+ const _el$ = _tmpl$$8.cloneNode(true);
126
+ web.insert(_el$, web.createComponent(solidJs.Index, {
127
+ each: keys,
128
+ children: key => {
129
+ const virtualDimensions = solidJs.createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
130
+ return web.createComponent(solidJs.Show, {
131
+ get when() {
132
+ return virtualDimensions().size > 0;
133
+ },
134
+ get children() {
135
+ const _el$2 = _tmpl$$8.cloneNode(true);
136
+ web.effect(_p$ => {
137
+ const _v$ = {
138
+ [styles$3["Key"]]: true,
139
+ [styles$3["black"]]: key().isBlack,
140
+ [styles$3["white"]]: !key().isBlack,
141
+ [styles$3["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
142
+ [styles$3["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
143
+ },
144
+ _v$2 = key().name,
145
+ _v$3 = key().number % 12,
146
+ _v$4 = `${virtualDimensions().offset}px`,
147
+ _v$5 = `${virtualDimensions().size}px`;
148
+ _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
149
+ _v$2 !== _p$._v$2 && web.setAttribute(_el$2, "title", _p$._v$2 = _v$2);
150
+ _v$3 !== _p$._v$3 && web.setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
151
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
152
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
153
+ return _p$;
154
+ }, {
155
+ _v$: undefined,
156
+ _v$2: undefined,
157
+ _v$3: undefined,
158
+ _v$4: undefined,
159
+ _v$5: undefined
160
+ });
161
+ return _el$2;
162
+ }
163
+ });
164
+ }
165
+ }));
166
+ web.effect(() => web.className(_el$, styles$3.PianoRollKeys));
167
+ return _el$;
168
+ })();
169
+ };
170
+ const blackKeys = [1, 3, 6, 8, 10];
171
+ const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
172
+ const keys = Array.from({
173
+ length: 128
174
+ }).map((_, index) => ({
175
+ number: index,
176
+ name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
177
+ isBlack: blackKeys.includes(index % 12)
178
+ }));
179
+
140
180
  var css_248z$2 = ".PianoRollNotes-module_PianoRollNotes__6pF-y {\n position: absolute;\n flex: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 1;\n cursor: grab;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb {\n position: absolute;\n box-sizing: border-box;\n border-width: 0.5px;\n border-style: solid;\n border-color: #a00;\n cursor: move;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimStart__vuBlj {\n cursor: w-resize;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimEnd__zPdjr {\n cursor: e-resize;\n}";
141
181
  var styles$2 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
142
182
  styleInject(css_248z$2);
@@ -150,10 +190,11 @@ const PianoRollNotes = props => {
150
190
  const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
151
191
  const insertOrUpdateNote = event => {
152
192
  const position = horizontalViewPort().calculatePosition(event.clientX);
153
- const midi = context.condensed ? 60 : 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
193
+ const existingNote = currentNote();
194
+ const midi = context.mode === "keys" ? 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY)) : existingNote?.midi ?? 60;
195
+ const targetTrackIndex = context.mode === "tracks" ? Math.floor(verticalViewPort().calculatePosition(event.clientY)) : context.selectedTrackIndex ?? 0;
154
196
  const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
155
197
  const velocity = 127;
156
- const existingNote = newNote();
157
198
  const ticks = existingNote?.ticks ?? eventPositionTicks;
158
199
  const durationTicks = existingNote?.ticks ? eventPositionTicks - existingNote?.ticks : gridDivisionTicks();
159
200
  const note = {
@@ -163,25 +204,26 @@ const PianoRollNotes = props => {
163
204
  velocity
164
205
  };
165
206
  if (existingNote) {
166
- context.onNoteChange?.(newNoteIndex(), note);
167
- return newNoteIndex();
207
+ context.onNoteChange?.(currentNoteTrackIndex(), currentNoteIndex(), note);
208
+ return currentNoteIndex();
168
209
  } else {
169
- return context.onInsertNote?.(note) ?? -1;
210
+ return context.onInsertNote?.(targetTrackIndex, note) ?? -1;
170
211
  }
171
212
  };
172
213
  const [isDragging, setIsDragging] = solidJs.createSignal(false);
173
214
  const [noteDragMode, setNoteDragMode] = solidJs.createSignal();
174
- const [newNoteIndex, setNewNoteIndex] = solidJs.createSignal(-1);
215
+ const [currentNoteIndex, setCurrentNoteIndex] = solidJs.createSignal(-1);
216
+ const [currentNoteTrackIndex, setCurrentNoteTrackIndex] = solidJs.createSignal(-1);
175
217
  const [isMouseDown, setIsMouseDown] = solidJs.createSignal(false);
176
- const newNote = solidJs.createMemo(() => context.notes[newNoteIndex()]);
218
+ const currentNote = solidJs.createMemo(() => context.tracks[currentNoteTrackIndex()]?.notes[currentNoteIndex()]);
177
219
  const getClasses = noteDragMode => {
178
220
  return noteDragMode ? [styles$2.Note, styles$2[noteDragMode]] : [styles$2.Note];
179
221
  };
180
222
  return (() => {
181
223
  const _el$ = _tmpl$$7.cloneNode(true);
182
224
  _el$.$$click = event => {
183
- if (newNote()) {
184
- setNewNoteIndex(-1);
225
+ if (currentNote()) {
226
+ setCurrentNoteIndex(-1);
185
227
  return;
186
228
  }
187
229
  if (!event.altKey) return;
@@ -202,94 +244,133 @@ const PianoRollNotes = props => {
202
244
  return;
203
245
  }
204
246
  const index = insertOrUpdateNote(event);
205
- setNewNoteIndex(index);
247
+ setCurrentNoteIndex(index);
206
248
  };
207
249
  _el$.$$mousedown = event => {
208
- console.log("down");
209
- setIsMouseDown(true);
210
- const index = insertOrUpdateNote(event);
211
- setNewNoteIndex(index);
250
+ solidJs.batch(() => {
251
+ setIsMouseDown(true);
252
+ const index = insertOrUpdateNote(event);
253
+ setCurrentNoteTrackIndex(context.selectedTrackIndex ?? 0);
254
+ setCurrentNoteIndex(index);
255
+ });
212
256
  };
213
257
  const _ref$ = props.ref;
214
258
  typeof _ref$ === "function" ? web.use(_ref$, _el$) : props.ref = _el$;
215
- web.insert(_el$, web.createComponent(solidJs.Index, {
259
+ web.insert(_el$, web.createComponent(solidJs.For, {
216
260
  get each() {
217
- return context.notes;
261
+ return context.tracks;
218
262
  },
219
- children: (note, index) => {
220
- const verticalVirtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
221
- const horizontalDimensions = solidJs.createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
263
+ children: (track, trackIndex) => {
222
264
  return web.createComponent(solidJs.Show, {
223
265
  get when() {
224
- return web.memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
266
+ return trackIndex() === context.selectedTrackIndex || context.showAllTracks || context.mode === "tracks";
225
267
  },
226
268
  get children() {
227
- const _el$2 = _tmpl$$7.cloneNode(true);
228
- _el$2.$$mousedown = event => {
229
- event.stopPropagation();
230
- setIsDragging(true);
231
- const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
232
- const diffPosition = initialPosition - note().ticks;
233
- const handleMouseMove = mouseMoveEvent => {
234
- const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
235
- context.onNoteChange?.(index, {
236
- ...note(),
237
- ...(noteDragMode() === "move" && !context.condensed && {
238
- midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
239
- }),
240
- ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
241
- ticks
242
- }),
243
- ...(noteDragMode() === "trimStart" && {
244
- durationTicks: note().durationTicks + note().ticks - ticks
245
- }),
246
- ...(noteDragMode() === "trimEnd" && {
247
- durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note().ticks, mouseMoveEvent.altKey)
248
- })
269
+ return web.createComponent(solidJs.For, {
270
+ get each() {
271
+ return track.notes;
272
+ },
273
+ children: (note, noteIndex) => {
274
+ const verticalVirtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(context.mode === "keys" ? 127 - note.midi : trackIndex(), 1));
275
+ const horizontalDimensions = solidJs.createMemo(() => horizontalViewPort().calculatePixelDimensions(note.ticks, note.durationTicks));
276
+ return web.createComponent(solidJs.Show, {
277
+ get when() {
278
+ return web.memo(() => !!verticalViewPort().isVisible(verticalVirtualDimensions()))() && horizontalViewPort().isVisible(horizontalDimensions());
279
+ },
280
+ get children() {
281
+ const _el$2 = _tmpl$$7.cloneNode(true);
282
+ _el$2.$$mousedown = event => {
283
+ event.stopPropagation();
284
+ setIsDragging(true);
285
+ setCurrentNoteIndex(noteIndex());
286
+ setCurrentNoteTrackIndex(trackIndex());
287
+ const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
288
+ const diffPosition = initialPosition - note.ticks;
289
+ const handleMouseMove = mouseMoveEvent => {
290
+ const note = currentNote();
291
+ if (!note) return;
292
+ const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
293
+ const updatedNote = {
294
+ ...note,
295
+ ...(noteDragMode() === "move" && context.mode === "keys" && {
296
+ midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
297
+ }),
298
+ ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
299
+ ticks
300
+ }),
301
+ ...(noteDragMode() === "trimStart" && {
302
+ durationTicks: note.durationTicks + note.ticks - ticks
303
+ }),
304
+ ...(noteDragMode() === "trimEnd" && {
305
+ durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note.ticks, mouseMoveEvent.altKey)
306
+ })
307
+ };
308
+ const previousTrackIndex = currentNoteTrackIndex();
309
+ const previousNoteIndex = currentNoteIndex();
310
+ const targetTrackIndex = context.mode === "tracks" ? Math.floor(verticalViewPort().calculatePosition(mouseMoveEvent.clientY)) : previousTrackIndex;
311
+ if (targetTrackIndex === previousTrackIndex) {
312
+ context.onNoteChange?.(previousTrackIndex, previousNoteIndex, updatedNote);
313
+ } else {
314
+ solidJs.batch(() => {
315
+ if (context.onInsertNote) {
316
+ context.onRemoveNote?.(previousTrackIndex, previousNoteIndex);
317
+ const newNoteIndex = context.onInsertNote(targetTrackIndex, updatedNote);
318
+ setCurrentNoteTrackIndex(targetTrackIndex);
319
+ setCurrentNoteIndex(newNoteIndex);
320
+ }
321
+ });
322
+ }
323
+ };
324
+ const handleMouseUp = () => {
325
+ setIsDragging(false);
326
+ setCurrentNoteIndex(-1);
327
+ setCurrentNoteTrackIndex(-1);
328
+ window.removeEventListener("mousemove", handleMouseMove);
329
+ window.removeEventListener("mouseup", handleMouseUp);
330
+ };
331
+ window.addEventListener("mousemove", handleMouseMove);
332
+ window.addEventListener("mouseup", handleMouseUp);
333
+ };
334
+ _el$2.$$dblclick = event => {
335
+ event.stopPropagation();
336
+ context.onRemoveNote?.(trackIndex(), noteIndex());
337
+ };
338
+ _el$2.$$mousemove = event => {
339
+ if (isDragging()) return;
340
+ event.stopPropagation();
341
+ const relativeX = horizontalViewPort().calculatePixelValue(horizontalViewPort().calculatePosition(event.clientX));
342
+ const noteStartX = horizontalViewPort().calculatePixelValue(note.ticks);
343
+ const noteEndX = horizontalViewPort().calculatePixelValue(note.ticks + note.durationTicks);
344
+ setNoteDragMode(relativeX - noteStartX < 3 ? "trimStart" : noteEndX - relativeX < 3 ? "trimEnd" : "move");
345
+ };
346
+ web.setAttribute(_el$2, "draggable", false);
347
+ web.effect(_p$ => {
348
+ const _v$ = getClasses(noteDragMode()).join(" "),
349
+ _v$2 = `rgba(255,0,0, ${(128 + note.velocity) / 256})`,
350
+ _v$3 = `${verticalVirtualDimensions().offset}px`,
351
+ _v$4 = `${verticalVirtualDimensions().size}px`,
352
+ _v$5 = `${horizontalDimensions().offset}px`,
353
+ _v$6 = `${horizontalDimensions().size}px`;
354
+ _v$ !== _p$._v$ && web.className(_el$2, _p$._v$ = _v$);
355
+ _v$2 !== _p$._v$2 && _el$2.style.setProperty("background-color", _p$._v$2 = _v$2);
356
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
357
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
358
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("left", _p$._v$5 = _v$5);
359
+ _v$6 !== _p$._v$6 && _el$2.style.setProperty("width", _p$._v$6 = _v$6);
360
+ return _p$;
361
+ }, {
362
+ _v$: undefined,
363
+ _v$2: undefined,
364
+ _v$3: undefined,
365
+ _v$4: undefined,
366
+ _v$5: undefined,
367
+ _v$6: undefined
368
+ });
369
+ return _el$2;
370
+ }
249
371
  });
250
- };
251
- const handleMouseUp = () => {
252
- setIsDragging(false);
253
- window.removeEventListener("mousemove", handleMouseMove);
254
- window.removeEventListener("mouseup", handleMouseUp);
255
- };
256
- window.addEventListener("mousemove", handleMouseMove);
257
- window.addEventListener("mouseup", handleMouseUp);
258
- };
259
- _el$2.$$dblclick = event => {
260
- event.stopPropagation();
261
- context.onRemoveNote?.(index);
262
- };
263
- _el$2.$$mousemove = event => {
264
- if (isDragging()) return;
265
- event.stopPropagation();
266
- const relativeX = horizontalViewPort().calculatePixelValue(horizontalViewPort().calculatePosition(event.clientX));
267
- const noteStartX = horizontalViewPort().calculatePixelValue(note().ticks);
268
- const noteEndX = horizontalViewPort().calculatePixelValue(note().ticks + note().durationTicks);
269
- setNoteDragMode(relativeX - noteStartX < 3 ? "trimStart" : noteEndX - relativeX < 3 ? "trimEnd" : "move");
270
- };
271
- web.effect(_p$ => {
272
- const _v$ = getClasses(noteDragMode()).join(" "),
273
- _v$2 = {
274
- "background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
275
- ...(context.condensed ? {
276
- top: 0,
277
- height: "100%"
278
- } : {
279
- top: `${verticalVirtualDimensions().offset}px`,
280
- height: `${verticalVirtualDimensions().size}px`
281
- }),
282
- left: `${horizontalDimensions().offset}px`,
283
- width: `${horizontalDimensions().size}px`
284
- };
285
- _v$ !== _p$._v$ && web.className(_el$2, _p$._v$ = _v$);
286
- _p$._v$2 = web.style(_el$2, _v$2, _p$._v$2);
287
- return _p$;
288
- }, {
289
- _v$: undefined,
290
- _v$2: undefined
372
+ }
291
373
  });
292
- return _el$2;
293
374
  }
294
375
  });
295
376
  }
@@ -403,74 +484,11 @@ const ScrollContainer = props => {
403
484
  })();
404
485
  };
405
486
 
406
- var css_248z$1 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\n width: 50px;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n}\n\n.PianoRollKeys-module_whiteAndNextIsWhite__PN1O8 {\n border-top-width: 0.1px;\n}\n\n.PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q {\n border-bottom-width: 0.1px;\n}\n";
407
- var styles$1 = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","Key":"PianoRollKeys-module_Key__jybNC","black":"PianoRollKeys-module_black__7rncB","white":"PianoRollKeys-module_white__fR2Lm","whiteAndNextIsWhite":"PianoRollKeys-module_whiteAndNextIsWhite__PN1O8","whiteAndPreviousIsWhite":"PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q"};
487
+ var css_248z$1 = ".PianoRollGrid-module_PianoRollGrid__tG119 {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Row__nRMCs {\n position: absolute;\n border-style: solid;\n border-color: gray;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Time__jLz3E {\n position: absolute;\n box-sizing: border-box;\n top: 0px;\n height: 100%;\n border-left-style: solid;\n border-left-width: 0.5px;\n}\n";
488
+ var styles$1 = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Row":"PianoRollGrid-module_PianoRollGrid-Row__nRMCs","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
408
489
  styleInject(css_248z$1);
409
490
 
410
491
  const _tmpl$$5 = /*#__PURE__*/web.template(`<div></div>`, 2);
411
- const PianoRollKeys = () => {
412
- const viewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
413
- return (() => {
414
- const _el$ = _tmpl$$5.cloneNode(true);
415
- web.insert(_el$, web.createComponent(solidJs.Index, {
416
- each: keys,
417
- children: key => {
418
- const virtualDimensions = solidJs.createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
419
- return web.createComponent(solidJs.Show, {
420
- get when() {
421
- return virtualDimensions().size > 0;
422
- },
423
- get children() {
424
- const _el$2 = _tmpl$$5.cloneNode(true);
425
- web.effect(_p$ => {
426
- const _v$ = {
427
- [styles$1["Key"]]: true,
428
- [styles$1["black"]]: key().isBlack,
429
- [styles$1["white"]]: !key().isBlack,
430
- [styles$1["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
431
- [styles$1["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
432
- },
433
- _v$2 = key().name,
434
- _v$3 = key().number % 12,
435
- _v$4 = `${virtualDimensions().offset}px`,
436
- _v$5 = `${virtualDimensions().size}px`;
437
- _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
438
- _v$2 !== _p$._v$2 && web.setAttribute(_el$2, "title", _p$._v$2 = _v$2);
439
- _v$3 !== _p$._v$3 && web.setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
440
- _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
441
- _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
442
- return _p$;
443
- }, {
444
- _v$: undefined,
445
- _v$2: undefined,
446
- _v$3: undefined,
447
- _v$4: undefined,
448
- _v$5: undefined
449
- });
450
- return _el$2;
451
- }
452
- });
453
- }
454
- }));
455
- web.effect(() => web.className(_el$, styles$1.PianoRollKeys));
456
- return _el$;
457
- })();
458
- };
459
- const blackKeys = [1, 3, 6, 8, 10];
460
- const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
461
- const keys = Array.from({
462
- length: 128
463
- }).map((_, index) => ({
464
- number: index,
465
- name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
466
- isBlack: blackKeys.includes(index % 12)
467
- }));
468
-
469
- var css_248z = ".PianoRollGrid-module_PianoRollGrid__tG119 {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Key__VRbiB {\n position: absolute;\n border-style: solid;\n border-color: gray;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Time__jLz3E {\n position: absolute;\n box-sizing: border-box;\n top: 0px;\n height: 100%;\n border-left-style: solid;\n border-left-width: 0.5px;\n}\n";
470
- var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
471
- styleInject(css_248z);
472
-
473
- const _tmpl$$4 = /*#__PURE__*/web.template(`<div></div>`, 2);
474
492
  const PianoRollGrid = () => {
475
493
  const context = usePianoRollContext();
476
494
  const verticalViewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
@@ -500,7 +518,7 @@ const PianoRollGrid = () => {
500
518
  }));
501
519
  });
502
520
  return (() => {
503
- const _el$ = _tmpl$$4.cloneNode(true);
521
+ const _el$ = _tmpl$$5.cloneNode(true);
504
522
  web.insert(_el$, web.createComponent(solidJs.Index, {
505
523
  get each() {
506
524
  return gridArray();
@@ -512,9 +530,9 @@ const PianoRollGrid = () => {
512
530
  return virtualDimensions().size > 0;
513
531
  },
514
532
  get children() {
515
- const _el$2 = _tmpl$$4.cloneNode(true);
533
+ const _el$2 = _tmpl$$5.cloneNode(true);
516
534
  web.effect(_p$ => {
517
- const _v$ = styles["PianoRollGrid-Time"],
535
+ const _v$ = styles$1["PianoRollGrid-Time"],
518
536
  _v$2 = Math.ceil((entry().index + 1 * selectedGridDivisorTicks()) / measureTicks()) % 2 === 0 ? "#ddd" : "#ccc",
519
537
  _v$3 = `${virtualDimensions().offset}px`,
520
538
  _v$4 = `${virtualDimensions().size}px`,
@@ -539,7 +557,7 @@ const PianoRollGrid = () => {
539
557
  }), null);
540
558
  web.insert(_el$, web.createComponent(solidJs.Show, {
541
559
  get when() {
542
- return !context.condensed;
560
+ return context.mode === "keys";
543
561
  },
544
562
  get children() {
545
563
  return web.createComponent(solidJs.Index, {
@@ -551,10 +569,10 @@ const PianoRollGrid = () => {
551
569
  return virtualDimensions().size > 0;
552
570
  },
553
571
  get children() {
554
- const _el$3 = _tmpl$$4.cloneNode(true);
572
+ const _el$3 = _tmpl$$5.cloneNode(true);
555
573
  _el$3.style.setProperty("width", "100%");
556
574
  web.effect(_p$ => {
557
- const _v$6 = styles["PianoRollGrid-Key"],
575
+ const _v$6 = styles$1["PianoRollGrid-Row"],
558
576
  _v$7 = `${virtualDimensions().offset}px`,
559
577
  _v$8 = `${virtualDimensions().size}px`,
560
578
  _v$9 = key().isBlack ? "rgba(0,0,0,0.2)" : "none",
@@ -579,35 +597,53 @@ const PianoRollGrid = () => {
579
597
  });
580
598
  }
581
599
  }), null);
582
- web.effect(() => web.className(_el$, styles.PianoRollGrid));
600
+ web.insert(_el$, web.createComponent(solidJs.Show, {
601
+ get when() {
602
+ return context.mode === "tracks";
603
+ },
604
+ get children() {
605
+ return web.createComponent(solidJs.For, {
606
+ get each() {
607
+ return context.tracks;
608
+ },
609
+ children: (track, index) => {
610
+ const virtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(index(), 1));
611
+ return web.createComponent(solidJs.Show, {
612
+ get when() {
613
+ return virtualDimensions().size > 0;
614
+ },
615
+ get children() {
616
+ const _el$4 = _tmpl$$5.cloneNode(true);
617
+ _el$4.style.setProperty("width", "100%");
618
+ _el$4.style.setProperty("border-width", "0");
619
+ web.effect(_p$ => {
620
+ const _v$11 = styles$1["PianoRollGrid-Row"],
621
+ _v$12 = `${virtualDimensions().offset}px`,
622
+ _v$13 = `${virtualDimensions().size}px`,
623
+ _v$14 = index() % 2 === 0 ? "rgba(0,0,0,0.2)" : "none";
624
+ _v$11 !== _p$._v$11 && web.className(_el$4, _p$._v$11 = _v$11);
625
+ _v$12 !== _p$._v$12 && _el$4.style.setProperty("top", _p$._v$12 = _v$12);
626
+ _v$13 !== _p$._v$13 && _el$4.style.setProperty("height", _p$._v$13 = _v$13);
627
+ _v$14 !== _p$._v$14 && _el$4.style.setProperty("background-color", _p$._v$14 = _v$14);
628
+ return _p$;
629
+ }, {
630
+ _v$11: undefined,
631
+ _v$12: undefined,
632
+ _v$13: undefined,
633
+ _v$14: undefined
634
+ });
635
+ return _el$4;
636
+ }
637
+ });
638
+ }
639
+ });
640
+ }
641
+ }), null);
642
+ web.effect(() => web.className(_el$, styles$1.PianoRollGrid));
583
643
  return _el$;
584
644
  })();
585
645
  };
586
646
 
587
- const useNotes = () => {
588
- const [notes, onNotesChange] = solidJs.createSignal([]);
589
- const onNoteChange = (index, note) => {
590
- onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
591
- };
592
- const onInsertNote = note => {
593
- const index = Math.max(notes().findIndex(({
594
- ticks
595
- }) => ticks > note.ticks), 0);
596
- onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
597
- return index;
598
- };
599
- const onRemoveNote = index => {
600
- onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
601
- };
602
- return {
603
- notes,
604
- onNotesChange,
605
- onNoteChange,
606
- onInsertNote,
607
- onRemoveNote
608
- };
609
- };
610
-
611
647
  const defaultRect = {
612
648
  left: 0,
613
649
  width: 0,
@@ -636,11 +672,11 @@ function useBoundingClientRect(containerRef) {
636
672
  return boundingClientRect;
637
673
  }
638
674
 
639
- const _tmpl$$3 = /*#__PURE__*/web.template(`<input min="1" max="11" step="0.01">`, 1);
675
+ const _tmpl$$4 = /*#__PURE__*/web.template(`<input min="1" max="11" step="0.01">`, 1);
640
676
  const VerticalZoomControl = props => {
641
677
  const context = usePianoRollContext();
642
678
  return (() => {
643
- const _el$ = _tmpl$$3.cloneNode(true);
679
+ const _el$ = _tmpl$$4.cloneNode(true);
644
680
  web.spread(_el$, web.mergeProps(props, {
645
681
  get value() {
646
682
  return context.verticalZoom;
@@ -664,224 +700,91 @@ const VerticalZoomControl = props => {
664
700
  })();
665
701
  };
666
702
 
667
- const _tmpl$$2 = /*#__PURE__*/web.template(`<div><ul></ul></div>`, 4),
668
- _tmpl$2 = /*#__PURE__*/web.template(`<ul></ul>`, 2),
669
- _tmpl$3 = /*#__PURE__*/web.template(`<div><div></div></div>`, 4),
670
- _tmpl$4 = /*#__PURE__*/web.template(`<div></div>`, 2),
671
- _tmpl$5 = /*#__PURE__*/web.template(`<li></li>`, 2);
672
- const MultiTrackPianoRoll = allProps => {
673
- const selectedTrack = solidJs.createMemo(() => allProps.tracks[allProps.selectedTrackIndex]);
674
- const condensed = solidJs.createMemo(() => !selectedTrack());
675
- const [ownProps, restProps] = solidJs.splitProps(allProps, ["tracks", "selectedTrackIndex"]);
676
- const [contextProps, divProps] = splitContextProps(solidJs.mergeProps(restProps, {
677
- notes: [],
678
- condensed: false,
679
- onNoteChange: () => undefined,
680
- onInsertNote: () => -1,
681
- onRemoveNote: () => undefined
682
- }));
683
- const [scrollerRef, setScrollerRef] = solidJs.createSignal();
684
- const clientRect = useBoundingClientRect(scrollerRef);
685
- const zoomFactor = 500;
686
- const minZoom = solidJs.createMemo(() => 1 / (zoomFactor / clientRect().width));
687
- const maxZoom = solidJs.createMemo(() => 500 * (zoomFactor / clientRect().width));
688
- const minVerticalZoom = solidJs.createMemo(() => 1 / (zoomFactor / clientRect().height));
689
- const maxVerticalZoom = solidJs.createMemo(() => 10 * (zoomFactor / clientRect().height));
703
+ const _tmpl$$3 = /*#__PURE__*/web.template(`<input max="500" min="1" step="0.01">`, 1);
704
+ const HorizontalZoomControl = props => {
705
+ const context = usePianoRollContext();
690
706
  return (() => {
691
- const _el$ = _tmpl$4.cloneNode(true);
692
- web.spread(_el$, web.mergeProps(divProps, {
707
+ const _el$ = _tmpl$$3.cloneNode(true);
708
+ web.spread(_el$, web.mergeProps(props, {
709
+ get value() {
710
+ return context.zoom;
711
+ },
712
+ "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
713
+ "type": "range",
693
714
  get style() {
694
715
  return {
695
- display: "flex",
696
- flex: 1,
697
- height: "100%",
698
- "flex-direction": "row",
699
- overflow: "hidden",
700
- ...(typeof divProps.style === "object" && divProps.style)
716
+ "margin-left": "50px",
717
+ "margin-right": "16px",
718
+ ...(typeof props.style === "object" && props.style)
701
719
  };
702
720
  }
703
- }), false, true);
704
- web.insert(_el$, web.createComponent(PianoRollContextProvider, {
705
- get value() {
706
- return {
707
- ...contextProps
708
- };
721
+ }), false, false);
722
+ return _el$;
723
+ })();
724
+ };
725
+
726
+ var css_248z = ".PianoRollTrackList-module_PianoRollTrackList__pyuxQ {\n position: relative;\n height: 100%;\n flex: 1;\n}\n\n.PianoRollTrackList-module_Track__VZFIg {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n border-bottom-width: 1px;\n}\n";
727
+ var styles = {"PianoRollTrackList":"PianoRollTrackList-module_PianoRollTrackList__pyuxQ","Track":"PianoRollTrackList-module_Track__VZFIg"};
728
+ styleInject(css_248z);
729
+
730
+ const _tmpl$$2 = /*#__PURE__*/web.template(`<div></div>`, 2),
731
+ _tmpl$2$1 = /*#__PURE__*/web.template(`<div> </div>`, 2);
732
+ const PianoRollTrackList = () => {
733
+ const viewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
734
+ const context = usePianoRollContext();
735
+ return (() => {
736
+ const _el$ = _tmpl$$2.cloneNode(true);
737
+ web.insert(_el$, web.createComponent(solidJs.Index, {
738
+ get each() {
739
+ return context.tracks;
709
740
  },
710
- get children() {
711
- return web.createComponent(ScrollZoomViewPort, {
712
- dimensions: {
713
- horizontal: () => ({
714
- pixelOffset: clientRect().left,
715
- pixelSize: clientRect().width,
716
- position: contextProps.position,
717
- range: contextProps.duration,
718
- zoom: contextProps.zoom * (zoomFactor / clientRect().width),
719
- onPositionChange: contextProps.onPositionChange,
720
- onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
721
- }),
722
- vertical: () => ({
723
- pixelOffset: clientRect().top,
724
- pixelSize: clientRect().height,
725
- position: contextProps.verticalPosition,
726
- range: 128,
727
- zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
728
- onPositionChange: contextProps.onVerticalPositionChange,
729
- onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
730
- })
741
+ children: (track, index) => {
742
+ const virtualDimensions = solidJs.createMemo(() => viewPort().calculatePixelDimensions(context.mode === "tracks" ? index : index * 8, context.mode === "tracks" ? 1 : 8));
743
+ return web.createComponent(solidJs.Show, {
744
+ get when() {
745
+ return virtualDimensions().size > 0;
731
746
  },
732
747
  get children() {
733
- return [(() => {
734
- const _el$2 = _tmpl$$2.cloneNode(true),
735
- _el$3 = _el$2.firstChild;
736
- _el$2.style.setProperty("width", "250px");
737
- _el$2.style.setProperty("display", "flex");
738
- _el$2.style.setProperty("flex-direction", "row");
739
- _el$3.style.setProperty("margin-block-start", "0");
740
- _el$3.style.setProperty("padding-inline-start", "0");
741
- _el$3.style.setProperty("flex", "1");
742
- _el$3.style.setProperty("position", "relative");
743
- web.insert(_el$3, web.createComponent(solidJs.Index, {
744
- get each() {
745
- return allProps.tracks;
746
- },
747
- children: (track, noteIndex) => (() => {
748
- const _el$7 = _tmpl$5.cloneNode(true);
749
- _el$7.$$click = () => {
750
- if (noteIndex === allProps.selectedTrackIndex) {
751
- allProps.onSelectedTrackIndexChange(-1);
752
- } else {
753
- allProps.onSelectedTrackIndexChange(noteIndex);
754
- }
755
- };
756
- _el$7.style.setProperty("width", "100%");
757
- _el$7.style.setProperty("height", "30px");
758
- _el$7.style.setProperty("list-style", "none");
759
- _el$7.style.setProperty("display", "flex");
760
- _el$7.style.setProperty("align-items", "center");
761
- _el$7.style.setProperty("border-top", "1px black solid");
762
- _el$7.style.setProperty("cursor", "pointer");
763
- web.insert(_el$7, () => track().name);
764
- web.effect(() => _el$7.style.setProperty("background", noteIndex === allProps.selectedTrackIndex ? "lightgray" : "none"));
765
- return _el$7;
766
- })()
767
- }));
768
- web.insert(_el$2, web.createComponent(solidJs.Show, {
769
- get when() {
770
- return !condensed();
771
- },
772
- get children() {
773
- return web.createComponent(PianoRollKeys, {});
774
- }
775
- }), null);
776
- return _el$2;
777
- })(), (() => {
778
- const _el$4 = _tmpl$3.cloneNode(true),
779
- _el$5 = _el$4.firstChild;
780
- _el$4.style.setProperty("flex", "1");
781
- web.insert(_el$5, web.createComponent(ScrollContainer, {
782
- ref: setScrollerRef,
783
- get children() {
784
- return [web.memo(() => allProps.children), (() => {
785
- const _el$6 = _tmpl$2.cloneNode(true);
786
- _el$6.style.setProperty("margin", "0");
787
- _el$6.style.setProperty("margin-block-start", "0");
788
- _el$6.style.setProperty("padding-inline-start", "0");
789
- web.insert(_el$6, web.createComponent(solidJs.Index, {
790
- get each() {
791
- return allProps.tracks;
792
- },
793
- children: (track, trackIndex) => {
794
- const notes = useNotes();
795
- solidJs.createEffect(() => {
796
- notes.onNotesChange(track().notes);
797
- });
798
- const [context, setContext] = store.createStore({
799
- ...contextProps
800
- });
801
- solidJs.createEffect(() => {
802
- setContext({
803
- ...contextProps,
804
- condensed: condensed(),
805
- notes: track()?.notes,
806
- onNoteChange: (noteIndex, note) => allProps?.onNoteChange?.(trackIndex, noteIndex, note),
807
- onInsertNote: note => allProps.onInsertNote?.(trackIndex, note) ?? -1,
808
- onRemoveNote: noteIndex => allProps.onRemoveNote?.(trackIndex, noteIndex)
809
- });
810
- });
811
- const verticalViewPort = useViewPortDimension("vertical");
812
- return web.createComponent(solidJs.Show, {
813
- get when() {
814
- return condensed() || allProps.selectedTrackIndex === trackIndex;
815
- },
816
- get children() {
817
- return web.createComponent(PianoRollContextProvider, {
818
- value: context,
819
- get children() {
820
- const _el$8 = _tmpl$5.cloneNode(true);
821
- _el$8.style.setProperty("display", "flex");
822
- _el$8.style.setProperty("position", "relative");
823
- _el$8.style.setProperty("list-style", "none");
824
- _el$8.style.setProperty("flex-direction", "row");
825
- _el$8.style.setProperty("border-top", "1px black solid");
826
- web.insert(_el$8, web.createComponent(PianoRollNotes, {}), null);
827
- web.insert(_el$8, web.createComponent(PianoRollGrid, {}), null);
828
- web.effect(() => _el$8.style.setProperty("height", condensed() ? "30px" : `${verticalViewPort.pixelSize}px`));
829
- return _el$8;
830
- }
831
- });
832
- }
833
- });
834
- }
835
- }));
836
- return _el$6;
837
- })()];
838
- }
839
- }), null);
840
- web.insert(_el$5, web.createComponent(solidJs.Show, {
841
- get when() {
842
- return !condensed();
843
- },
844
- get children() {
845
- return web.createComponent(VerticalZoomControl, {
846
- get value() {
847
- return contextProps.verticalZoom;
848
- },
849
- onInput: event => contextProps.onVerticalZoomChange?.(event.currentTarget.valueAsNumber)
850
- });
851
- }
852
- }), null);
853
- web.insert(_el$4, web.createComponent(HorizontalZoomControl, {
854
- style: {
855
- width: "100%",
856
- "margin-left": 0
857
- },
858
- get value() {
859
- return contextProps.zoom;
748
+ const _el$2 = _tmpl$2$1.cloneNode(true),
749
+ _el$3 = _el$2.firstChild;
750
+ _el$2.$$click = () => context.onSelectedTrackIndexChange?.(index);
751
+ _el$2.style.setProperty("cursor", "pointer");
752
+ web.insert(_el$2, index, _el$3);
753
+ web.insert(_el$2, () => track().name || "[unnamed track]", null);
754
+ web.effect(_p$ => {
755
+ const _v$ = {
756
+ [styles["Track"]]: true
860
757
  },
861
- onInput: event => contextProps.onZoomChange?.(event.currentTarget.valueAsNumber)
862
- }), null);
863
- web.effect(_p$ => {
864
- const _v$ = styles$3.PianoRoll,
865
- _v$2 = styles$3.PianoRollContainer;
866
- _v$ !== _p$._v$ && web.className(_el$4, _p$._v$ = _v$);
867
- _v$2 !== _p$._v$2 && web.className(_el$5, _p$._v$2 = _v$2);
868
- return _p$;
869
- }, {
870
- _v$: undefined,
871
- _v$2: undefined
872
- });
873
- return _el$4;
874
- })()];
758
+ _v$2 = track().name,
759
+ _v$3 = `${virtualDimensions().offset}px`,
760
+ _v$4 = `${virtualDimensions().size}px`,
761
+ _v$5 = index === context.selectedTrackIndex ? "gray" : "lightgrey";
762
+ _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
763
+ _v$2 !== _p$._v$2 && web.setAttribute(_el$2, "title", _p$._v$2 = _v$2);
764
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
765
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
766
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("background", _p$._v$5 = _v$5);
767
+ return _p$;
768
+ }, {
769
+ _v$: undefined,
770
+ _v$2: undefined,
771
+ _v$3: undefined,
772
+ _v$4: undefined,
773
+ _v$5: undefined
774
+ });
775
+ return _el$2;
875
776
  }
876
777
  });
877
778
  }
878
779
  }));
780
+ web.effect(() => web.className(_el$, styles.PianoRollTrackList));
879
781
  return _el$;
880
782
  })();
881
783
  };
882
784
  web.delegateEvents(["click"]);
883
785
 
884
- const _tmpl$$1 = /*#__PURE__*/web.template(`<div><div></div></div>`, 4);
786
+ const _tmpl$$1 = /*#__PURE__*/web.template(`<div></div>`, 2),
787
+ _tmpl$2 = /*#__PURE__*/web.template(`<div><div></div></div>`, 4);
885
788
  const PianoRoll = allProps => {
886
789
  const [contextProps, divProps] = splitContextProps(allProps);
887
790
  const [scrollerRef, setScrollerRef] = solidJs.createSignal();
@@ -891,14 +794,20 @@ const PianoRoll = allProps => {
891
794
  const maxZoom = solidJs.createMemo(() => 500 * (zoomFactor / clientRect().width));
892
795
  const minVerticalZoom = solidJs.createMemo(() => 1 / (zoomFactor / clientRect().height));
893
796
  const maxVerticalZoom = solidJs.createMemo(() => 10 * (zoomFactor / clientRect().height));
797
+ solidJs.createEffect(isInitial => {
798
+ if (isInitial) return false;
799
+ if (contextProps.mode === "tracks") {
800
+ contextProps.onVerticalPositionChange?.(0);
801
+ }
802
+ }, true);
894
803
  return web.createComponent(PianoRollContextProvider, {
895
804
  value: contextProps,
896
805
  get children() {
897
- const _el$ = _tmpl$$1.cloneNode(true),
806
+ const _el$ = _tmpl$2.cloneNode(true),
898
807
  _el$2 = _el$.firstChild;
899
808
  web.spread(_el$, web.mergeProps(divProps, {
900
809
  get ["class"]() {
901
- return styles$3.PianoRoll;
810
+ return styles$4.PianoRoll;
902
811
  }
903
812
  }), false, true);
904
813
  web.insert(_el$2, web.createComponent(ScrollZoomViewPort, {
@@ -916,14 +825,35 @@ const PianoRoll = allProps => {
916
825
  pixelOffset: clientRect().top,
917
826
  pixelSize: clientRect().height,
918
827
  position: contextProps.verticalPosition,
919
- range: 128,
828
+ range: contextProps.mode === "keys" ? 128 : Math.max(contextProps.tracks.length, 16),
920
829
  zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
921
830
  onPositionChange: contextProps.onVerticalPositionChange,
922
831
  onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
923
832
  })
924
833
  },
925
834
  get children() {
926
- return [web.createComponent(PianoRollKeys, {}), web.createComponent(ScrollContainer, {
835
+ return [(() => {
836
+ const _el$3 = _tmpl$$1.cloneNode(true);
837
+ _el$3.style.setProperty("display", "flex");
838
+ _el$3.style.setProperty("width", "20%");
839
+ web.insert(_el$3, web.createComponent(solidJs.Show, {
840
+ get when() {
841
+ return allProps.showTrackList;
842
+ },
843
+ get children() {
844
+ return web.createComponent(PianoRollTrackList, {});
845
+ }
846
+ }), null);
847
+ web.insert(_el$3, web.createComponent(solidJs.Show, {
848
+ get when() {
849
+ return contextProps.mode === "keys";
850
+ },
851
+ get children() {
852
+ return web.createComponent(PianoRollKeys, {});
853
+ }
854
+ }), null);
855
+ return _el$3;
856
+ })(), web.createComponent(ScrollContainer, {
927
857
  ref: setScrollerRef,
928
858
  get children() {
929
859
  return [web.memo(() => allProps.children), web.createComponent(PianoRollGrid, {}), web.createComponent(PianoRollNotes, {})];
@@ -946,7 +876,7 @@ const PianoRoll = allProps => {
946
876
  return maxZoom();
947
877
  }
948
878
  }), null);
949
- web.effect(() => web.className(_el$2, styles$3.PianoRollContainer));
879
+ web.effect(() => web.className(_el$2, styles$4.PianoRollContainer));
950
880
  return _el$;
951
881
  }
952
882
  });
@@ -1006,13 +936,37 @@ const PlayHead = allProps => {
1006
936
  })();
1007
937
  };
1008
938
 
939
+ const useNotes = () => {
940
+ const [notes, onNotesChange] = solidJs.createSignal([]);
941
+ const onNoteChange = (index, note) => {
942
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
943
+ };
944
+ const onInsertNote = note => {
945
+ const index = Math.max(notes().findIndex(({
946
+ ticks
947
+ }) => ticks > note.ticks), 0);
948
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
949
+ return index;
950
+ };
951
+ const onRemoveNote = index => {
952
+ onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
953
+ };
954
+ return {
955
+ notes,
956
+ onNotesChange,
957
+ onNoteChange,
958
+ onInsertNote,
959
+ onRemoveNote
960
+ };
961
+ };
962
+
1009
963
  const usePianoRoll = () => {
1010
964
  const [ppq, onPpqChange] = solidJs.createSignal(120);
1011
- const [condensed, onCondensedChange] = solidJs.createSignal(false);
965
+ const [mode, onModeChange] = solidJs.createSignal("tracks");
1012
966
  const [position, onPositionChange] = solidJs.createSignal(0);
1013
967
  const [zoom, onZoomChange] = solidJs.createSignal(10);
1014
968
  const [verticalZoom, onVerticalZoomChange] = solidJs.createSignal(5);
1015
- const [verticalPosition, onVerticalPositionChange] = solidJs.createSignal(64);
969
+ const [verticalPosition, onVerticalPositionChange] = solidJs.createSignal(44);
1016
970
  const [gridDivision, onGridDivisionChange] = solidJs.createSignal(4);
1017
971
  const [snapToGrid, onSnapToGridChange] = solidJs.createSignal(true);
1018
972
  const [duration, onDurationChange] = solidJs.createSignal(0);
@@ -1031,14 +985,13 @@ const usePianoRoll = () => {
1031
985
  onGridDivisionChange,
1032
986
  snapToGrid,
1033
987
  onSnapToGridChange,
1034
- condensed,
1035
- onCondensedChange,
988
+ mode,
989
+ onModeChange,
1036
990
  duration,
1037
991
  onDurationChange
1038
992
  };
1039
993
  };
1040
994
 
1041
- exports.MultiTrackPianoRoll = MultiTrackPianoRoll;
1042
995
  exports.PianoRoll = PianoRoll;
1043
996
  exports.PlayHead = PlayHead;
1044
997
  exports.useNotes = useNotes;