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