solid-pianoroll 0.0.14 → 0.0.16

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 border-width: 0;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n border-left-width: 1px;\n background: white;\n cursor: pointer;\n overflow: hidden;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n transition-property: background-color, box-shadow;\n transition-duration: 400ms;\n transition-timing-function: ease-out;\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 120%;\n left: -20%;\n border-color: #000;\n border-style: solid;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n border-top-right-radius: 12%;\n border-bottom-right-radius: 12%;\n margin-left: -20%;\n z-index: 1;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n border-top-width: 0.5px;\n border-bottom-width: 0.5px;\n}\n\n.PianoRollKeys-module_down__GcNeZ {\n transition: none;\n background: red;\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","down":"PianoRollKeys-module_down__GcNeZ"};
47
+ styleInject(css_248z$3);
67
48
 
68
49
  function createViewPortDimension(getState) {
69
50
  const getStateWithFunctions = () => ({
@@ -137,6 +118,95 @@ 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 [isDown, setIsDown] = solidJs.createSignal(false);
130
+ const virtualDimensions = solidJs.createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
131
+ const previousIsBlack = blackKeys.includes((key().number - 1) % 12);
132
+ const nextIsBlack = blackKeys.includes((key().number + 1) % 12);
133
+ return web.createComponent(solidJs.Show, {
134
+ get when() {
135
+ return virtualDimensions().size > 0;
136
+ },
137
+ get children() {
138
+ const _el$2 = _tmpl$$8.cloneNode(true);
139
+ _el$2.$$mouseup = () => setIsDown(false);
140
+ _el$2.$$mousedown = () => setIsDown(true);
141
+ web.insert(_el$2, web.createComponent(solidJs.Show, {
142
+ get when() {
143
+ return key().isBlack && false;
144
+ },
145
+ get children() {
146
+ const _el$3 = _tmpl$$8.cloneNode(true);
147
+ web.effect(_p$ => {
148
+ const _v$ = styles$3["black-separator"],
149
+ _v$2 = `${virtualDimensions().offset}px`,
150
+ _v$3 = `${virtualDimensions().size / 2 - 0.25}px`;
151
+ _v$ !== _p$._v$ && web.className(_el$3, _p$._v$ = _v$);
152
+ _v$2 !== _p$._v$2 && _el$3.style.setProperty("top", _p$._v$2 = _v$2);
153
+ _v$3 !== _p$._v$3 && _el$3.style.setProperty("height", _p$._v$3 = _v$3);
154
+ return _p$;
155
+ }, {
156
+ _v$: undefined,
157
+ _v$2: undefined,
158
+ _v$3: undefined
159
+ });
160
+ return _el$3;
161
+ }
162
+ }));
163
+ web.effect(_p$ => {
164
+ const _v$4 = {
165
+ [styles$3["Key"]]: true,
166
+ [styles$3["black"]]: key().isBlack,
167
+ [styles$3["white"]]: !key().isBlack,
168
+ [styles$3["down"]]: isDown()
169
+ },
170
+ _v$5 = key().name,
171
+ _v$6 = key().number % 12,
172
+ _v$7 = `${virtualDimensions().offset - (!key().isBlack && nextIsBlack ? virtualDimensions().size / 2 : 0)}px`,
173
+ _v$8 = `${virtualDimensions().size + (!key().isBlack && nextIsBlack ? virtualDimensions().size / 2 : 0) + (!key().isBlack && previousIsBlack ? virtualDimensions().size / 2 : 0)}px`,
174
+ _v$9 = [`0px 0px ${Math.min(virtualDimensions().size / 20, 1)}px ${Math.min(virtualDimensions().size / 50, 1)}px rgba(0, 0, 0, 0.5) ${key().isBlack ? "" : "inset"}`, isDown() && `0px 0px ${Math.min(virtualDimensions().size / 8, 2)}px ${Math.min(virtualDimensions().size / 20, 2)}px rgba(0, 0, 0, 0.5) inset`].filter(item => !!item).join(", ");
175
+ _p$._v$4 = web.classList(_el$2, _v$4, _p$._v$4);
176
+ _v$5 !== _p$._v$5 && web.setAttribute(_el$2, "title", _p$._v$5 = _v$5);
177
+ _v$6 !== _p$._v$6 && web.setAttribute(_el$2, "data-index", _p$._v$6 = _v$6);
178
+ _v$7 !== _p$._v$7 && _el$2.style.setProperty("top", _p$._v$7 = _v$7);
179
+ _v$8 !== _p$._v$8 && _el$2.style.setProperty("height", _p$._v$8 = _v$8);
180
+ _v$9 !== _p$._v$9 && _el$2.style.setProperty("box-shadow", _p$._v$9 = _v$9);
181
+ return _p$;
182
+ }, {
183
+ _v$4: undefined,
184
+ _v$5: undefined,
185
+ _v$6: undefined,
186
+ _v$7: undefined,
187
+ _v$8: undefined,
188
+ _v$9: undefined
189
+ });
190
+ return _el$2;
191
+ }
192
+ });
193
+ }
194
+ }));
195
+ web.effect(() => web.className(_el$, styles$3.PianoRollKeys));
196
+ return _el$;
197
+ })();
198
+ };
199
+ const blackKeys = [1, 3, 6, 8, 10];
200
+ const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
201
+ const keys = Array.from({
202
+ length: 128
203
+ }).map((_, index) => ({
204
+ number: index,
205
+ name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
206
+ isBlack: blackKeys.includes(index % 12)
207
+ }));
208
+ web.delegateEvents(["mousedown", "mouseup"]);
209
+
140
210
  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
