solid-pianoroll 0.0.21 → 0.0.23

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$5 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n height: 100%;\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$5 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
34
- styleInject(css_248z$5);
32
+ var css_248z$6 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n height: 100%;\n user-select: none;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n\n.PianoRoll-module_PianoRollLeftColumn__S6SZQ {\n display: flex;\n overflow: hidden;\n flex-direction: column;\n max-width: 250px;\n margin-top: 30px;\n}\n.PianoRoll-module_PianoRollLeftColumn__S6SZQ.PianoRoll-module_showTrackList__mqsrT {\n width: 30%;\n margin-top: 0;\n}\n\n.PianoRoll-module_PianoRollRightColumn__V98HV {\n display: flex;\n position: relative;\n flex-direction: column;\n flex: 1;\n height: 100%;\n}\n";
33
+ var styles$6 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7","PianoRollLeftColumn":"PianoRoll-module_PianoRollLeftColumn__S6SZQ","showTrackList":"PianoRoll-module_showTrackList__mqsrT","PianoRollRightColumn":"PianoRoll-module_PianoRollRightColumn__V98HV"};
34
+ styleInject(css_248z$6);
35
35
 
36
36
  const defaultState = {
37
37
  ppq: 0,
@@ -47,10 +47,22 @@ const defaultState = {
47
47
  duration: 0,
48
48
  tracks: [],
49
49
  selectedTrackIndex: 0,
50
- pressedKeys: []
50
+ pressedKeys: {},
51
+ notesScrollerClientRect: {
52
+ left: 0,
53
+ width: 0,
54
+ top: 0,
55
+ height: 0
56
+ },
57
+ tracksScrollerClientRect: {
58
+ left: 0,
59
+ width: 0,
60
+ top: 0,
61
+ height: 0
62
+ }
51
63
  };
52
64
  const propNameToHandlerName = name => `on${name[0]?.toUpperCase()}${name.slice(1)}Change`;
53
- const pianoRollStatePropNames = [...Object.keys(defaultState), ...Object.keys(defaultState).map(propNameToHandlerName), "onNoteChange", "onInsertNote", "onRemoveNote", "onNoteDown", "onNoteUp"];
65
+ const pianoRollStatePropNames = [...Object.keys(defaultState), ...Object.keys(defaultState).map(propNameToHandlerName), "onNoteChange", "onInsertNote", "onRemoveNote", "onNoteDown", "onNoteUp", "isKeyDown"];
54
66
  const createPianoRollstate = initialState => {
55
67
  const [state, setState] = store.createStore({
56
68
  ...defaultState,
@@ -84,19 +96,30 @@ const createPianoRollstate = initialState => {
84
96
  const onRemoveNote = (trackIndex, noteIndex) => {
85
97
  updateNotes(trackIndex, notes => [...notes.slice(0, noteIndex), ...notes.slice(noteIndex + 1)]);
86
98
  };
87
- const onNoteDown = keyNumber => {
88
- handlers.onPressedKeysChange?.([...state.pressedKeys, keyNumber]);
99
+ const updateKeyPressedState = (trackIndex, keyNumber, value) => {
100
+ handlers.onPressedKeysChange?.({
101
+ ...state.pressedKeys,
102
+ [trackIndex]: {
103
+ ...state.pressedKeys[trackIndex],
104
+ [keyNumber]: value
105
+ }
106
+ });
107
+ };
108
+ const onNoteDown = (trackIndex, keyNumber) => {
109
+ updateKeyPressedState(trackIndex, keyNumber, true);
89
110
  };
90
- const onNoteUp = keyNumber => {
91
- handlers.onPressedKeysChange?.([...state.pressedKeys].filter(number => number !== keyNumber));
111
+ const onNoteUp = (trackIndex, keyNumber) => {
112
+ updateKeyPressedState(trackIndex, keyNumber, false);
92
113
  };
114
+ const isKeyDown = (trackIndex, keyNumber) => !!state.pressedKeys[trackIndex]?.[keyNumber];
93
115
  return solidJs.mergeProps(state, {
94
116
  ...handlers,
95
117
  onNoteChange,
96
118
  onInsertNote,
97
119
  onRemoveNote,
98
120
  onNoteDown,
99
- onNoteUp
121
+ onNoteUp,
122
+ isKeyDown
100
123
  });
101
124
  };
102
125
 
@@ -109,9 +132,9 @@ const usePianoRollContext = () => {
109
132
  };
110
133
  const splitContextProps = allProps => solidJs.splitProps(allProps, [...pianoRollStatePropNames, "showAllTracks", "showTrackList"]);
111
134
 
112
- var css_248z$4 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\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}\n\n.PianoRollKeys-module_Key__jybNC {\n transition-property: background-color, box-shadow;\n transition-duration: 200ms;\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";
113
- var styles$4 = {"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"};
114
- styleInject(css_248z$4);
135
+ var css_248z$5 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\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}\n\n.PianoRollKeys-module_Key__jybNC {\n transition-property: background-color, box-shadow;\n transition-duration: 200ms;\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 transform: rotateX(0deg);\n perspective: 100px;\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 border: 1px black outset;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n border-top-width: 0.5px;\n border-bottom-width: 0.5px;\n border-top-right-radius: 4%;\n border-bottom-right-radius: 4%;\n}\n\n.PianoRollKeys-module_down__GcNeZ {\n transition: none;\n background: red;\n transform: rotateX(0deg) rotateY(20deg);\n}\n";
136
+ var styles$5 = {"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"};
137
+ styleInject(css_248z$5);
115
138
 
116
139
  function createViewPortDimension(getState) {
117
140
  const getStateWithFunctions = () => {
@@ -201,11 +224,11 @@ const useViewPortDimension = name => {
201
224
  return viewPort;
202
225
  };
203
226
 
204
- var css_248z$3 = ".ScrollZoomContainer-module_ScrollZoomContainer__o2bRt {\n height: 100%;\n width: 100%;\n z-index: 4;\n}\n";
205
- var styles$3 = {"ScrollZoomContainer":"ScrollZoomContainer-module_ScrollZoomContainer__o2bRt"};
206
- styleInject(css_248z$3);
227
+ var css_248z$4 = ".ScrollZoomContainer-module_ScrollZoomContainer__o2bRt {\n height: 100%;\n width: 100%;\n z-index: 4;\n}\n";
228
+ var styles$4 = {"ScrollZoomContainer":"ScrollZoomContainer-module_ScrollZoomContainer__o2bRt"};
229
+ styleInject(css_248z$4);
207
230
 
208
- const _tmpl$$7 = /*#__PURE__*/web.template(`<div><div><div><div></div></div></div></div>`, 8);
231
+ const _tmpl$$8 = /*#__PURE__*/web.template(`<div><div><div><div></div></div></div></div>`, 8);
209
232
  const ScrollZoomContainer = props => {
210
233
  let scrollContentRef;
211
234
  const [ownProps, divProps] = solidJs.splitProps(props, ["ref", "verticalDimensionName", "horizontalDimensionName", "showScrollbar"]);
@@ -241,11 +264,11 @@ const ScrollZoomContainer = props => {
241
264
  if (event.altKey) {
242
265
  event.preventDefault();
243
266
  if (Math.abs(event.deltaX) > Math.abs(event.deltaY)) {
244
- horizontalViewPort()?.onZoomChange?.(horizontalViewPort().zoom * (1 + event.deltaX / horizontalViewPort().pixelSize));
267
+ horizontalViewPort()?.onZoomChange?.(horizontalViewPort().zoom / (1 + event.deltaX / horizontalViewPort().pixelSize));
245
268
  const maxPosition = horizontalViewPort().calculateMaxPosition();
246
269
  horizontalViewPort()?.onPositionChange?.(Math.min(maxPosition, horizontalViewPort()?.position));
247
270
  } else {
248
- verticalViewPort()?.onZoomChange?.(verticalViewPort().zoom * (1 + event.deltaY / verticalViewPort().pixelSize));
271
+ verticalViewPort()?.onZoomChange?.(verticalViewPort().zoom / (1 + event.deltaY / verticalViewPort().pixelSize));
249
272
  const maxVerticalPosition = verticalViewPort().calculateMaxPosition();
250
273
  verticalViewPort()?.onPositionChange?.(Math.min(maxVerticalPosition, verticalViewPort()?.position));
251
274
  }
@@ -277,7 +300,7 @@ const ScrollZoomContainer = props => {
277
300
  });
278
301
  });
279
302
  return (() => {
280
- const _el$ = _tmpl$$7.cloneNode(true),
303
+ const _el$ = _tmpl$$8.cloneNode(true),
281
304
  _el$2 = _el$.firstChild,
282
305
  _el$3 = _el$2.firstChild,
283
306
  _el$4 = _el$3.firstChild;
@@ -294,7 +317,7 @@ const ScrollZoomContainer = props => {
294
317
  },
295
318
  get classList() {
296
319
  return {
297
- [styles$3.ScrollZoomContainer]: true,
320
+ [styles$4.ScrollZoomContainer]: true,
298
321
  ...divProps.classList
299
322
  };
300
323
  }
@@ -327,7 +350,7 @@ const ScrollZoomContainer = props => {
327
350
  })();
328
351
  };
329
352
 
330
- const _tmpl$$6 = /*#__PURE__*/web.template(`<div></div>`, 2);
353
+ const _tmpl$$7 = /*#__PURE__*/web.template(`<div></div>`, 2);
331
354
  const PianoRollKeys = () => {
332
355
  const verticalViewPort = solidJs.createMemo(() => useViewPortDimension("vertical"));
333
356
  const horizontalViewPort = solidJs.createMemo(() => useViewPortDimension("horizontalKeys"));
@@ -344,7 +367,7 @@ const PianoRollKeys = () => {
344
367
  }
345
368
  });
346
369
  return (() => {
347
- const _el$ = _tmpl$$6.cloneNode(true);
370
+ const _el$ = _tmpl$$7.cloneNode(true);
348
371
  web.insert(_el$, web.createComponent(ScrollZoomContainer, {
349
372
  horizontalDimensionName: "horizontalKeys",
350
373
  showScrollbar: false,
@@ -352,81 +375,59 @@ const PianoRollKeys = () => {
352
375
  return web.createComponent(solidJs.Index, {
353
376
  each: keys,
354
377
  children: key => {
355
- const isDown = solidJs.createMemo(() => context.pressedKeys.includes(key().number));
378
+ const isDown = solidJs.createMemo(() => context.isKeyDown(context.selectedTrackIndex, key().number));
356
379
  const virtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(127 - key().number, 1));
357
380
  const previousIsBlack = blackKeys.includes((key().number - 1) % 12);
358
381
  const nextIsBlack = blackKeys.includes((key().number + 1) % 12);
359
382
  return web.createComponent(solidJs.Show, {
360
383
  get when() {
361
- return virtualDimensions().size > 0;
384
+ return verticalViewPort().isVisible(virtualDimensions());
362
385
  },
363
386
  get children() {
364
- const _el$2 = _tmpl$$6.cloneNode(true);
387
+ const _el$2 = _tmpl$$7.cloneNode(true);
365
388
  _el$2.addEventListener("mouseleave", () => {
366
389
  if (isMouseDown()) {
367
- context.onNoteUp(key().number);
390
+ context.onNoteUp(context.selectedTrackIndex, key().number);
368
391
  }
369
392
  });
370
393
  _el$2.addEventListener("mouseenter", () => {
371
394
  if (isMouseDown()) {
372
- context.onNoteDown(key().number);
395
+ context.onNoteDown(context.selectedTrackIndex, key().number);
373
396
  }
374
397
  });
375
398
  _el$2.$$mouseup = () => {
376
- context.onNoteUp(key().number);
399
+ context.onNoteUp(context.selectedTrackIndex, key().number);
377
400
  };
378
401
  _el$2.$$mousedown = () => {
379
402
  setIsMouseDown(true);
380
- context.onNoteDown(key().number);
403
+ context.onNoteDown(context.selectedTrackIndex, key().number);
381
404
  };
382
- web.insert(_el$2, web.createComponent(solidJs.Show, {
383
- get when() {
384
- return key().isBlack && false;
385
- },
386
- get children() {
387
- const _el$3 = _tmpl$$6.cloneNode(true);
388
- web.effect(_p$ => {
389
- const _v$3 = styles$4["black-separator"],
390
- _v$4 = `${virtualDimensions().offset}px`,
391
- _v$5 = `${virtualDimensions().size / 2 - 0.25}px`;
392
- _v$3 !== _p$._v$3 && web.className(_el$3, _p$._v$3 = _v$3);
393
- _v$4 !== _p$._v$4 && _el$3.style.setProperty("top", _p$._v$4 = _v$4);
394
- _v$5 !== _p$._v$5 && _el$3.style.setProperty("height", _p$._v$5 = _v$5);
395
- return _p$;
396
- }, {
397
- _v$3: undefined,
398
- _v$4: undefined,
399
- _v$5: undefined
400
- });
401
- return _el$3;
402
- }
403
- }));
404
405
  web.effect(_p$ => {
405
- const _v$6 = {
406
- [styles$4["Key"]]: true,
407
- [styles$4["black"]]: key().isBlack,
408
- [styles$4["white"]]: !key().isBlack,
409
- [styles$4["down"]]: isDown()
406
+ const _v$3 = {
407
+ [styles$5["Key"]]: true,
408
+ [styles$5["black"]]: key().isBlack,
409
+ [styles$5["white"]]: !key().isBlack,
410
+ [styles$5["down"]]: isDown()
410
411
  },
411
- _v$7 = key().name,
412
- _v$8 = key().number % 12,
413
- _v$9 = `${virtualDimensions().offset - (!key().isBlack && nextIsBlack ? virtualDimensions().size / 2 : 0)}px`,
414
- _v$10 = `${virtualDimensions().size + (!key().isBlack && nextIsBlack ? virtualDimensions().size / 2 : 0) + (!key().isBlack && previousIsBlack ? virtualDimensions().size / 2 : 0)}px`,
415
- _v$11 = [`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(", ");
416
- _p$._v$6 = web.classList(_el$2, _v$6, _p$._v$6);
417
- _v$7 !== _p$._v$7 && web.setAttribute(_el$2, "title", _p$._v$7 = _v$7);
418
- _v$8 !== _p$._v$8 && web.setAttribute(_el$2, "data-index", _p$._v$8 = _v$8);
419
- _v$9 !== _p$._v$9 && _el$2.style.setProperty("top", _p$._v$9 = _v$9);
420
- _v$10 !== _p$._v$10 && _el$2.style.setProperty("height", _p$._v$10 = _v$10);
421
- _v$11 !== _p$._v$11 && _el$2.style.setProperty("box-shadow", _p$._v$11 = _v$11);
412
+ _v$4 = key().name,
413
+ _v$5 = key().number % 12,
414
+ _v$6 = `${virtualDimensions().offset - virtualDimensions().size * (!key().isBlack ? nextIsBlack ? 1 / 2 : 0 : 0)}px`,
415
+ _v$7 = `${virtualDimensions().size + (!key().isBlack && nextIsBlack ? virtualDimensions().size / 2 : 0) + (!key().isBlack && previousIsBlack ? virtualDimensions().size / 2 : 0)}px`,
416
+ _v$8 = `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` : "";
417
+ _p$._v$3 = web.classList(_el$2, _v$3, _p$._v$3);
418
+ _v$4 !== _p$._v$4 && web.setAttribute(_el$2, "title", _p$._v$4 = _v$4);
419
+ _v$5 !== _p$._v$5 && web.setAttribute(_el$2, "data-index", _p$._v$5 = _v$5);
420
+ _v$6 !== _p$._v$6 && _el$2.style.setProperty("top", _p$._v$6 = _v$6);
421
+ _v$7 !== _p$._v$7 && _el$2.style.setProperty("height", _p$._v$7 = _v$7);
422
+ _v$8 !== _p$._v$8 && _el$2.style.setProperty("box-shadow", _p$._v$8 = _v$8);
422
423
  return _p$;
423
424
  }, {
425
+ _v$3: undefined,
426
+ _v$4: undefined,
427
+ _v$5: undefined,
424
428
  _v$6: undefined,
425
429
  _v$7: undefined,
426
- _v$8: undefined,
427
- _v$9: undefined,
428
- _v$10: undefined,
429
- _v$11: undefined
430
+ _v$8: undefined
430
431
  });
431
432
  return _el$2;
432
433
  }
@@ -436,7 +437,7 @@ const PianoRollKeys = () => {
436
437
  }
437
438
  }));
438
439
  web.effect(_p$ => {
439
- const _v$ = styles$4.PianoRollKeys,
440
+ const _v$ = styles$5.PianoRollKeys,
440
441
  _v$2 = `${horizontalViewPort().pixelSize}px`;
441
442
  _v$ !== _p$._v$ && web.className(_el$, _p$._v$ = _v$);
442
443
  _v$2 !== _p$._v$2 && _el$.style.setProperty("width", _p$._v$2 = _v$2);
@@ -459,82 +460,112 @@ const keys = Array.from({
459
460
  }));
460
461
  web.delegateEvents(["mousedown", "mouseup"]);
461
462
 
462
- 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}";
463
- var styles$2 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
464
- styleInject(css_248z$2);
463
+ var css_248z$3 = ".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}";
464
+ var styles$3 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
465
+ styleInject(css_248z$3);
465
466
 
466
- const _tmpl$$5 = /*#__PURE__*/web.template(`<div></div>`, 2);
467
+ const _tmpl$$6 = /*#__PURE__*/web.template(`<div></div>`, 2);
467
468
  const PianoRollNotes = props => {
468
469
  const context = usePianoRollContext();
469
470
  const verticalViewPort = solidJs.createMemo(() => useViewPortDimension(context.mode === "keys" ? "vertical" : "verticalTracks"));
470
471
  const horizontalViewPort = solidJs.createMemo(() => useViewPortDimension("horizontal"));
471
472
  const gridDivisionTicks = solidJs.createMemo(() => context.ppq * 4 / context.gridDivision);
473
+ const [isDragging, setIsDragging] = solidJs.createSignal(false);
474
+ const [noteDragMode, setNoteDragMode] = solidJs.createSignal();
475
+ const [currentNoteIndex, setCurrentNoteIndex] = solidJs.createSignal(-1);
476
+ const [currentNoteTrackIndex, setCurrentNoteTrackIndex] = solidJs.createSignal(-1);
477
+ const [diffPosition, setDiffPosition] = solidJs.createSignal(0);
478
+ const [getInitialNote, setInitialNote] = solidJs.createSignal();
472
479
  const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
473
- const insertOrUpdateNote = event => {
474
- const position = horizontalViewPort().calculatePosition(event.clientX);
475
- const existingNote = currentNote();
476
- const midi = context.mode === "keys" ? 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY)) : existingNote?.midi ?? 60;
477
- const targetTrackIndex = context.mode === "tracks" ? clamp(Math.floor(verticalViewPort().calculatePosition(event.clientY)), 0, context.tracks.length - 1) : context.selectedTrackIndex ?? 0;
478
- const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
479
- const velocity = 127;
480
- const ticks = existingNote?.ticks ?? eventPositionTicks;
481
- const durationTicks = existingNote?.ticks ? eventPositionTicks - existingNote?.ticks : gridDivisionTicks();
482
- const note = {
480
+ const calculateNoteDragValues = event => {
481
+ const targetTrackIndex = context.mode === "tracks" ? clamp(Math.floor(verticalViewPort().calculatePosition(event.clientY)), 0, context.tracks.length - 1) : currentNoteTrackIndex() > -1 ? currentNoteTrackIndex() : context.selectedTrackIndex;
482
+ const midi = context.mode === "keys" ? Math.floor(128 - verticalViewPort().calculatePosition(event.clientY)) : getInitialNote()?.midi ?? 60;
483
+ const horiontalPosition = horizontalViewPort().calculatePosition(event.clientX);
484
+ return {
485
+ targetTrackIndex,
486
+ midi,
487
+ horiontalPosition
488
+ };
489
+ };
490
+ const handleMouseMove = mouseMoveEvent => {
491
+ mouseMoveEvent.preventDefault();
492
+ mouseMoveEvent.stopPropagation();
493
+ const note = getInitialNote();
494
+ if (!note) return;
495
+ const {
496
+ targetTrackIndex,
483
497
  midi,
484
- ticks,
485
- durationTicks,
486
- velocity
498
+ horiontalPosition
499
+ } = calculateNoteDragValues(mouseMoveEvent);
500
+ const ticks = snapValueToGridIfEnabled(horiontalPosition - diffPosition(), mouseMoveEvent.altKey);
501
+ const updatedNote = {
502
+ ...note,
503
+ midi,
504
+ ...(noteDragMode() === "move" && {
505
+ ticks
506
+ }),
507
+ ...(noteDragMode() === "trimStart" && {
508
+ ticks: ticks < note.ticks + note.durationTicks ? ticks : note.ticks + note.durationTicks,
509
+ durationTicks: ticks < note.ticks + note.durationTicks ? note.ticks + note.durationTicks - ticks : snapValueToGridIfEnabled(horiontalPosition - note.ticks, mouseMoveEvent.altKey)
510
+ }),
511
+ ...(noteDragMode() === "trimEnd" && {
512
+ ticks: ticks < note.ticks ? ticks : note.ticks,
513
+ durationTicks: ticks < note.ticks ? note.ticks - ticks : snapValueToGridIfEnabled(horiontalPosition - note.ticks, mouseMoveEvent.altKey)
514
+ })
487
515
  };
488
- if (existingNote) {
489
- context.onNoteChange?.(currentNoteTrackIndex(), currentNoteIndex(), note);
490
- return currentNoteIndex();
516
+ const previousTrackIndex = currentNoteTrackIndex();
517
+ const previousNoteIndex = currentNoteIndex();
518
+ if (targetTrackIndex === previousTrackIndex) {
519
+ context.onNoteChange?.(previousTrackIndex, previousNoteIndex, updatedNote);
491
520
  } else {
492
- return context.onInsertNote?.(targetTrackIndex, note) ?? -1;
521
+ if (context.onInsertNote) {
522
+ context.onRemoveNote?.(previousTrackIndex, previousNoteIndex);
523
+ const newNoteIndex = context.onInsertNote(targetTrackIndex, updatedNote);
524
+ setCurrentNoteTrackIndex(targetTrackIndex);
525
+ setCurrentNoteIndex(newNoteIndex);
526
+ }
493
527
  }
494
528
  };
495
- const [isDragging, setIsDragging] = solidJs.createSignal(false);
496
- const [noteDragMode, setNoteDragMode] = solidJs.createSignal();
497
- const [currentNoteIndex, setCurrentNoteIndex] = solidJs.createSignal(-1);
498
- const [currentNoteTrackIndex, setCurrentNoteTrackIndex] = solidJs.createSignal(-1);
499
- const [isMouseDown, setIsMouseDown] = solidJs.createSignal(false);
500
- const currentNote = solidJs.createMemo(() => context.tracks[currentNoteTrackIndex()]?.notes[currentNoteIndex()]);
529
+ const stopDragging = () => {
530
+ window.removeEventListener("mousemove", handleMouseMove);
531
+ window.removeEventListener("mouseup", stopDragging);
532
+ setIsDragging(false);
533
+ setCurrentNoteIndex(-1);
534
+ setCurrentNoteTrackIndex(-1);
535
+ };
536
+ const startDragging = () => {
537
+ window.addEventListener("mousemove", handleMouseMove);
538
+ window.addEventListener("mouseup", stopDragging);
539
+ };
501
540
  const getClasses = noteDragMode => {
502
- return noteDragMode ? [styles$2.Note, styles$2[noteDragMode]] : [styles$2.Note];
541
+ return noteDragMode ? [styles$3.Note, styles$3[noteDragMode]] : [styles$3.Note];
503
542
  };
504
543
  return (() => {
505
- const _el$ = _tmpl$$5.cloneNode(true);
506
- _el$.$$click = event => {
507
- if (currentNote()) {
508
- setCurrentNoteIndex(-1);
509
- return;
510
- }
511
- if (!event.altKey) return;
512
- insertOrUpdateNote(event);
513
- };
514
- _el$.$$dblclick = event => {
515
- insertOrUpdateNote(event);
516
- };
517
- _el$.$$mouseup = event => {
518
- setIsMouseDown(false);
519
- if (!event.altKey) return;
520
- insertOrUpdateNote(event);
521
- };
522
- _el$.$$mousemove = event => {
523
- if (isDragging()) return;
524
- if (!isMouseDown()) {
525
- setNoteDragMode(undefined);
526
- return;
527
- }
528
- const index = insertOrUpdateNote(event);
529
- setCurrentNoteIndex(index);
530
- };
531
- _el$.$$mousedown = event => {
532
- solidJs.batch(() => {
533
- setIsMouseDown(true);
534
- const index = insertOrUpdateNote(event);
535
- setCurrentNoteTrackIndex(context.selectedTrackIndex ?? 0);
536
- setCurrentNoteIndex(index);
537
- });
544
+ const _el$ = _tmpl$$6.cloneNode(true);
545
+ _el$.$$mousedown = mouseDownEvent => {
546
+ mouseDownEvent.preventDefault();
547
+ mouseDownEvent.stopPropagation();
548
+ const {
549
+ targetTrackIndex,
550
+ midi,
551
+ horiontalPosition
552
+ } = calculateNoteDragValues(mouseDownEvent);
553
+ const ticks = snapValueToGridIfEnabled(horiontalPosition, mouseDownEvent.altKey);
554
+ const durationTicks = gridDivisionTicks();
555
+ const newNote = {
556
+ midi,
557
+ ticks,
558
+ durationTicks,
559
+ velocity: 100
560
+ };
561
+ const newNoteIndex = context.onInsertNote(targetTrackIndex, newNote);
562
+ setIsDragging(true);
563
+ setCurrentNoteTrackIndex(targetTrackIndex);
564
+ setCurrentNoteIndex(newNoteIndex);
565
+ setInitialNote(newNote);
566
+ setDiffPosition(0);
567
+ setNoteDragMode("trimEnd");
568
+ startDragging();
538
569
  };
539
570
  const _ref$ = props.ref;
540
571
  typeof _ref$ === "function" ? web.use(_ref$, _el$) : props.ref = _el$;
@@ -560,58 +591,16 @@ const PianoRollNotes = props => {
560
591
  return web.memo(() => !!verticalViewPort().isVisible(verticalVirtualDimensions()))() && horizontalViewPort().isVisible(horizontalDimensions());
561
592
  },
562
593
  get children() {
563
- const _el$2 = _tmpl$$5.cloneNode(true);
594
+ const _el$2 = _tmpl$$6.cloneNode(true);
564
595
  _el$2.$$mousedown = event => {
565
596
  event.stopPropagation();
597
+ const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
598
+ setDiffPosition(noteDragMode() === "trimEnd" ? -(note.ticks + note.durationTicks - initialPosition) : initialPosition - note.ticks);
566
599
  setIsDragging(true);
567
600
  setCurrentNoteIndex(noteIndex());
568
601
  setCurrentNoteTrackIndex(trackIndex());
569
- const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
570
- const diffPosition = initialPosition - note.ticks;
571
- const handleMouseMove = mouseMoveEvent => {
572
- const note = currentNote();
573
- if (!note) return;
574
- const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
575
- const updatedNote = {
576
- ...note,
577
- ...(noteDragMode() === "move" && context.mode === "keys" && {
578
- midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
579
- }),
580
- ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
581
- ticks
582
- }),
583
- ...(noteDragMode() === "trimStart" && {
584
- durationTicks: note.durationTicks + note.ticks - ticks
585
- }),
586
- ...(noteDragMode() === "trimEnd" && {
587
- durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note.ticks, mouseMoveEvent.altKey)
588
- })
589
- };
590
- const previousTrackIndex = currentNoteTrackIndex();
591
- const previousNoteIndex = currentNoteIndex();
592
- const targetTrackIndex = context.mode === "tracks" ? clamp(Math.floor(verticalViewPort().calculatePosition(mouseMoveEvent.clientY)), 0, context.tracks.length - 1) : previousTrackIndex;
593
- if (targetTrackIndex === previousTrackIndex) {
594
- context.onNoteChange?.(previousTrackIndex, previousNoteIndex, updatedNote);
595
- } else {
596
- solidJs.batch(() => {
597
- if (context.onInsertNote) {
598
- context.onRemoveNote?.(previousTrackIndex, previousNoteIndex);
599
- const newNoteIndex = context.onInsertNote(targetTrackIndex, updatedNote);
600
- setCurrentNoteTrackIndex(targetTrackIndex);
601
- setCurrentNoteIndex(newNoteIndex);
602
- }
603
- });
604
- }
605
- };
606
- const handleMouseUp = () => {
607
- setIsDragging(false);
608
- setCurrentNoteIndex(-1);
609
- setCurrentNoteTrackIndex(-1);
610
- window.removeEventListener("mousemove", handleMouseMove);
611
- window.removeEventListener("mouseup", handleMouseUp);
612
- };
613
- window.addEventListener("mousemove", handleMouseMove);
614
- window.addEventListener("mouseup", handleMouseUp);
602
+ setInitialNote(note);
603
+ startDragging();
615
604
  };
616
605
  _el$2.$$dblclick = event => {
617
606
  event.stopPropagation();
@@ -658,21 +647,19 @@ const PianoRollNotes = props => {
658
647
  }
659
648
  }));
660
649
  web.effect(_$p => web.classList(_el$, {
661
- [styles$2.PianoRollNotes]: true
650
+ [styles$3.PianoRollNotes]: true
662
651
  }, _$p));
663
652
  return _el$;
664
653
  })();
665
654
  };
666
- web.delegateEvents(["mousedown", "mousemove", "mouseup", "dblclick", "click"]);
655
+ web.delegateEvents(["mousedown", "mousemove", "dblclick"]);
667
656
 
668
- 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";
669
- var styles$1 = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Row":"PianoRollGrid-module_PianoRollGrid-Row__nRMCs","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
670
- styleInject(css_248z$1);
657
+ var css_248z$2 = ".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 width: 100%;\n border-width: 0;\n}\n.PianoRollGrid-module_PianoRollGrid-Row__nRMCs.PianoRollGrid-module_IsDark__jRyyy {\n background-color: rgba(0, 0, 0, 0.2);\n}\n\n.PianoRollGrid-module_PianoRollGrid-Row__nRMCs.PianoRollGrid-module_Key__8ZwPN {\n border-width: 0px 1px 0px 0;\n}\n.PianoRollGrid-module_PianoRollGrid-Row__nRMCs.PianoRollGrid-module_IsBlackAndNextIsWhite__UF8O2 {\n background-color: rgba(0, 0, 0, 0.2);\n border-width: 0.1px 1px 0.1px 0;\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 border-left-color: #bbb;\n background: #ccc;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Time__jLz3E.PianoRollGrid-module_Highlighted__N1J6q {\n background: #ddd;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Time__jLz3E.PianoRollGrid-module_HighlightedBorder__Vnrff {\n border-left-color: gray;\n}\n";
658
+ var styles$2 = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Row":"PianoRollGrid-module_PianoRollGrid-Row__nRMCs","IsDark":"PianoRollGrid-module_IsDark__jRyyy","Key":"PianoRollGrid-module_Key__8ZwPN","IsBlackAndNextIsWhite":"PianoRollGrid-module_IsBlackAndNextIsWhite__UF8O2","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E","Highlighted":"PianoRollGrid-module_Highlighted__N1J6q","HighlightedBorder":"PianoRollGrid-module_HighlightedBorder__Vnrff"};
659
+ styleInject(css_248z$2);
671
660
 
672
- const _tmpl$$4 = /*#__PURE__*/web.template(`<div></div>`, 2);
673
- const PianoRollGrid = () => {
661
+ const usePianoRollGrid = () => {
674
662
  const context = usePianoRollContext();
675
- const verticalViewPort = solidJs.createMemo(() => useViewPortDimension(context.mode === "keys" ? "vertical" : "verticalTracks"));
676
663
  const horizontalViewPort = solidJs.createMemo(() => useViewPortDimension("horizontal"));
677
664
  const measureTicks = solidJs.createMemo(() => context.ppq * 4);
678
665
  const selectedGridDivisorTicks = solidJs.createMemo(() => measureTicks() / context.gridDivision);
@@ -693,43 +680,62 @@ const PianoRollGrid = () => {
693
680
  const startIndex = Math.floor(context.position / gridDivisorTicks());
694
681
  return Array.from({
695
682
  length: numberOfLines
696
- }).map((_, index) => ({
697
- index: index + startIndex,
698
- ticks: (index + startIndex) * gridDivisorTicks()
699
- }));
683
+ }).map((_, i) => {
684
+ const index = i + startIndex;
685
+ const ticks = index * gridDivisorTicks();
686
+ const measurePosition = ticks / context.ppq / 4 + 1;
687
+ const bars = Math.floor(measurePosition);
688
+ const beats = Math.floor((measurePosition - bars) * 4);
689
+ const label = `${bars}${beats ? `.${beats}` : ""}`;
690
+ return {
691
+ index,
692
+ ticks,
693
+ isHighlighted: Math.ceil((index + 1) * selectedGridDivisorTicks() / measureTicks()) % 2 === 0,
694
+ hasHighlightedBorder: index * gridDivisorTicks() % selectedGridDivisorTicks() === 0,
695
+ showLabel: index * selectedGridDivisorTicks() / measureTicks() % 2 === 0,
696
+ virtualDimensions: horizontalViewPort().calculatePixelDimensions(ticks, gridDivisorTicks()),
697
+ label
698
+ };
699
+ });
700
700
  });
701
+ return gridArray;
702
+ };
703
+
704
+ const _tmpl$$5 = /*#__PURE__*/web.template(`<div></div>`, 2);
705
+ const PianoRollGrid = () => {
706
+ const context = usePianoRollContext();
707
+ const verticalViewPort = solidJs.createMemo(() => useViewPortDimension(context.mode === "keys" ? "vertical" : "verticalTracks"));
708
+ const horizontalViewPort = solidJs.createMemo(() => useViewPortDimension("horizontal"));
709
+ const gridArray = usePianoRollGrid();
701
710
  return (() => {
702
- const _el$ = _tmpl$$4.cloneNode(true);
711
+ const _el$ = _tmpl$$5.cloneNode(true);
703
712
  web.insert(_el$, web.createComponent(solidJs.Index, {
704
713
  get each() {
705
714
  return gridArray();
706
715
  },
707
716
  children: entry => {
708
- const virtualDimensions = solidJs.createMemo(() => horizontalViewPort().calculatePixelDimensions(entry().ticks, gridDivisorTicks()));
709
717
  return web.createComponent(solidJs.Show, {
710
718
  get when() {
711
- return virtualDimensions().size > 0;
719
+ return horizontalViewPort().isVisible(entry().virtualDimensions);
712
720
  },
713
721
  get children() {
714
- const _el$2 = _tmpl$$4.cloneNode(true);
722
+ const _el$2 = _tmpl$$5.cloneNode(true);
715
723
  web.effect(_p$ => {
716
- const _v$ = styles$1["PianoRollGrid-Time"],
717
- _v$2 = Math.ceil((entry().index + 1 * selectedGridDivisorTicks()) / measureTicks()) % 2 === 0 ? "#ddd" : "#ccc",
718
- _v$3 = `${virtualDimensions().offset}px`,
719
- _v$4 = `${virtualDimensions().size}px`,
720
- _v$5 = entry().index * gridDivisorTicks() % selectedGridDivisorTicks() === 0 ? "gray" : "#bbb";
721
- _v$ !== _p$._v$ && web.className(_el$2, _p$._v$ = _v$);
722
- _v$2 !== _p$._v$2 && _el$2.style.setProperty("background", _p$._v$2 = _v$2);
723
- _v$3 !== _p$._v$3 && _el$2.style.setProperty("left", _p$._v$3 = _v$3);
724
- _v$4 !== _p$._v$4 && _el$2.style.setProperty("width", _p$._v$4 = _v$4);
725
- _v$5 !== _p$._v$5 && _el$2.style.setProperty("border-left-color", _p$._v$5 = _v$5);
724
+ const _v$ = {
725
+ [styles$2["PianoRollGrid-Time"]]: true,
726
+ [styles$2["Highlighted"]]: entry().isHighlighted,
727
+ [styles$2["HighlightedBorder"]]: entry().hasHighlightedBorder
728
+ },
729
+ _v$2 = `${entry().virtualDimensions.offset}px`,
730
+ _v$3 = `${entry().virtualDimensions.size}px`;
731
+ _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
732
+ _v$2 !== _p$._v$2 && _el$2.style.setProperty("left", _p$._v$2 = _v$2);
733
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("width", _p$._v$3 = _v$3);
726
734
  return _p$;
727
735
  }, {
728
736
  _v$: undefined,
729
737
  _v$2: undefined,
730
- _v$3: undefined,
731
- _v$4: undefined,
732
- _v$5: undefined
738
+ _v$3: undefined
733
739
  });
734
740
  return _el$2;
735
741
  }
@@ -747,29 +753,27 @@ const PianoRollGrid = () => {
747
753
  const virtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(127 - key().number, 1));
748
754
  return web.createComponent(solidJs.Show, {
749
755
  get when() {
750
- return virtualDimensions().size > 0;
756
+ return verticalViewPort().isVisible(virtualDimensions());
751
757
  },
752
758
  get children() {
753
- const _el$3 = _tmpl$$4.cloneNode(true);
754
- _el$3.style.setProperty("width", "100%");
759
+ const _el$3 = _tmpl$$5.cloneNode(true);
755
760
  web.effect(_p$ => {
756
- const _v$6 = styles$1["PianoRollGrid-Row"],
757
- _v$7 = `${virtualDimensions().offset}px`,
758
- _v$8 = `${virtualDimensions().size}px`,
759
- _v$9 = key().isBlack ? "rgba(0,0,0,0.2)" : "none",
760
- _v$10 = `${!key().isBlack && !blackKeys.includes((key().number + 1) % 12) ? "0.1px" : 0} 1px ${!key().isBlack && !blackKeys.includes((key().number - 1) % 12) ? "0.1px" : 0} 0`;
761
- _v$6 !== _p$._v$6 && web.className(_el$3, _p$._v$6 = _v$6);
762
- _v$7 !== _p$._v$7 && _el$3.style.setProperty("top", _p$._v$7 = _v$7);
763
- _v$8 !== _p$._v$8 && _el$3.style.setProperty("height", _p$._v$8 = _v$8);
764
- _v$9 !== _p$._v$9 && _el$3.style.setProperty("background-color", _p$._v$9 = _v$9);
765
- _v$10 !== _p$._v$10 && _el$3.style.setProperty("border-width", _p$._v$10 = _v$10);
761
+ const _v$4 = {
762
+ [styles$2["PianoRollGrid-Row"]]: true,
763
+ [styles$2["Key"]]: true,
764
+ [styles$2["IsDark"]]: key().isBlack,
765
+ [styles$2["IsBlackAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12)
766
+ },
767
+ _v$5 = `${virtualDimensions().offset}px`,
768
+ _v$6 = `${virtualDimensions().size}px`;
769
+ _p$._v$4 = web.classList(_el$3, _v$4, _p$._v$4);
770
+ _v$5 !== _p$._v$5 && _el$3.style.setProperty("top", _p$._v$5 = _v$5);
771
+ _v$6 !== _p$._v$6 && _el$3.style.setProperty("height", _p$._v$6 = _v$6);
766
772
  return _p$;
767
773
  }, {
768
- _v$6: undefined,
769
- _v$7: undefined,
770
- _v$8: undefined,
771
- _v$9: undefined,
772
- _v$10: undefined
774
+ _v$4: undefined,
775
+ _v$5: undefined,
776
+ _v$6: undefined
773
777
  });
774
778
  return _el$3;
775
779
  }
@@ -791,27 +795,25 @@ const PianoRollGrid = () => {
791
795
  const virtualDimensions = solidJs.createMemo(() => verticalViewPort().calculatePixelDimensions(index(), 1));
792
796
  return web.createComponent(solidJs.Show, {
793
797
  get when() {
794
- return virtualDimensions().size > 0;
798
+ return verticalViewPort().isVisible(virtualDimensions());
795
799
  },
796
800
  get children() {
797
- const _el$4 = _tmpl$$4.cloneNode(true);
798
- _el$4.style.setProperty("width", "100%");
799
- _el$4.style.setProperty("border-width", "0");
801
+ const _el$4 = _tmpl$$5.cloneNode(true);
800
802
  web.effect(_p$ => {
801
- const _v$11 = styles$1["PianoRollGrid-Row"],
802
- _v$12 = `${virtualDimensions().offset}px`,
803
- _v$13 = `${virtualDimensions().size}px`,
804
- _v$14 = index() % 2 === 0 ? "rgba(0,0,0,0.2)" : "none";
805
- _v$11 !== _p$._v$11 && web.className(_el$4, _p$._v$11 = _v$11);
806
- _v$12 !== _p$._v$12 && _el$4.style.setProperty("top", _p$._v$12 = _v$12);
807
- _v$13 !== _p$._v$13 && _el$4.style.setProperty("height", _p$._v$13 = _v$13);
808
- _v$14 !== _p$._v$14 && _el$4.style.setProperty("background-color", _p$._v$14 = _v$14);
803
+ const _v$7 = {
804
+ [styles$2["PianoRollGrid-Row"]]: true,
805
+ [styles$2["IsDark"]]: index() % 2 === 0
806
+ },
807
+ _v$8 = `${virtualDimensions().offset}px`,
808
+ _v$9 = `${virtualDimensions().size}px`;
809
+ _p$._v$7 = web.classList(_el$4, _v$7, _p$._v$7);
810
+ _v$8 !== _p$._v$8 && _el$4.style.setProperty("top", _p$._v$8 = _v$8);
811
+ _v$9 !== _p$._v$9 && _el$4.style.setProperty("height", _p$._v$9 = _v$9);
809
812
  return _p$;
810
813
  }, {
811
- _v$11: undefined,
812
- _v$12: undefined,
813
- _v$13: undefined,
814
- _v$14: undefined
814
+ _v$7: undefined,
815
+ _v$8: undefined,
816
+ _v$9: undefined
815
817
  });
816
818
  return _el$4;
817
819
  }
@@ -820,47 +822,19 @@ const PianoRollGrid = () => {
820
822
  });
821
823
  }
822
824
  }), null);
823
- web.effect(() => web.className(_el$, styles$1.PianoRollGrid));
825
+ web.effect(() => web.className(_el$, styles$2.PianoRollGrid));
824
826
  return _el$;
825
827
  })();
826
828
  };
827
829
 
828
- const defaultRect = {
829
- left: 0,
830
- width: 0,
831
- top: 0,
832
- height: 0,
833
- bottom: 0,
834
- right: 0,
835
- x: 0,
836
- y: 0
837
- };
838
- function useBoundingClientRect(containerRef) {
839
- const [boundingClientRect, setBoundingClientRect] = solidJs.createSignal(defaultRect);
840
- solidJs.createEffect(() => {
841
- const container = containerRef();
842
- if (!container) return;
843
- const updateBoundingClientRect = () => {
844
- setBoundingClientRect(container.getBoundingClientRect() ?? defaultRect);
845
- };
846
- const resizeObserver = new ResizeObserver(updateBoundingClientRect);
847
- resizeObserver.observe(container);
848
- updateBoundingClientRect();
849
- return () => {
850
- resizeObserver.disconnect();
851
- };
852
- });
853
- return boundingClientRect;
854
- }
855
-
856
- const _tmpl$$3 = /*#__PURE__*/web.template(`<input step="0.01">`, 1);
830
+ const _tmpl$$4 = /*#__PURE__*/web.template(`<input step="0.01">`, 1);
857
831
  const ZoomSliderControl = props => {
858
832
  const propsWithDefaults = solidJs.mergeProps({
859
833
  orientation: "horizontal"
860
834
  }, props);
861
835
  const dimension = solidJs.createMemo(() => useViewPortDimension(props.dimensionName ?? propsWithDefaults.orientation));
862
836
  return (() => {
863
- const _el$ = _tmpl$$3.cloneNode(true);
837
+ const _el$ = _tmpl$$4.cloneNode(true);
864
838
  web.spread(_el$, web.mergeProps({
865
839
  get min() {
866
840
  return dimension().minZoom;
@@ -872,7 +846,10 @@ const ZoomSliderControl = props => {
872
846
  get value() {
873
847
  return dimension().zoom;
874
848
  },
875
- "onInput": event => dimension().onZoomChange?.(event.currentTarget.valueAsNumber),
849
+ "onInput": event => {
850
+ const value = event.currentTarget.valueAsNumber;
851
+ dimension().onZoomChange?.(value);
852
+ },
876
853
  "type": "range"
877
854
  }, () => ({
878
855
  orient: propsWithDefaults.orientation
@@ -902,17 +879,17 @@ const ZoomSliderControl = props => {
902
879
  })();
903
880
  };
904
881
 
905
- 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";
906
- var styles = {"PianoRollTrackList":"PianoRollTrackList-module_PianoRollTrackList__pyuxQ","Track":"PianoRollTrackList-module_Track__VZFIg"};
907
- styleInject(css_248z);
882
+ var css_248z$1 = ".PianoRollTrackList-module_PianoRollTrackList__-sDf0 {\n position: relative;\n height: 100%;\n flex: 1;\n}\n\n.PianoRollTrackList-module_Track__mZP1K {\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 padding: 2px;\n cursor: pointer;\n background: lightgrey;\n}\n.PianoRollTrackList-module_Track__mZP1K.PianoRollTrackList-module_selected__0b-mf {\n background: gray;\n}";
883
+ var styles$1 = {"PianoRollTrackList":"PianoRollTrackList-module_PianoRollTrackList__-sDf0","Track":"PianoRollTrackList-module_Track__mZP1K","selected":"PianoRollTrackList-module_selected__0b-mf"};
884
+ styleInject(css_248z$1);
908
885
 
909
- const _tmpl$$2 = /*#__PURE__*/web.template(`<div></div>`, 2),
886
+ const _tmpl$$3 = /*#__PURE__*/web.template(`<div></div>`, 2),
910
887
  _tmpl$2$1 = /*#__PURE__*/web.template(`<div> </div>`, 2);
911
888
  const PianoRollTrackList = () => {
912
889
  const viewPort = solidJs.createMemo(() => useViewPortDimension("verticalTracks"));
913
890
  const context = usePianoRollContext();
914
891
  return (() => {
915
- const _el$ = _tmpl$$2.cloneNode(true);
892
+ const _el$ = _tmpl$$3.cloneNode(true);
916
893
  web.insert(_el$, web.createComponent(solidJs.Index, {
917
894
  get each() {
918
895
  return context.tracks;
@@ -927,135 +904,279 @@ const PianoRollTrackList = () => {
927
904
  const _el$2 = _tmpl$2$1.cloneNode(true),
928
905
  _el$3 = _el$2.firstChild;
929
906
  _el$2.$$click = () => context.onSelectedTrackIndexChange?.(index);
930
- _el$2.style.setProperty("cursor", "pointer");
931
907
  web.insert(_el$2, index, _el$3);
932
908
  web.insert(_el$2, () => track().name || "[unnamed track]", null);
933
909
  web.effect(_p$ => {
934
910
  const _v$ = {
935
- [styles["Track"]]: true
911
+ [styles$1["Track"]]: true,
912
+ [styles$1["selected"]]: index === context.selectedTrackIndex
936
913
  },
937
914
  _v$2 = track().name,
938
915
  _v$3 = `${virtualDimensions().offset}px`,
939
- _v$4 = `${virtualDimensions().size}px`,
940
- _v$5 = index === context.selectedTrackIndex ? "gray" : "lightgrey";
916
+ _v$4 = `${virtualDimensions().size}px`;
941
917
  _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
942
918
  _v$2 !== _p$._v$2 && web.setAttribute(_el$2, "title", _p$._v$2 = _v$2);
943
919
  _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
944
920
  _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
945
- _v$5 !== _p$._v$5 && _el$2.style.setProperty("background", _p$._v$5 = _v$5);
946
921
  return _p$;
947
922
  }, {
948
923
  _v$: undefined,
949
924
  _v$2: undefined,
950
925
  _v$3: undefined,
951
- _v$4: undefined,
952
- _v$5: undefined
926
+ _v$4: undefined
953
927
  });
954
928
  return _el$2;
955
929
  }
956
930
  });
957
931
  }
958
932
  }));
959
- web.effect(() => web.className(_el$, styles.PianoRollTrackList));
933
+ web.effect(() => web.className(_el$, styles$1.PianoRollTrackList));
960
934
  return _el$;
961
935
  })();
962
936
  };
963
937
  web.delegateEvents(["click"]);
964
938
 
965
- const _tmpl$$1 = /*#__PURE__*/web.template(`<div><div></div></div>`, 4),
966
- _tmpl$2 = /*#__PURE__*/web.template(`<div></div>`, 2);
939
+ const PianoRollScrollZoomViewPort = props => {
940
+ const zoomFactor = 500;
941
+ const context = usePianoRollContext();
942
+ return web.createComponent(ScrollZoomViewPort, {
943
+ dimensions: {
944
+ horizontal: () => ({
945
+ pixelOffset: context.notesScrollerClientRect.left,
946
+ pixelSize: context.notesScrollerClientRect.width,
947
+ position: context.position,
948
+ range: context.duration,
949
+ zoom: context.zoom * (zoomFactor / context.notesScrollerClientRect.width),
950
+ onPositionChange: context.onPositionChange,
951
+ onZoomChange: zoom => context.onZoomChange?.(zoom / (zoomFactor / context.notesScrollerClientRect.width)),
952
+ minZoom: 1,
953
+ maxZoom: 500
954
+ }),
955
+ vertical: () => ({
956
+ pixelOffset: context.notesScrollerClientRect.top,
957
+ pixelSize: context.notesScrollerClientRect.height,
958
+ position: context.verticalPosition,
959
+ range: 128,
960
+ zoom: context.verticalZoom * (zoomFactor / context.notesScrollerClientRect.height),
961
+ onPositionChange: context.onVerticalPositionChange,
962
+ onZoomChange: verticalZoom => context.onVerticalZoomChange?.(verticalZoom / (zoomFactor / context.notesScrollerClientRect.height)),
963
+ minZoom: 1,
964
+ maxZoom: 10
965
+ }),
966
+ horizontalTracks: () => ({
967
+ pixelOffset: 0,
968
+ pixelSize: context.tracksScrollerClientRect.width
969
+ }),
970
+ verticalTracks: () => ({
971
+ pixelOffset: context.tracksScrollerClientRect.top,
972
+ pixelSize: context.tracksScrollerClientRect.height,
973
+ position: context.verticalTrackPosition,
974
+ range: context.tracks.length,
975
+ zoom: context.verticalTrackZoom * (zoomFactor / context.tracksScrollerClientRect.height),
976
+ onPositionChange: context.onVerticalTrackPositionChange,
977
+ onZoomChange: verticalTrackZoom => context.onVerticalTrackZoomChange?.(verticalTrackZoom / (zoomFactor / context.tracksScrollerClientRect.height)),
978
+ minZoom: 0.8,
979
+ maxZoom: 3
980
+ }),
981
+ horizontalKeys: () => ({
982
+ pixelSize: 60
983
+ })
984
+ },
985
+ get children() {
986
+ return props.children;
987
+ }
988
+ });
989
+ };
990
+
991
+ const defaultRect = {
992
+ left: 0,
993
+ width: 0,
994
+ top: 0,
995
+ height: 0,
996
+ bottom: 0,
997
+ right: 0,
998
+ x: 0,
999
+ y: 0
1000
+ };
1001
+ function useBoundingClientRect(containerRef) {
1002
+ const [boundingClientRect, setBoundingClientRect] = solidJs.createSignal(defaultRect);
1003
+ solidJs.createEffect(() => {
1004
+ const container = containerRef();
1005
+ if (!container) return;
1006
+ const updateBoundingClientRect = () => {
1007
+ setBoundingClientRect(container.getBoundingClientRect() ?? defaultRect);
1008
+ };
1009
+ const resizeObserver = new ResizeObserver(updateBoundingClientRect);
1010
+ resizeObserver.observe(container);
1011
+ updateBoundingClientRect();
1012
+ return () => {
1013
+ resizeObserver.disconnect();
1014
+ };
1015
+ });
1016
+ return boundingClientRect;
1017
+ }
1018
+
1019
+ const PianoRollNotesScroller = props => {
1020
+ const context = usePianoRollContext();
1021
+ const [ref, setRef] = solidJs.createSignal();
1022
+ const clientRect = useBoundingClientRect(ref);
1023
+ solidJs.createEffect(() => {
1024
+ context.onNotesScrollerClientRectChange(clientRect());
1025
+ });
1026
+ return web.createComponent(ScrollZoomContainer, {
1027
+ ref: setRef,
1028
+ get verticalDimensionName() {
1029
+ return context.mode === "keys" ? "vertical" : "verticalTracks";
1030
+ },
1031
+ get children() {
1032
+ return props.children;
1033
+ }
1034
+ });
1035
+ };
1036
+
1037
+ const PianoRollTrackListScroller = props => {
1038
+ const context = usePianoRollContext();
1039
+ const [ref, setRef] = solidJs.createSignal();
1040
+ const clientRect = useBoundingClientRect(ref);
1041
+ solidJs.createEffect(() => {
1042
+ context.onTracksScrollerClientRectChange(clientRect());
1043
+ });
1044
+ return web.createComponent(ScrollZoomContainer, {
1045
+ ref: setRef,
1046
+ horizontalDimensionName: "horizontalTracks",
1047
+ verticalDimensionName: "verticalTracks",
1048
+ get showScrollbar() {
1049
+ return context.mode === "keys";
1050
+ },
1051
+ get children() {
1052
+ return props.children;
1053
+ }
1054
+ });
1055
+ };
1056
+
1057
+ var css_248z = ".PianoRollScale-module_PianoRollScale__5wGRm {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.PianoRollScale-module_PianoRollScale-Time__03hGQ {\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 border-left-color: x#666;\n border-bottom-color: #333;\n border-bottom-style: solid;\n border-bottom-width: 0.5px;\n background: #777;\n display: flex;\n align-items: center;\n}\n\n.PianoRollScale-module_PianoRollScale-Label__aoRi6 {\n position: absolute;\n z-index: 1;\n color: #ccc;\n margin-left: 3px;\n font-size: 0.8em;\n}\n\n.PianoRollScale-module_PianoRollScale-Time__03hGQ.PianoRollScale-module_Highlighted__ziWn5 {\n background: #666;\n}\n\n.PianoRollScale-module_PianoRollScale-Time__03hGQ.PianoRollScale-module_HighlightedBorder__-OoZE {\n border-left-color: #111;\n}\n";
1058
+ var styles = {"PianoRollScale":"PianoRollScale-module_PianoRollScale__5wGRm","PianoRollScale-Time":"PianoRollScale-module_PianoRollScale-Time__03hGQ","PianoRollScale-Label":"PianoRollScale-module_PianoRollScale-Label__aoRi6","Highlighted":"PianoRollScale-module_Highlighted__ziWn5","HighlightedBorder":"PianoRollScale-module_HighlightedBorder__-OoZE"};
1059
+ styleInject(css_248z);
1060
+
1061
+ const _tmpl$$2 = /*#__PURE__*/web.template(`<div></div>`, 2);
1062
+ const PianoRollScale = () => {
1063
+ const horizontalViewPort = solidJs.createMemo(() => useViewPortDimension("horizontal"));
1064
+ const grid = usePianoRollGrid();
1065
+ return (() => {
1066
+ const _el$ = _tmpl$$2.cloneNode(true);
1067
+ web.insert(_el$, web.createComponent(solidJs.Index, {
1068
+ get each() {
1069
+ return grid();
1070
+ },
1071
+ children: entry => {
1072
+ return web.createComponent(solidJs.Show, {
1073
+ get when() {
1074
+ return horizontalViewPort().isVisible(entry().virtualDimensions);
1075
+ },
1076
+ get children() {
1077
+ const _el$2 = _tmpl$$2.cloneNode(true);
1078
+ web.insert(_el$2, web.createComponent(solidJs.Show, {
1079
+ get when() {
1080
+ return entry().showLabel;
1081
+ },
1082
+ get children() {
1083
+ const _el$3 = _tmpl$$2.cloneNode(true);
1084
+ web.insert(_el$3, () => entry().label);
1085
+ web.effect(() => web.className(_el$3, styles["PianoRollScale-Label"]));
1086
+ return _el$3;
1087
+ }
1088
+ }));
1089
+ web.effect(_p$ => {
1090
+ const _v$ = {
1091
+ [styles["PianoRollScale-Time"]]: true,
1092
+ [styles["Highlighted"]]: entry().isHighlighted,
1093
+ [styles["HighlightedBorder"]]: entry().hasHighlightedBorder
1094
+ },
1095
+ _v$2 = `${entry().virtualDimensions.offset}px`,
1096
+ _v$3 = `${entry().virtualDimensions.size}px`;
1097
+ _p$._v$ = web.classList(_el$2, _v$, _p$._v$);
1098
+ _v$2 !== _p$._v$2 && _el$2.style.setProperty("left", _p$._v$2 = _v$2);
1099
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("width", _p$._v$3 = _v$3);
1100
+ return _p$;
1101
+ }, {
1102
+ _v$: undefined,
1103
+ _v$2: undefined,
1104
+ _v$3: undefined
1105
+ });
1106
+ return _el$2;
1107
+ }
1108
+ });
1109
+ }
1110
+ }));
1111
+ web.effect(() => web.className(_el$, styles.PianoRollScale));
1112
+ return _el$;
1113
+ })();
1114
+ };
1115
+
1116
+ const _tmpl$$1 = /*#__PURE__*/web.template(`<div><button><div></div></button></div>`, 6),
1117
+ _tmpl$2 = /*#__PURE__*/web.template(`<div><div><div></div></div><div><div></div></div></div>`, 10),
1118
+ _tmpl$3 = /*#__PURE__*/web.template(`<div></div>`, 2);
967
1119
  const PianoRoll = allProps => {
968
1120
  const propsWithDefaults = solidJs.mergeProps({
969
1121
  showAllTracks: false
970
1122
  }, allProps);
971
1123
  const [context, divProps] = splitContextProps(propsWithDefaults);
972
- const [notesScrollerRef, setNotesScrollerRef] = solidJs.createSignal();
973
- const [tracksScrollerRef, setTracksScrollerRef] = solidJs.createSignal();
974
- const notesScrollerClientRect = useBoundingClientRect(notesScrollerRef);
975
- const tracksScrollerClientRect = useBoundingClientRect(tracksScrollerRef);
976
- const zoomFactor = 500;
977
1124
  return web.createComponent(PianoRollContextProvider, {
978
1125
  value: context,
979
1126
  get children() {
980
- const _el$ = _tmpl$2.cloneNode(true);
1127
+ const _el$ = _tmpl$3.cloneNode(true);
981
1128
  web.spread(_el$, web.mergeProps(divProps, {
982
1129
  get ["class"]() {
983
- return styles$5.PianoRoll;
1130
+ return styles$6.PianoRoll;
984
1131
  }
985
1132
  }), false, true);
986
- web.insert(_el$, web.createComponent(ScrollZoomViewPort, {
987
- dimensions: {
988
- horizontal: () => ({
989
- pixelOffset: notesScrollerClientRect().left,
990
- pixelSize: notesScrollerClientRect().width,
991
- position: context.position,
992
- range: context.duration,
993
- zoom: context.zoom * (zoomFactor / notesScrollerClientRect().width),
994
- onPositionChange: context.onPositionChange,
995
- onZoomChange: zoom => context.onZoomChange?.(zoom / (zoomFactor / notesScrollerClientRect().width)),
996
- minZoom: 1,
997
- maxZoom: 500
998
- }),
999
- vertical: () => ({
1000
- pixelOffset: notesScrollerClientRect().top,
1001
- pixelSize: notesScrollerClientRect().height,
1002
- position: context.verticalPosition,
1003
- range: 128,
1004
- zoom: context.verticalZoom * (zoomFactor / notesScrollerClientRect().height),
1005
- onPositionChange: context.onVerticalPositionChange,
1006
- onZoomChange: verticalZoom => context.onVerticalZoomChange?.(verticalZoom / (zoomFactor / notesScrollerClientRect().height)),
1007
- minZoom: 1,
1008
- maxZoom: 10
1009
- }),
1010
- horizontalTracks: () => ({
1011
- pixelOffset: 0,
1012
- pixelSize: tracksScrollerClientRect().width
1013
- }),
1014
- verticalTracks: () => ({
1015
- pixelOffset: tracksScrollerClientRect().top,
1016
- pixelSize: tracksScrollerClientRect().height,
1017
- position: context.verticalTrackPosition,
1018
- range: context.tracks.length,
1019
- zoom: context.verticalTrackZoom * (zoomFactor / tracksScrollerClientRect().height),
1020
- onPositionChange: context.onVerticalTrackPositionChange,
1021
- onZoomChange: verticalTrackZoom => context.onVerticalTrackZoomChange?.(verticalTrackZoom / (zoomFactor / tracksScrollerClientRect().height)),
1022
- minZoom: 0.8,
1023
- maxZoom: 3
1024
- }),
1025
- horizontalKeys: () => ({
1026
- pixelSize: 60
1027
- })
1028
- },
1133
+ web.insert(_el$, web.createComponent(PianoRollScrollZoomViewPort, {
1029
1134
  get children() {
1030
1135
  return [(() => {
1031
- const _el$2 = _tmpl$$1.cloneNode(true),
1032
- _el$3 = _el$2.firstChild;
1136
+ const _el$2 = _tmpl$2.cloneNode(true),
1137
+ _el$3 = _el$2.firstChild,
1138
+ _el$7 = _el$3.firstChild,
1139
+ _el$8 = _el$3.nextSibling,
1140
+ _el$9 = _el$8.firstChild;
1033
1141
  web.insert(_el$2, web.createComponent(ZoomSliderControl, {
1034
1142
  orientation: "vertical",
1035
1143
  dimensionName: "verticalTracks"
1036
1144
  }), _el$3);
1037
- _el$3.style.setProperty("display", "flex");
1038
- _el$3.style.setProperty("width", "30%");
1039
- _el$3.style.setProperty("max-width", "250px");
1040
1145
  web.insert(_el$3, web.createComponent(solidJs.Show, {
1041
1146
  get when() {
1042
1147
  return context.showTrackList;
1043
1148
  },
1044
1149
  get children() {
1045
- return web.createComponent(ScrollZoomContainer, {
1046
- ref: setTracksScrollerRef,
1047
- horizontalDimensionName: "horizontalTracks",
1048
- verticalDimensionName: "verticalTracks",
1049
- get showScrollbar() {
1050
- return context.mode === "keys";
1051
- },
1150
+ const _el$4 = _tmpl$$1.cloneNode(true),
1151
+ _el$5 = _el$4.firstChild,
1152
+ _el$6 = _el$5.firstChild;
1153
+ _el$4.style.setProperty("height", "30px");
1154
+ _el$5.$$click = () => context.onModeChange(context.mode === "keys" ? "tracks" : "keys");
1155
+ _el$5.style.setProperty("font-size", "16px");
1156
+ _el$5.style.setProperty("line-height", "16px");
1157
+ _el$5.style.setProperty("cursor", "pointer");
1158
+ _el$5.style.setProperty("overflow", "hidden");
1159
+ web.insert(_el$6, () => context.mode === "keys" ? "≡" : "🎹");
1160
+ web.effect(() => web.setAttribute(_el$5, "title", context.mode === "keys" ? "Tracks Mode" : "Keys Mode"));
1161
+ return _el$4;
1162
+ }
1163
+ }), _el$7);
1164
+ _el$7.style.setProperty("flex", "1");
1165
+ _el$7.style.setProperty("display", "flex");
1166
+ _el$7.style.setProperty("overflow", "hidden");
1167
+ web.insert(_el$7, web.createComponent(solidJs.Show, {
1168
+ get when() {
1169
+ return context.showTrackList;
1170
+ },
1171
+ get children() {
1172
+ return web.createComponent(PianoRollTrackListScroller, {
1052
1173
  get children() {
1053
1174
  return web.createComponent(PianoRollTrackList, {});
1054
1175
  }
1055
1176
  });
1056
1177
  }
1057
1178
  }), null);
1058
- web.insert(_el$3, web.createComponent(solidJs.Show, {
1179
+ web.insert(_el$7, web.createComponent(solidJs.Show, {
1059
1180
  get when() {
1060
1181
  return context.mode === "keys";
1061
1182
  },
@@ -1063,11 +1184,14 @@ const PianoRoll = allProps => {
1063
1184
  return web.createComponent(PianoRollKeys, {});
1064
1185
  }
1065
1186
  }), null);
1066
- web.insert(_el$2, web.createComponent(ScrollZoomContainer, {
1067
- ref: setNotesScrollerRef,
1068
- get verticalDimensionName() {
1069
- return context.mode === "keys" ? "vertical" : "verticalTracks";
1070
- },
1187
+ _el$8.style.setProperty("width", "100%");
1188
+ _el$8.style.setProperty("display", "flex");
1189
+ _el$8.style.setProperty("height", "100%");
1190
+ _el$8.style.setProperty("flex-direction", "column");
1191
+ _el$8.style.setProperty("overflow", "hidden");
1192
+ _el$9.style.setProperty("height", "30px");
1193
+ web.insert(_el$9, web.createComponent(PianoRollScale, {}));
1194
+ web.insert(_el$8, web.createComponent(PianoRollNotesScroller, {
1071
1195
  get children() {
1072
1196
  return [web.memo(() => allProps.children), web.createComponent(PianoRollGrid, {}), web.createComponent(PianoRollNotes, {})];
1073
1197
  }
@@ -1078,13 +1202,25 @@ const PianoRoll = allProps => {
1078
1202
  return context.mode !== "keys";
1079
1203
  }
1080
1204
  }), null);
1081
- web.effect(() => web.className(_el$2, styles$5.PianoRollContainer));
1205
+ web.effect(_p$ => {
1206
+ const _v$ = styles$6.PianoRollContainer,
1207
+ _v$2 = {
1208
+ [styles$6.PianoRollLeftColumn]: true,
1209
+ [styles$6.showTrackList]: context.showTrackList
1210
+ };
1211
+ _v$ !== _p$._v$ && web.className(_el$2, _p$._v$ = _v$);
1212
+ _p$._v$2 = web.classList(_el$3, _v$2, _p$._v$2);
1213
+ return _p$;
1214
+ }, {
1215
+ _v$: undefined,
1216
+ _v$2: undefined
1217
+ });
1082
1218
  return _el$2;
1083
1219
  })(), web.createComponent(ZoomSliderControl, {
1084
1220
  orientation: "horizontal",
1085
1221
  get style() {
1086
1222
  return {
1087
- "margin-left": `${tracksScrollerClientRect().width + 24}px`,
1223
+ "margin-left": `${context.tracksScrollerClientRect.width + 24}px`,
1088
1224
  "margin-right": "24px"
1089
1225
  };
1090
1226
  }
@@ -1095,22 +1231,19 @@ const PianoRoll = allProps => {
1095
1231
  }
1096
1232
  });
1097
1233
  };
1234
+ web.delegateEvents(["click"]);
1098
1235
 
1099
1236
  const _tmpl$ = /*#__PURE__*/web.template(`<div class="PlayHead"></div>`, 2);
1100
1237
  const PlayHead = allProps => {
1101
- const propsWithDefauls = solidJs.mergeProps({
1102
- playHeadPosition: 0,
1103
- sync: false
1104
- }, allProps);
1105
- const [props, divProps] = solidJs.splitProps(propsWithDefauls, ["playHeadPosition", "sync", "onPlayHeadPositionChange", "onPositionChange"]);
1106
- const viewPort = useViewPortDimension("horizontal");
1238
+ const [props, divProps] = solidJs.splitProps(allProps, ["position", "sync", "onPositionChange", "dimensionName"]);
1239
+ const viewPort = useViewPortDimension(props.dimensionName ?? "horizontal");
1107
1240
  solidJs.createEffect(() => {
1108
1241
  if (!props.sync) return;
1109
1242
  const maxPosition = viewPort.range;
1110
- const newPosition = clamp(props.playHeadPosition - viewPort.range / viewPort.zoom / 2, 0, maxPosition);
1111
- props.onPositionChange?.(newPosition);
1243
+ const newPosition = clamp(props.position - viewPort.range / viewPort.zoom / 2, 0, maxPosition);
1244
+ viewPort.onPositionChange?.(newPosition);
1112
1245
  });
1113
- const leftPosition = solidJs.createMemo(() => viewPort.calculatePixelOffset(props.playHeadPosition));
1246
+ const leftPosition = solidJs.createMemo(() => viewPort.calculatePixelOffset(props.position));
1114
1247
  return (() => {
1115
1248
  const _el$ = _tmpl$.cloneNode(true);
1116
1249
  web.spread(_el$, web.mergeProps(divProps, {
@@ -1132,7 +1265,7 @@ const PlayHead = allProps => {
1132
1265
  clientX
1133
1266
  }) => {
1134
1267
  const newPosition = viewPort.calculatePosition(clientX);
1135
- props.onPlayHeadPositionChange?.(newPosition);
1268
+ props.onPositionChange?.(newPosition);
1136
1269
  };
1137
1270
  const handleMouseUp = () => {
1138
1271
  window.removeEventListener("mousemove", handleMouseMove);