solid-pianoroll 0.0.10 → 0.0.12

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, insert, effect, classList, setAttribute, className, template, delegateEvents, use, memo, spread, mergeProps } from 'solid-js/web';
2
- import { createContext, useContext, createEffect, createMemo, Index, Show, createSignal, splitProps } from 'solid-js';
1
+ import { spread, mergeProps, template, createComponent, delegateEvents, use, insert, memo, effect, className, style, classList, setAttribute } from 'solid-js/web';
2
+ import { createContext, splitProps, useContext, createEffect, createMemo, createSignal, Index, Show, mergeProps as mergeProps$1 } from 'solid-js';
3
3
  import { createStore } from 'solid-js/store';
4
4
 
5
5
  function styleInject(css, ref) {
@@ -27,7 +27,7 @@ function styleInject(css, ref) {
27
27
  }
28
28
  }
29
29
 
30
- var css_248z$3 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n padding-top: 16px;\n padding-left: 16px;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
30
+ var css_248z$3 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
31
31
  var styles$3 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
32
32
  styleInject(css_248z$3);
33
33
 
@@ -38,10 +38,30 @@ const usePianoRollContext = () => {
38
38
  if (!context) throw new Error("No PianoRollContext found");
39
39
  return context;
40
40
  };
41
+ const splitContextProps = allProps => splitProps(allProps, ["condensed", "duration", "gridDivision", "notes", "position", "ppq", "snapToGrid", "verticalPosition", "verticalZoom", "zoom", "onInsertNote", "onNoteChange", "onPositionChange", "onRemoveNote", "onVerticalPositionChange", "onVerticalZoomChange", "onZoomChange"]);
41
42
 
42
- var css_248z$2 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\n width: 50px;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n}\n\n.PianoRollKeys-module_whiteAndNextIsWhite__PN1O8 {\n border-top-width: 0.1px;\n}\n\n.PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q {\n border-bottom-width: 0.1px;\n}\n";
43
- var styles$2 = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","Key":"PianoRollKeys-module_Key__jybNC","black":"PianoRollKeys-module_black__7rncB","white":"PianoRollKeys-module_white__fR2Lm","whiteAndNextIsWhite":"PianoRollKeys-module_whiteAndNextIsWhite__PN1O8","whiteAndPreviousIsWhite":"PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q"};
44
- styleInject(css_248z$2);
43
+ const _tmpl$$7 = /*#__PURE__*/template(`<input max="500" min="1" step="0.01">`, 1);
44
+ const HorizontalZoomControl = props => {
45
+ const context = usePianoRollContext();
46
+ return (() => {
47
+ const _el$ = _tmpl$$7.cloneNode(true);
48
+ spread(_el$, mergeProps(props, {
49
+ get value() {
50
+ return context.zoom;
51
+ },
52
+ "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
53
+ "type": "range",
54
+ get style() {
55
+ return {
56
+ "margin-left": "50px",
57
+ "margin-right": "16px",
58
+ ...(typeof props.style === "object" && props.style)
59
+ };
60
+ }
61
+ }), false, false);
62
+ return _el$;
63
+ })();
64
+ };
45
65
 
46
66
  function createViewPortDimension(getState) {
47
67
  const getStateWithFunctions = () => ({
@@ -50,7 +70,8 @@ function createViewPortDimension(getState) {
50
70
  calculatePosition,
51
71
  calculatePixelDimensions,
52
72
  calculateVisibleRange,
53
- calculateMaxPosition
73
+ calculateMaxPosition,
74
+ isVisible
54
75
  });
55
76
  const [state, setState] = createStore(getStateWithFunctions());
56
77
  createEffect(() => setState(getStateWithFunctions()));
@@ -80,6 +101,12 @@ function createViewPortDimension(getState) {
80
101
  size
81
102
  };
82
103
  }
104
+ function isVisible({
105
+ offset,
106
+ size
107
+ }) {
108
+ return offset + size > 0 && offset < state.pixelSize;
109
+ }
83
110
  return state;
84
111
  }
85
112
  const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