211
  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
212
  styleInject(css_248z$2);
@@ -150,10 +220,11 @@ const PianoRollNotes = props => {
150
220
  const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
151
221
  const insertOrUpdateNote = event => {
152
222
  const position = horizontalViewPort().calculatePosition(event.clientX);
153
- const midi = context.condensed ? 60 : 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
223
+ const existingNote = currentNote();
224
+ const midi = context.mode === "keys" ? 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY)) : existingNote?.midi ?? 60;
225
+ const targetTrackIndex = context.mode === "tracks" ? Math.floor(verticalViewPort().calculatePosition(event.clientY)) : context.selectedTrackIndex ?? 0;
154
226
  const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
155
227
  const velocity = 127;
156
- const existingNote = newNote();
157
228
  const ticks = existingNote?.ticks ?? eventPositionTicks;
158
229
  const durationTicks = existingNote?.ticks ? eventPositionTicks - existingNote?.ticks : gridDivisionTicks();
159
230
  const note = {
@@ -163,25 +234,26 @@ const PianoRollNotes = props => {
163
234
  velocity
164
235
  };
165
236
  if (existingNote) {
166
- context.onNoteChange?.(newNoteIndex(), note);
167
- return newNoteIndex();
237
+ context.onNoteChange?.(currentNoteTrackIndex(), currentNoteIndex(), note);
238
+ return currentNoteIndex();
168
239
  } else {
169
- return context.onInsertNote?.(note) ?? -1;
240
+ return context.onInsertNote?.(targetTrackIndex, note) ?? -1;
170
241
  }
171
242
  };
172
243
  const [isDragging, setIsDragging] = solidJs.createSignal(false);
173
244
  const [noteDragMode, setNoteDragMode] = solidJs.createSignal();
174
- const [newNoteIndex, setNewNoteIndex] = solidJs.createSignal(-1);
245
+ const [currentNoteIndex, setCurrentNoteIndex] = solidJs.createSignal(-1);
246
+ const [currentNoteTrackIndex, setCurrentNoteTrackIndex] = solidJs.createSignal(-1);
175
247
  const [isMouseDown, setIsMouseDown] = solidJs.createSignal(false);
176
- const newNote = solidJs.createMemo(() => context.notes[newNoteIndex()]);
248
+ const currentNote = solidJs.createMemo(() => context.tracks[currentNoteTrackIndex()]?.notes[currentNoteIndex()]);
177
249
  const getClasses = noteDragMode => {
178
250
  return noteDragMode ? [styles$2.Note, styles$2[noteDragMode]] : [styles$2.Note];
179
251
  };
180
252
  return (() => {
181
253
  const _el$ = _tmpl$$7.cloneNode(true);
182
254
  _el$.$$click = event => {
183
- if (newNote()) {
184
- setNewNoteIndex(-1);
255
+ if (currentNote()) {
256
+ setCurrentNoteIndex(-1);
185
257
  return;
186
258
  }
187
259
  if (!event.altKey) return;
@@ -202,94 +274,133 @@ const PianoRollNotes = props => {
202
274
  return;
203
275
  }
204
276
  const index = insertOrUpdateNote(event);
205
- setNewNoteIndex(index);
277
+ setCurrentNoteIndex(index);
206
278
  };
207
279
  _el$.$$mousedown = event => {
208
- console.log("down");
209
- setIsMouseDown(true);
210
- const index = insertOrUpdateNote(event);
211
- setNewNoteIndex(index);
280
+ solidJs.batch(() => {
281
+ setIsMouseDown(true);
282
+ const index = insertOrUpdateNote(event);
283
+ setCurrentNoteTrackIndex(context.selectedTrackIndex ?? 0);
284
+ setCurrentNoteIndex(index);
285
+ });
212
286
  };
213
287
  const _ref$ = props.ref;
214
288
  typeof _ref$ === "function" ? web.use(_ref$, _el$) : props.ref = _el$;
215
- web.insert(_el$, web.createComponent(solidJs.Index, {
289
+ web.insert(_el$, web.createComponent(solidJs.For, {
216
290
  get each() {
217
- return context.notes;
291
+ return context.tracks;
218
292
  },
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));
293
+ children: (track, trackIndex) => {
222
294
  return web.createComponent(solidJs.Show, {
223
295
  get when() {
224
- return web.memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
296
+ return trackIndex() === context.selectedTrackIndex || context.showAllTracks || context.mode === "tracks";
225
297
  },
226
298
  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
- })
299
+ return web.createComponent(solidJs.For, {
300
+ get each() {
301
+ return track.notes;
302
+ },
303
+ children: (note, noteIndex) => {
304
+ const verticalVirtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(context.mode === "keys" ? 127 - note.midi : trackIndex(), 1));
305
+ const horizontalDimensions = solidJs.createMemo(() => horizontalViewPort().calculatePixelDimensions(note.ticks, note.durationTicks));
306
+ return web.createComponent(solidJs.Show, {
307
+ get when() {
308
+ return web.memo(() => !!verticalViewPort().isVisible(verticalVirtualDimensions()))() && horizontalViewPort().isVisible(horizontalDimensions());
309
+ },
310
+ get children() {
311
+ const _el$2 = _tmpl$$7.cloneNode(true);
312
+ _el$2.$$mousedown = event => {
313
+ event.stopPropagation();
314
+ setIsDragging(true);
315
+ setCurrentNoteIndex(noteIndex());
316
+ setCurrentNoteTrackIndex(trackIndex());
317
+ const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
318
+ const diffPosition = initialPosition - note.ticks;
319
+ const handleMouseMove = mouseMoveEvent => {
320
+ const note = currentNote();
321
+ if (!note) return;
322
+ const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
323
+ const updatedNote = {
324
+ ...note,
325
+ ...(noteDragMode() === "move" && context.mode === "keys" && {
326
+ midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
327
+ }),
328
+ ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
329
+ ticks
330
+ }),
331
+ ...(noteDragMode() === "trimStart" && {
332
+ durationTicks: note.durationTicks + note.ticks - ticks
333
+ }),
334
+ ...(noteDragMode() === "trimEnd" && {
335
+ durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note.ticks, mouseMoveEvent.altKey)
336
+ })
337
+ };
338
+ const previousTrackIndex = currentNoteTrackIndex();
339
+ const previousNoteIndex = currentNoteIndex();
340
+ const targetTrackIndex = context.mode === "tracks" ? Math.floor(verticalViewPort().calculatePosition(mouseMoveEvent.clientY)) : previousTrackIndex;
341
+ if (targetTrackIndex === previousTrackIndex) {
342
+ context.onNoteChange?.(previousTrackIndex, previousNoteIndex, updatedNote);
343
+ } else {
344
+ solidJs.batch(() => {
345
+ if (context.onInsertNote) {
346
+ context.onRemoveNote?.(previousTrackIndex, previousNoteIndex);
347
+ const newNoteIndex = context.onInsertNote(targetTrackIndex, updatedNote);
348
+ setCurrentNoteTrackIndex(targetTrackIndex);
349
+ setCurrentNoteIndex(newNoteIndex);
350
+ }
351
+ });
352
+ }
353
+ };
354
+ const handleMouseUp = () => {
355
+ setIsDragging(false);
356
+ setCurrentNoteIndex(-1);
357
+ setCurrentNoteTrackIndex(-1);
358
+ window.removeEventListener("mousemove", handleMouseMove);
359
+ window.removeEventListener("mouseup", handleMouseUp);
360
+ };
361
+ window.addEventListener("mousemove", handleMouseMove);
362
+ window.addEventListener("mouseup", handleMouseUp);
363
+ };
364
+ _el$2.$$dblclick = event => {
365
+ event.stopPropagation();
366
+ context.onRemoveNote?.(trackIndex(), noteIndex());
367
+ };
368
+ _el$2.$$mousemove = event => {
369
+ if (isDragging()) return;
370
+ event.stopPropagation();
371
+ const relativeX = horizontalViewPort().calculatePixelValue(horizontalViewPort().calculatePosition(event.clientX));
372
+ const noteStartX = horizontalViewPort().calculatePixelValue(note.ticks);
373
+ const noteEndX = horizontalViewPort().calculatePixelValue(note.ticks + note.durationTicks);
374
+ setNoteDragMode(relativeX - noteStartX < 3 ? "trimStart" : noteEndX - relativeX < 3 ? "trimEnd" : "move");
375
+ };
376
+ web.setAttribute(_el$2, "draggable", false);
377
+ web.effect(_p$ => {
378
+ const _v$ = getClasses(noteDragMode()).join(" "),
379
+ _v$2 = `rgba(255,0,0, ${(128 + note.velocity) / 256})`,
380
+ _v$3 = `${verticalVirtualDimensions().offset}px`,
381
+ _v$4 = `${verticalVirtualDimensions().size}px`,
382
+ _v$5 = `${horizontalDimensions().offset}px`,
383
+ _v$6 = `${horizontalDimensions().size}px`;
384
+ _v$ !== _p$._v$ && web.className(_el$2, _p$._v$ = _v$);
385
+ _v$2 !== _p$._v$2 && _el$2.style.setProperty("background-color", _p$._v$2 = _v$2);
386
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
387
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
388
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("left", _p$._v$5 = _v$5);
389
+ _v$6 !== _p$._v$6 && _el$2.style.setProperty("width", _p$._v$6 = _v$6);
390
+ return _p$;
391
+ }, {
392
+ _v$: undefined,
393
+ _v$2: undefined,
394
+ _v$3: undefined,
395
+ _v$4: undefined,
396
+ _v$5: undefined,
397
+ _v$6: undefined
398
+ });
399
+ return _el$2;
400
+ }
249
401
  });
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
402
+ }
291
403
  });
292
- return _el$2;
293
404
  }
294
405
  });
295
406
  }