@@ -107,70 +134,11 @@ const useViewPortDimension = name => {
107
134
  return viewPort;
108
135
  };
109
136
 
110
- const _tmpl$$6 = /*#__PURE__*/template(`<div></div>`, 2);
111
- const PianoRollKeys = () => {
112
- const viewPort = createMemo(() => useViewPortDimension("vertical"));
113
- return (() => {
114
- const _el$ = _tmpl$$6.cloneNode(true);
115
- insert(_el$, createComponent(Index, {
116
- each: keys,
117
- children: key => {
118
- const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
119
- return createComponent(Show, {
120
- get when() {
121
- return virtualDimensions().size > 0;
122
- },
123
- get children() {
124
- const _el$2 = _tmpl$$6.cloneNode(true);
125
- effect(_p$ => {
126
- const _v$ = {
127
- [styles$2["Key"]]: true,
128
- [styles$2["black"]]: key().isBlack,
129
- [styles$2["white"]]: !key().isBlack,
130
- [styles$2["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
131
- [styles$2["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
132
- },
133
- _v$2 = key().name,
134
- _v$3 = key().number % 12,
135
- _v$4 = `${virtualDimensions().offset}px`,
136
- _v$5 = `${virtualDimensions().size}px`;
137
- _p$._v$ = classList(_el$2, _v$, _p$._v$);
138
- _v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
139
- _v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
140
- _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
141
- _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
142
- return _p$;
143
- }, {
144
- _v$: undefined,
145
- _v$2: undefined,
146
- _v$3: undefined,
147
- _v$4: undefined,
148
- _v$5: undefined
149
- });
150
- return _el$2;
151
- }
152
- });
153
- }
154
- }));
155
- effect(() => className(_el$, styles$2.PianoRollKeys));
156
- return _el$;
157
- })();
158
- };
159
- const blackKeys = [1, 3, 6, 8, 10];
160
- const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
161
- const keys = Array.from({
162
- length: 128
163
- }).map((_, index) => ({
164
- number: index,
165
- name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
166
- isBlack: blackKeys.includes(index % 12)
167
- }));
168
-
169
- var css_248z$1 = ".PianoRollNotes-module_PianoRollNotes__6pF-y {\n position: absolute;\n flex: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\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: pointer;\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}";
170
- var styles$1 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
171
- styleInject(css_248z$1);
137
+ 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}";
138
+ var styles$2 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
139
+ styleInject(css_248z$2);
172
140
 
173
- const _tmpl$$5 = /*#__PURE__*/template(`<div></div>`, 2);
141
+ const _tmpl$$6 = /*#__PURE__*/template(`<div></div>`, 2);
174
142
  const PianoRollNotes = props => {
175
143
  const context = usePianoRollContext();
176
144
  const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
@@ -179,7 +147,7 @@ const PianoRollNotes = props => {
179
147
  const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
180
148
  const insertOrUpdateNote = event => {
181
149
  const position = horizontalViewPort().calculatePosition(event.clientX);
182
- const midi = 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
150
+ const midi = context.condensed ? 60 : 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
183
151
  const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
184
152
  const velocity = 127;
185
153
  const existingNote = newNote();
@@ -204,10 +172,10 @@ const PianoRollNotes = props => {
204
172
  const [isMouseDown, setIsMouseDown] = createSignal(false);
205
173
  const newNote = createMemo(() => context.notes[newNoteIndex()]);
206
174
  const getClasses = noteDragMode => {
207
- return noteDragMode ? [styles$1.Note, styles$1[noteDragMode]] : [styles$1.Note];
175
+ return noteDragMode ? [styles$2.Note, styles$2[noteDragMode]] : [styles$2.Note];
208
176
  };
209
177
  return (() => {
210
- const _el$ = _tmpl$$5.cloneNode(true);
178
+ const _el$ = _tmpl$$6.cloneNode(true);
211
179
  _el$.$$click = event => {
212
180
  if (newNote()) {
213
181
  setNewNoteIndex(-1);
@@ -231,9 +199,6 @@ const PianoRollNotes = props => {
231
199
  return;
232
200
  }
233
201
  const index = insertOrUpdateNote(event);
234
- console.log({
235
- index
236
- });
237
202
  setNewNoteIndex(index);
238
203
  };
239
204
  _el$.$$mousedown = () => {
@@ -247,14 +212,14 @@ const PianoRollNotes = props => {
247
212
  return context.notes;
248
213
  },
249
214
  children: (note, index) => {
250
- const verticalVirtualDimensionss = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
215
+ const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
251
216
  const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
252
217
  return createComponent(Show, {
253
218
  get when() {
254
- return memo(() => !!!!verticalVirtualDimensionss().size)() && !!horizontalDimensions().size;
219
+ return memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
255
220
  },
256
221
  get children() {
257
- const _el$2 = _tmpl$$5.cloneNode(true);
222
+ const _el$2 = _tmpl$$6.cloneNode(true);
258
223
  _el$2.$$mousedown = event => {
259
224
  event.stopPropagation();
260
225
  setIsDragging(true);
@@ -264,7 +229,7 @@ const PianoRollNotes = props => {
264
229
  const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
265
230
  context.onNoteChange?.(index, {
266
231
  ...note(),
267
- ...(noteDragMode() === "move" && {
232
+ ...(noteDragMode() === "move" && !context.condensed && {
268
233
  midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
269
234
  }),
270
235
  ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
@@ -300,38 +265,37 @@ const PianoRollNotes = props => {
300
265
  };
301
266
  effect(_p$ => {
302
267
  const _v$ = getClasses(noteDragMode()).join(" "),
303
- _v$2 = `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
304
- _v$3 = `${verticalVirtualDimensionss().offset}px`,
305
- _v$4 = `${verticalVirtualDimensionss().size}px`,
306
- _v$5 = `${horizontalDimensions().offset}px`,
307
- _v$6 = `${horizontalDimensions().size}px`;
268
+ _v$2 = {
269
+ "background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
270
+ ...(context.condensed ? {
271
+ top: 0,
272
+ height: "100%"
273
+ } : {
274
+ top: `${verticalVirtualDimensions().offset}px`,
275
+ height: `${verticalVirtualDimensions().size}px`
276
+ }),
277
+ left: `${horizontalDimensions().offset}px`,
278
+ width: `${horizontalDimensions().size}px`
279
+ };
308
280
  _v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
309
- _v$2 !== _p$._v$2 && _el$2.style.setProperty("background-color", _p$._v$2 = _v$2);
310
- _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
311
- _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
312
- _v$5 !== _p$._v$5 && _el$2.style.setProperty("left", _p$._v$5 = _v$5);
313
- _v$6 !== _p$._v$6 && _el$2.style.setProperty("width", _p$._v$6 = _v$6);
281
+ _p$._v$2 = style(_el$2, _v$2, _p$._v$2);
314
282
  return _p$;
315
283
  }, {
316
284
  _v$: undefined,
317
- _v$2: undefined,
318
- _v$3: undefined,
319
- _v$4: undefined,
320
- _v$5: undefined,
321
- _v$6: undefined
285
+ _v$2: undefined
322
286
  });
323
287
  return _el$2;
324
288
  }
325
289
  });
326
290
  }
327
291
  }));
328
- effect(() => className(_el$, styles$1.PianoRollNotes));
292
+ effect(() => className(_el$, styles$2.PianoRollNotes));
329
293
  return _el$;
330
294
  })();
331
295
  };
332
296
  delegateEvents(["mousedown", "mousemove", "mouseup", "dblclick", "click"]);
333
297
 
334
- const _tmpl$$4 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
298
+ const _tmpl$$5 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
335
299
  const ScrollContainer = props => {
336
300
  let scrollContentRef;
337
301
  const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
@@ -393,7 +357,7 @@ const ScrollContainer = props => {
393
357
  });
394
358
  });
395
359
  return (() => {
396
- const _el$ = _tmpl$$4.cloneNode(true),
360
+ const _el$ = _tmpl$$5.cloneNode(true),
397
361
  _el$2 = _el$.firstChild,
398
362
  _el$3 = _el$2.firstChild,
399
363
  _el$4 = _el$3.firstChild;
@@ -434,6 +398,69 @@ const ScrollContainer = props => {
434
398
  })();
435
399
  };
436
400
 
401
+ var css_248z$1 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\n width: 50px;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n}\n\n.PianoRollKeys-module_whiteAndNextIsWhite__PN1O8 {\n border-top-width: 0.1px;\n}\n\n.PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q {\n border-bottom-width: 0.1px;\n}\n";
402
+ var styles$1 = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","Key":"PianoRollKeys-module_Key__jybNC","black":"PianoRollKeys-module_black__7rncB","white":"PianoRollKeys-module_white__fR2Lm","whiteAndNextIsWhite":"PianoRollKeys-module_whiteAndNextIsWhite__PN1O8","whiteAndPreviousIsWhite":"PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q"};
403
+ styleInject(css_248z$1);
404
+
405
+ const _tmpl$$4 = /*#__PURE__*/template(`<div></div>`, 2);
406
+ const PianoRollKeys = () => {
407
+ const viewPort = createMemo(() => useViewPortDimension("vertical"));
408
+ return (() => {
409
+ const _el$ = _tmpl$$4.cloneNode(true);
410
+ insert(_el$, createComponent(Index, {
411
+ each: keys,
412
+ children: key => {
413
+ const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
414
+ return createComponent(Show, {
415
+ get when() {
416
+ return virtualDimensions().size > 0;
417
+ },
418
+ get children() {
419
+ const _el$2 = _tmpl$$4.cloneNode(true);
420
+ effect(_p$ => {
421
+ const _v$ = {
422
+ [styles$1["Key"]]: true,
423
+ [styles$1["black"]]: key().isBlack,
424
+ [styles$1["white"]]: !key().isBlack,
425
+ [styles$1["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
426
+ [styles$1["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
427
+ },
428
+ _v$2 = key().name,
429
+ _v$3 = key().number % 12,
430
+ _v$4 = `${virtualDimensions().offset}px`,
431
+ _v$5 = `${virtualDimensions().size}px`;
432
+ _p$._v$ = classList(_el$2, _v$, _p$._v$);
433
+ _v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
434
+ _v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
435
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
436
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
437
+ return _p$;
438
+ }, {
439
+ _v$: undefined,
440
+ _v$2: undefined,
441
+ _v$3: undefined,
442
+ _v$4: undefined,
443
+ _v$5: undefined
444
+ });
445
+ return _el$2;
446
+ }
447
+ });
448
+ }
449
+ }));
450
+ effect(() => className(_el$, styles$1.PianoRollKeys));
451
+ return _el$;
452
+ })();
453
+ };
454
+ const blackKeys = [1, 3, 6, 8, 10];
455
+ const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
456
+ const keys = Array.from({
457
+ length: 128
458
+ }).map((_, index) => ({
459
+ number: index,
460
+ name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
461
+ isBlack: blackKeys.includes(index % 12)
462
+ }));
463
+
437
464
  var css_248z = ".PianoRollGrid-module_PianoRollGrid__tG119 {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Key__VRbiB {\n position: absolute;\n border-style: solid;\n border-color: gray;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Time__jLz3E {\n position: absolute;\n box-sizing: border-box;\n top: 0px;\n height: 100%;\n border-left-style: solid;\n border-left-width: 0.5px;\n}\n";
438
465
  var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
439
466
  styleInject(css_248z);
@@ -550,6 +577,30 @@ const PianoRollGrid = () => {
550
577
  })();
551
578
  };
552
579
 
580
+ const useNotes = () => {
581
+ const [notes, onNotesChange] = createSignal([]);
582
+ const onNoteChange = (index, note) => {
583
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
584
+ };
585
+ const onInsertNote = note => {
586
+ const index = Math.max(notes().findIndex(({
587
+ ticks
588
+ }) => ticks > note.ticks), 0);
589
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
590
+ return index;
591
+ };
592
+ const onRemoveNote = index => {
593
+ onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
594
+ };
595
+ return {
596
+ notes,
597
+ onNotesChange,
598
+ onNoteChange,
599
+ onInsertNote,
600
+ onRemoveNote
601
+ };
602
+ };
603
+
553
604
  const defaultRect = {
554
605
  left: 0,
555
606
  width: 0,
@@ -606,29 +657,198 @@ const VerticalZoomControl = props => {
606
657
  })();
607
658
  };
608
659
 
609
- const _tmpl$$1 = /*#__PURE__*/template(`<input max="500" min="1" step="0.01">`, 1);
610
- const HorizontalZoomControl = props => {
611
- const context = usePianoRollContext();
612
- return (() => {
613
- const _el$ = _tmpl$$1.cloneNode(true);
614
- spread(_el$, mergeProps(props, {
615
- get value() {
616
- return context.zoom;
617
- },
618
- "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
619
- "type": "range",
620
- "style": {
621
- "margin-left": "50px",
622
- "margin-right": "16px"
623
- }
624
- }), false, false);
625
- return _el$;
626
- })();
660
+ const _tmpl$$1 = /*#__PURE__*/template(`<ul></ul>`, 2),
661
+ _tmpl$2 = /*#__PURE__*/template(`<div><ul></ul><div><div></div></div></div>`, 8),
662
+ _tmpl$3 = /*#__PURE__*/template(`<li></li>`, 2);
663
+ const MultiTrackPianoRoll = allProps => {
664
+ const condensed = createMemo(() => !allProps.selectedTrack);
665
+ const [ownProps, restProps] = splitProps(allProps, ["tracks", "selectedTrack"]);
666
+ const [contextProps, divProps] = splitContextProps(mergeProps$1(restProps, {
667
+ notes: [],
668
+ condensed: false
669
+ }));
670
+ const [scrollerRef, setScrollerRef] = createSignal();
671
+ const clientRect = useBoundingClientRect(scrollerRef);
672
+ const zoomFactor = 500;
673
+ const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
674
+ const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
675
+ const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
676
+ const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
677
+ return createComponent(PianoRollContextProvider, {
678
+ get value() {
679
+ return {
680
+ ...contextProps
681
+ };
682
+ },
683
+ get children() {
684
+ return createComponent(ScrollZoomViewPort, {
685
+ dimensions: {
686
+ horizontal: () => ({
687
+ pixelOffset: clientRect().left,
688
+ pixelSize: clientRect().width,
689
+ position: contextProps.position,
690
+ range: contextProps.duration,
691
+ zoom: contextProps.zoom * (zoomFactor / clientRect().width),
692
+ onPositionChange: contextProps.onPositionChange,
693
+ onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
694
+ }),
695
+ vertical: () => ({
696
+ pixelOffset: clientRect().top,
697
+ pixelSize: clientRect().height,
698
+ position: contextProps.verticalPosition,
699
+ range: 128,
700
+ zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
701
+ onPositionChange: contextProps.onVerticalPositionChange,
702
+ onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
703
+ })
704
+ },
705
+ get children() {
706
+ const _el$ = _tmpl$2.cloneNode(true),
707
+ _el$2 = _el$.firstChild,
708
+ _el$3 = _el$2.nextSibling,
709
+ _el$4 = _el$3.firstChild;
710
+ _el$.style.setProperty("display", "flex");
711
+ _el$.style.setProperty("flex", "1");
712
+ _el$.style.setProperty("height", "100%");
713
+ _el$.style.setProperty("flex-direction", "row");
714
+ _el$2.style.setProperty("margin-block-start", "0");
715
+ _el$2.style.setProperty("padding-inline-start", "0");
716
+ _el$2.style.setProperty("width", "150px");
717
+ insert(_el$2, createComponent(Index, {
718
+ get each() {
719
+ return allProps.tracks;
720
+ },
721
+ children: track => (() => {
722
+ const _el$6 = _tmpl$3.cloneNode(true);
723
+ _el$6.$$click = () => {
724
+ if (track() === allProps.selectedTrack) {
725
+ allProps.onSelectedTrackChange(undefined);
726
+ } else {
727
+ allProps.onSelectedTrackChange(track());
728
+ }
729
+ };
730
+ _el$6.style.setProperty("width", "150px");
731
+ _el$6.style.setProperty("height", "30px");
732
+ _el$6.style.setProperty("list-style", "none");
733
+ _el$6.style.setProperty("display", "flex");
734
+ _el$6.style.setProperty("align-items", "center");
735
+ _el$6.style.setProperty("border-top", "1px black solid");
736
+ _el$6.style.setProperty("cursor", "pointer");
737
+ insert(_el$6, () => track().name);
738
+ effect(() => _el$6.style.setProperty("background", track() === allProps.selectedTrack ? "lightgray" : "none"));
739
+ return _el$6;
740
+ })()
741
+ }));
742
+ _el$3.style.setProperty("flex", "1");
743
+ insert(_el$4, createComponent(Show, {
744
+ get when() {
745
+ return !condensed();
746
+ },
747
+ get children() {
748
+ return createComponent(PianoRollKeys, {});
749
+ }
750
+ }), null);
751
+ insert(_el$4, createComponent(ScrollContainer, {
752
+ ref: setScrollerRef,
753
+ get children() {
754
+ const _el$5 = _tmpl$$1.cloneNode(true);
755
+ _el$5.style.setProperty("margin", "0");
756
+ _el$5.style.setProperty("margin-block-start", "0");
757
+ _el$5.style.setProperty("padding-inline-start", "0");
758
+ insert(_el$5, createComponent(Index, {
759
+ get each() {
760
+ return allProps.tracks;
761
+ },
762
+ children: track => {
763
+ const notes = useNotes();
764
+ createEffect(() => {
765
+ notes.onNotesChange(track().notes);
766
+ });
767
+ const [context, setContext] = createStore({
768
+ ...contextProps
769
+ });
770
+ createEffect(() => {
771
+ setContext({
772
+ ...contextProps,
773
+ condensed: condensed(),
774
+ notes: notes.notes(),
775
+ onNoteChange: notes.onNoteChange,
776
+ onInsertNote: notes.onInsertNote,
777
+ onRemoveNote: notes.onRemoveNote
778
+ });
779
+ });
780
+ const verticalViewPort = useViewPortDimension("vertical");
781
+ return createComponent(Show, {
782
+ get when() {
783
+ return condensed() || allProps.selectedTrack === track();
784
+ },
785
+ get children() {
786
+ return createComponent(PianoRollContextProvider, {
787
+ value: context,
788
+ get children() {
789
+ const _el$7 = _tmpl$3.cloneNode(true);
790
+ _el$7.style.setProperty("display", "flex");
791
+ _el$7.style.setProperty("position", "relative");
792
+ _el$7.style.setProperty("list-style", "none");
793
+ _el$7.style.setProperty("flex-direction", "row");
794
+ _el$7.style.setProperty("border-top", "1px black solid");
795
+ insert(_el$7, createComponent(PianoRollNotes, {}), null);
796
+ insert(_el$7, createComponent(PianoRollGrid, {}), null);
797
+ effect(() => _el$7.style.setProperty("height", condensed() ? "30px" : `${verticalViewPort.pixelSize}px`));
798
+ return _el$7;
799
+ }
800
+ });
801
+ }
802
+ });
803
+ }
804
+ }));
805
+ return _el$5;
806
+ }
807
+ }), null);
808
+ insert(_el$4, createComponent(Show, {
809
+ get when() {
810
+ return !condensed();
811
+ },
812
+ get children() {
813
+ return createComponent(VerticalZoomControl, {
814
+ get value() {
815
+ return contextProps.verticalZoom;
816
+ },
817
+ onInput: event => contextProps.onVerticalZoomChange?.(event.currentTarget.valueAsNumber)
818
+ });
819
+ }
820
+ }), null);
821
+ insert(_el$3, createComponent(HorizontalZoomControl, {
822
+ style: {
823
+ width: "100%",
824
+ "margin-left": 0
825
+ },
826
+ get value() {
827
+ return contextProps.zoom;
828
+ },
829
+ onInput: event => contextProps.onZoomChange?.(event.currentTarget.valueAsNumber)
830
+ }), null);
831
+ effect(_p$ => {
832
+ const _v$ = styles$3.PianoRoll,
833
+ _v$2 = styles$3.PianoRollContainer;
834
+ _v$ !== _p$._v$ && className(_el$3, _p$._v$ = _v$);
835
+ _v$2 !== _p$._v$2 && className(_el$4, _p$._v$2 = _v$2);
836
+ return _p$;
837
+ }, {
838
+ _v$: undefined,
839
+ _v$2: undefined
840
+ });
841
+ return _el$;
842
+ }
843
+ });
844
+ }
845
+ });
627
846
  };
847
+ delegateEvents(["click"]);
628
848
 
629
849
  const _tmpl$ = /*#__PURE__*/template(`<div><div></div></div>`, 4);
630
850
  const PianoRoll = allProps => {
631
- const [contextProps, divProps] = splitProps(allProps, ["ppq", "notes", "position", "duration", "zoom", "verticalPosition", "verticalZoom", "onVerticalZoomChange", "onVerticalPositionChange", "onZoomChange", "onPositionChange", "onNoteChange", "gridDivision", "snapToGrid", "onInsertNote", "onRemoveNote"]);
851
+ const [contextProps, divProps] = splitContextProps(allProps);
632
852
  const [scrollerRef, setScrollerRef] = createSignal();
633
853
  const clientRect = useBoundingClientRect(scrollerRef);
634
854
  const zoomFactor = 500;
@@ -699,33 +919,14 @@ const PianoRoll = allProps => {
699
919
 
700
920
  const usePianoRoll = () => {
701
921
  const [ppq, onPpqChange] = createSignal(120);
922
+ const [condensed, onCondensedChange] = createSignal(false);
702
923
  const [position, onPositionChange] = createSignal(0);
703
924
  const [zoom, onZoomChange] = createSignal(10);
704
925
  const [verticalZoom, onVerticalZoomChange] = createSignal(5);
705
926
  const [verticalPosition, onVerticalPositionChange] = createSignal(64);
706
927
  const [gridDivision, onGridDivisionChange] = createSignal(16);
707
928
  const [snapToGrid, onSnapToGridChange] = createSignal(true);
708
- const [notes, onNotesChange] = createSignal([]);
709
929
  const [duration, onDurationChange] = createSignal(0);
710
- const onNoteChange = (index, note) => {
711
- onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
712
- };
713
- const onInsertNote = note => {
714
- const index = Math.max(notes().findIndex(({
715
- ticks
716
- }) => ticks > note.ticks), 0);
717
- onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
718
- return index;
719
- };
720
- const onRemoveNote = index => {
721
- onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
722
- };
723
- createEffect(() => {
724
- const minDuration = Math.max((notes()[notes().length - 1]?.ticks ?? 0) + (notes()[notes().length - 1]?.durationTicks ?? 0), ppq() * 4 * 4);
725
- if (duration() < minDuration) {
726
- onDurationChange(minDuration);
727
- }
728
- });
729
930
  return {
730
931
  ppq,
731
932
  onPpqChange,
@@ -741,15 +942,12 @@ const usePianoRoll = () => {
741
942
  onGridDivisionChange,
742
943
  snapToGrid,
743
944
  onSnapToGridChange,
744
- notes,
745
- onNotesChange,
746
- onNoteChange,
747
- onInsertNote,
748
- onRemoveNote,
945
+ condensed,
946
+ onCondensedChange,
749
947
  duration,
750
948
  onDurationChange
751
949
  };
752
950
  };
753
951
 
754
- export { PianoRoll, usePianoRoll };
952
+ export { MultiTrackPianoRoll, PianoRoll, useNotes, usePianoRoll };
755
953
  //# sourceMappingURL=index.js.map