@@ -403,74 +514,11 @@ const ScrollContainer = props => {
403
514
  })();
404
515
  };
405
516
 
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"};
517
+ 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";
518
+ var styles$1 = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Row":"PianoRollGrid-module_PianoRollGrid-Row__nRMCs","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
408
519
  styleInject(css_248z$1);
409
520
 
410
521
  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
522
  const PianoRollGrid = () => {
475
523
  const context = usePianoRollContext();
476
524
  const verticalViewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
@@ -500,7 +548,7 @@ const PianoRollGrid = () => {
500
548
  }));
501
549
  });
502
550
  return (() => {
503
- const _el$ = _tmpl$$4.cloneNode(true);
551
+ const _el$ = _tmpl$$5.cloneNode(true);
504
552
  web.insert(_el$, web.createComponent(solidJs.Index, {
505
553
  get each() {
506
554
  return gridArray();
@@ -512,9 +560,9 @@ const PianoRollGrid = () => {
512
560
  return virtualDimensions().size > 0;
513
561
  },
514
562
  get children() {
515
- const _el$2 = _tmpl$$4.cloneNode(true);
563
+ const _el$2 = _tmpl$$5.cloneNode(true);
516
564
  web.effect(_p$ => {
517
- const _v$ = styles["PianoRollGrid-Time"],
565
+ const _v$ = styles$1["PianoRollGrid-Time"],
518
566
  _v$2 = Math.ceil((entry().index + 1 * selectedGridDivisorTicks()) / measureTicks()) % 2 === 0 ? "#ddd" : "#ccc",
519
567
  _v$3 = `${virtualDimensions().offset}px`,
520
568
  _v$4 = `${virtualDimensions().size}px`,
@@ -539,7 +587,7 @@ const PianoRollGrid = () => {
539
587
  }), null);
540
588
  web.insert(_el$, web.createComponent(solidJs.Show, {
541
589
  get when() {
542
- return !context.condensed;
590
+ return context.mode === "keys";
543
591
  },
544
592
  get children() {
545
593
  return web.createComponent(solidJs.Index, {
@@ -551,10 +599,10 @@ const PianoRollGrid = () => {
551
599
  return virtualDimensions().size > 0;
552
600
  },
553
601
  get children() {
554
- const _el$3 = _tmpl$$4.cloneNode(true);
602
+ const _el$3 = _tmpl$$5.cloneNode(true);
555
603
  _el$3.style.setProperty("width", "100%");
556
604
  web.effect(_p$ => {
557
- const _v$6 = styles["PianoRollGrid-Key"],
605
+ const _v$6 = styles$1["PianoRollGrid-Row"],
558
606
  _v$7 = `${virtualDimensions().offset}px`,
559
607
  _v$8 = `${virtualDimensions().size}px`,
560
608
  _v$9 = key().isBlack ? "rgba(0,0,0,0.2)" : "none",
@@ -579,35 +627,53 @@ const PianoRollGrid = () => {
579
627
  });
580
628
  }
581
629
  }), null);
582
- web.effect(() => web.className(_el$, styles.PianoRollGrid));
630
+ web.insert(_el$, web.createComponent(solidJs.Show, {
631
+ get when() {
632
+ return context.mode === "tracks";
633
+ },
634
+ get children() {
635
+ return web.createComponent(solidJs.For, {
636
+ get each() {
637
+ return context.tracks;
638
+ },
639
+ children: (track, index) => {
640
+ const virtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(index(), 1));
641
+ return web.createComponent(solidJs.Show, {
642
+ get when() {
643
+ return virtualDimensions().size > 0;
644
+ },
645
+ get children() {
646
+ const _el$4 = _tmpl$$5.cloneNode(true);
647
+ _el$4.style.setProperty("width", "100%");
648
+ _el$4.style.setProperty("border-width", "0");
649
+ web.effect(_p$ => {
650
+ const _v$11 = styles$1["PianoRollGrid-Row"],
651
+ _v$12 = `${virtualDimensions().offset}px`,
652
+ _v$13 = `${virtualDimensions().size}px`,
653
+ _v$14 = index() % 2 === 0 ? "rgba(0,0,0,0.2)" : "none";
654
+ _v$11 !== _p$._v$11 && web.className(_el$4, _p$._v$11 = _v$11);
655
+ _v$12 !== _p$._v$12 && _el$4.style.setProperty("top", _p$._v$12 = _v$12);
656
+ _v$13 !== _p$._v$13 && _el$4.style.setProperty("height", _p$._v$13 = _v$13);
657
+ _v$14 !== _p$._v$14 && _el$4.style.setProperty("background-color", _p$._v$14 = _v$14);
658
+ return _p$;
659
+ }, {
660
+ _v$11: undefined,
661
+ _v$12: undefined,
662
+ _v$13: undefined,
663
+ _v$14: undefined
664
+ });
665
+ return _el$4;
666
+ }
667
+ });
668
+ }
669
+ });
670
+ }
671
+ }), null);
672
+ web.effect(() => web.className(_el$, styles$1.PianoRollGrid));
583
673
  return _el$;
584
674
  })();
585
675
  };
586
676
 
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
677
  const defaultRect = {
612
678
  left: 0,
613
679
  width: 0,
@@ -636,11 +702,11 @@ function useBoundingClientRect(containerRef) {
636
702
  return boundingClientRect;
637
703
  }
638
704
 
639
- const _tmpl$$3 = /*#__PURE__*/web.template(`<input min="1" max="11" step="0.01">`, 1);
705
+ const _tmpl$$4 = /*#__PURE__*/web.template(`<input min="1" max="11" step="0.01">`, 1);
640
706
  const VerticalZoomControl = props => {
641
707
  const context = usePianoRollContext();
642
708
  return (() => {
643
- const _el$ = _tmpl$$3.cloneNode(true);
709
+ const _el$ = _tmpl$$4.cloneNode(true);
644
710
  web.spread(_el$, web.mergeProps(props, {
645
711
  get value() {
646
712
  return context.verticalZoom;
@@ -664,224 +730,91 @@ const VerticalZoomControl = props => {
664
730
  })();
665
731
  };
666
732
 
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));
733
+ const _tmpl$$3 = /*#__PURE__*/web.template(`<input max="500" min="1" step="0.01">`, 1);
734
+ const HorizontalZoomControl = props => {
735
+ const context = usePianoRollContext();
690
736
  return (() => {
691
- const _el$ = _tmpl$4.cloneNode(true);
692
- web.spread(_el$, web.mergeProps(divProps, {
737
+ const _el$ = _tmpl$$3.cloneNode(true);
738
+ web.spread(_el$, web.mergeProps(props, {
739
+ get value() {
740
+ return context.zoom;
741
+ },
742
+ "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
743
+ "type": "range",
693
744
  get style() {
694
745
  return {
695
- display: "flex",
696
- flex: 1,
697
- height: "100%",
698
- "flex-direction": "row",
699
- overflow: "hidden",
700
- ...(typeof divProps.style === "object" && divProps.style)
746
+ "margin-left": "50px",
747
+ "margin-right": "16px",
748
+ ...(typeof props.style === "object" && props.style)
701
749
  };
702
750
  }
703
- }), false, true);
704
- web.insert(_el$, web.createComponent(PianoRollContextProvider, {
705
- get value() {
706
- return {
707
- ...contextProps
708
- };
751
+ }), false, false);
752
+ return _el$;
753
+ })();
754
+ };
755
+
756
+ 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";
757
+ var styles = {"PianoRollTrackList":"PianoRollTrackList-module_PianoRollTrackList__pyuxQ","Track":"PianoRollTrackList-module_Track__VZFIg"};
758
+ styleInject(css_248z);
759
+
760
+ const _tmpl$$2 = /*#__PURE__*/web.template(`<div></div>`, 2),
761
+ _tmpl$2$1 = /*#__PURE__*/web.template(`<div> </div>`, 2);
762
+ const PianoRollTrackList = () => {
763
+ const viewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
764
+ const context = usePianoRollContext();
765
+ return (() => {
766
+ const _el$ = _tmpl$$2.cloneNode(true);
767
+ web.insert(_el$, web.createComponent(solidJs.Index, {
768
+ get each() {
769
+ return context.tracks;
709
770
  },
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
- })
771
+ children: (track, index) => {
772
+ const virtualDimensions = solidJs.createMemo(() => viewPort().calculatePixelDimensions(context.mode === "tracks" ? index : index * 8, context.mode === "tracks" ? 1 : 8));
773
+ return web.createComponent(solidJs.Show, {
774
+ get when() {
775
+ return virtualDimensions().size > 0;
731
776
  },
732
777
  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;
778
+ const _el$2 = _tmpl$2$1.cloneNode(true),
779
+ _el$3 = _el$2.firstChild;
780
+ _el$2.$$click = () => context.onSelectedTrackIndexChange?.(index);
781
+ _el$2.style.setProperty("cursor", "pointer");
782
+ web.insert(_el$2, index, _el$3);
783
+ web.insert(_el$2, () => track().name || "[unnamed track]", null);
784
+ web.effect(_p$ => {
785
+ const _v$ = {
786
+ [styles["Track"]]: true
860
787
  },
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
- })()];
788
+ _v$2 = track().name,
789
+ _v$3 = `${virtualDimensions().offset}px`,
790
+ _v$4 = `${virtualDimensions().size}px`,
791
+ _v$5 = index === context.selectedTrackIndex ? "gray" : "lightgrey";
792
+ _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
793
+ _v$2 !== _p$._v$2 && web.setAttribute(_el$2, "title", _p$._v$2 = _v$2);
794
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
795
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
796
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("background", _p$._v$5 = _v$5);
797
+ return _p$;
798
+ }, {
799
+ _v$: undefined,
800
+ _v$2: undefined,
801
+ _v$3: undefined,
802
+ _v$4: undefined,
803
+ _v$5: undefined
804
+ });
805
+ return _el$2;
875
806
  }
876
807
  });
877
808
  }
878
809
  }));
810
+ web.effect(() => web.className(_el$, styles.PianoRollTrackList));
879
811
  return _el$;
880
812
  })();
881
813
  };
882
814
  web.delegateEvents(["click"]);
883
815
 
884
- const _tmpl$$1 = /*#__PURE__*/web.template(`<div><div></div></div>`, 4);
816
+ const _tmpl$$1 = /*#__PURE__*/web.template(`<div></div>`, 2),
817
+ _tmpl$2 = /*#__PURE__*/web.template(`<div><div></div></div>`, 4);
885
818
  const PianoRoll = allProps => {
886
819
  const [contextProps, divProps] = splitContextProps(allProps);
887
820
  const [scrollerRef, setScrollerRef] = solidJs.createSignal();
@@ -891,14 +824,20 @@ const PianoRoll = allProps => {
891
824
  const maxZoom = solidJs.createMemo(() => 500 * (zoomFactor / clientRect().width));
892
825
  const minVerticalZoom = solidJs.createMemo(() => 1 / (zoomFactor / clientRect().height));
893
826
  const maxVerticalZoom = solidJs.createMemo(() => 10 * (zoomFactor / clientRect().height));
827
+ solidJs.createEffect(isInitial => {
828
+ if (isInitial) return false;
829
+ if (contextProps.mode === "tracks") {
830
+ contextProps.onVerticalPositionChange?.(0);
831
+ }
832
+ }, true);
894
833
  return web.createComponent(PianoRollContextProvider, {
895
834
  value: contextProps,
896
835
  get children() {
897
- const _el$ = _tmpl$$1.cloneNode(true),
836
+ const _el$ = _tmpl$2.cloneNode(true),
898
837
  _el$2 = _el$.firstChild;
899
838
  web.spread(_el$, web.mergeProps(divProps, {
900
839
  get ["class"]() {
901
- return styles$3.PianoRoll;
840
+ return styles$4.PianoRoll;
902
841
  }
903
842
  }), false, true);
904
843
  web.insert(_el$2, web.createComponent(ScrollZoomViewPort, {
@@ -916,14 +855,35 @@ const PianoRoll = allProps => {
916
855
  pixelOffset: clientRect().top,
917
856
  pixelSize: clientRect().height,
918
857
  position: contextProps.verticalPosition,
919
- range: 128,
858
+ range: contextProps.mode === "keys" ? 128 : Math.max(contextProps.tracks.length, 16),
920
859
  zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
921
860
  onPositionChange: contextProps.onVerticalPositionChange,
922
861
  onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
923
862
  })
924
863
  },
925
864
  get children() {
926
- return [web.createComponent(PianoRollKeys, {}), web.createComponent(ScrollContainer, {
865
+ return [(() => {
866
+ const _el$3 = _tmpl$$1.cloneNode(true);
867
+ _el$3.style.setProperty("display", "flex");
868
+ _el$3.style.setProperty("width", "20%");
869
+ web.insert(_el$3, web.createComponent(solidJs.Show, {
870
+ get when() {
871
+ return allProps.showTrackList;
872
+ },
873
+ get children() {
874
+ return web.createComponent(PianoRollTrackList, {});
875
+ }
876
+ }), null);
877
+ web.insert(_el$3, web.createComponent(solidJs.Show, {
878
+ get when() {
879
+ return contextProps.mode === "keys";
880
+ },
881
+ get children() {
882
+ return web.createComponent(PianoRollKeys, {});
883
+ }
884
+ }), null);
885
+ return _el$3;
886
+ })(), web.createComponent(ScrollContainer, {
927
887
  ref: setScrollerRef,
928
888
  get children() {
929
889
  return [web.memo(() => allProps.children), web.createComponent(PianoRollGrid, {}), web.createComponent(PianoRollNotes, {})];
@@ -946,7 +906,7 @@ const PianoRoll = allProps => {
946
906
  return maxZoom();
947
907
  }
948
908
  }), null);
949
- web.effect(() => web.className(_el$2, styles$3.PianoRollContainer));
909
+ web.effect(() => web.className(_el$2, styles$4.PianoRollContainer));
950
910
  return _el$;
951
911
  }
952
912
  });
@@ -1006,13 +966,37 @@ const PlayHead = allProps => {
1006
966
  })();
1007
967
  };
1008
968
 
969
+ const useNotes = () => {
970
+ const [notes, onNotesChange] = solidJs.createSignal([]);
971
+ const onNoteChange = (index, note) => {
972
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
973
+ };
974
+ const onInsertNote = note => {
975
+ const index = Math.max(notes().findIndex(({
976
+ ticks
977
+ }) => ticks > note.ticks), 0);
978
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
979
+ return index;
980
+ };
981
+ const onRemoveNote = index => {
982
+ onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
983
+ };
984
+ return {
985
+ notes,
986
+ onNotesChange,
987
+ onNoteChange,
988
+ onInsertNote,
989
+ onRemoveNote
990
+ };
991
+ };
992
+
1009
993
  const usePianoRoll = () => {
1010
994
  const [ppq, onPpqChange] = solidJs.createSignal(120);
1011
- const [condensed, onCondensedChange] = solidJs.createSignal(false);
995
+ const [mode, onModeChange] = solidJs.createSignal("tracks");
1012
996
  const [position, onPositionChange] = solidJs.createSignal(0);
1013
997
  const [zoom, onZoomChange] = solidJs.createSignal(10);
1014
998
  const [verticalZoom, onVerticalZoomChange] = solidJs.createSignal(5);
1015
- const [verticalPosition, onVerticalPositionChange] = solidJs.createSignal(64);
999
+ const [verticalPosition, onVerticalPositionChange] = solidJs.createSignal(44);
1016
1000
  const [gridDivision, onGridDivisionChange] = solidJs.createSignal(4);
1017
1001
  const [snapToGrid, onSnapToGridChange] = solidJs.createSignal(true);
1018
1002
  const [duration, onDurationChange] = solidJs.createSignal(0);
@@ -1031,14 +1015,13 @@ const usePianoRoll = () => {
1031
1015
  onGridDivisionChange,
1032
1016
  snapToGrid,
1033
1017
  onSnapToGridChange,
1034
- condensed,
1035
- onCondensedChange,
1018
+ mode,
1019
+ onModeChange,
1036
1020
  duration,
1037
1021
  onDurationChange
1038
1022
  };
1039
1023
  };
1040
1024
 
1041
- exports.MultiTrackPianoRoll = MultiTrackPianoRoll;
1042
1025
  exports.PianoRoll = PianoRoll;
1043
1026
  exports.PlayHead = PlayHead;
1044
1027
  exports.useNotes = useNotes;