solid-pianoroll 0.0.11 → 0.0.13

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,14 +199,13 @@ 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
- _el$.$$mousedown = () => {
204
+ _el$.$$mousedown = event => {
240
205
  console.log("down");
241
206
  setIsMouseDown(true);
207
+ const index = insertOrUpdateNote(event);
208
+ setNewNoteIndex(index);
242
209
  };
243
210
  const _ref$ = props.ref;
244
211
  typeof _ref$ === "function" ? use(_ref$, _el$) : props.ref = _el$;
@@ -247,14 +214,14 @@ const PianoRollNotes = props => {
247
214
  return context.notes;
248
215
  },
249
216
  children: (note, index) => {
250
- const verticalVirtualDimensionss = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
217
+ const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
251
218
  const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
252
219
  return createComponent(Show, {
253
220
  get when() {
254
- return memo(() => !!!!verticalVirtualDimensionss().size)() && !!horizontalDimensions().size;
221
+ return memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
255
222
  },
256
223
  get children() {
257
- const _el$2 = _tmpl$$5.cloneNode(true);
224
+ const _el$2 = _tmpl$$6.cloneNode(true);
258
225
  _el$2.$$mousedown = event => {
259
226
  event.stopPropagation();
260
227
  setIsDragging(true);
@@ -264,7 +231,7 @@ const PianoRollNotes = props => {
264
231
  const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
265
232
  context.onNoteChange?.(index, {
266
233
  ...note(),
267
- ...(noteDragMode() === "move" && {
234
+ ...(noteDragMode() === "move" && !context.condensed && {
268
235
  midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
269
236
  }),
270
237
  ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
@@ -300,38 +267,37 @@ const PianoRollNotes = props => {
300
267
  };
301
268
  effect(_p$ => {
302
269
  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`;
270
+ _v$2 = {
271
+ "background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
272
+ ...(context.condensed ? {
273
+ top: 0,
274
+ height: "100%"
275
+ } : {
276
+ top: `${verticalVirtualDimensions().offset}px`,
277
+ height: `${verticalVirtualDimensions().size}px`
278
+ }),
279
+ left: `${horizontalDimensions().offset}px`,
280
+ width: `${horizontalDimensions().size}px`
281
+ };
308
282
  _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);
283
+ _p$._v$2 = style(_el$2, _v$2, _p$._v$2);
314
284
  return _p$;
315
285
  }, {
316
286
  _v$: undefined,
317
- _v$2: undefined,
318
- _v$3: undefined,
319
- _v$4: undefined,
320
- _v$5: undefined,
321
- _v$6: undefined
287
+ _v$2: undefined
322
288
  });
323
289
  return _el$2;
324
290
  }
325
291
  });
326
292
  }
327
293
  }));
328
- effect(() => className(_el$, styles$1.PianoRollNotes));
294
+ effect(() => className(_el$, styles$2.PianoRollNotes));
329
295
  return _el$;
330
296
  })();
331
297
  };
332
298
  delegateEvents(["mousedown", "mousemove", "mouseup", "dblclick", "click"]);
333
299
 
334
- const _tmpl$$4 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
300
+ const _tmpl$$5 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
335
301
  const ScrollContainer = props => {
336
302
  let scrollContentRef;
337
303
  const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
@@ -393,7 +359,7 @@ const ScrollContainer = props => {
393
359
  });
394
360
  });
395
361
  return (() => {
396
- const _el$ = _tmpl$$4.cloneNode(true),
362
+ const _el$ = _tmpl$$5.cloneNode(true),
397
363
  _el$2 = _el$.firstChild,
398
364
  _el$3 = _el$2.firstChild,
399
365
  _el$4 = _el$3.firstChild;
@@ -434,6 +400,69 @@ const ScrollContainer = props => {
434
400
  })();
435
401
  };
436
402
 
403
+ 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";
404
+ 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"};
405
+ styleInject(css_248z$1);
406
+
407
+ const _tmpl$$4 = /*#__PURE__*/template(`<div></div>`, 2);
408
+ const PianoRollKeys = () => {
409
+ const viewPort = createMemo(() => useViewPortDimension("vertical"));
410
+ return (() => {
411
+ const _el$ = _tmpl$$4.cloneNode(true);
412
+ insert(_el$, createComponent(Index, {
413
+ each: keys,
414
+ children: key => {
415
+ const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
416
+ return createComponent(Show, {
417
+ get when() {
418
+ return virtualDimensions().size > 0;
419
+ },
420
+ get children() {
421
+ const _el$2 = _tmpl$$4.cloneNode(true);
422
+ effect(_p$ => {
423
+ const _v$ = {
424
+ [styles$1["Key"]]: true,
425
+ [styles$1["black"]]: key().isBlack,
426
+ [styles$1["white"]]: !key().isBlack,
427
+ [styles$1["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
428
+ [styles$1["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
429
+ },
430
+ _v$2 = key().name,
431
+ _v$3 = key().number % 12,
432
+ _v$4 = `${virtualDimensions().offset}px`,
433
+ _v$5 = `${virtualDimensions().size}px`;
434
+ _p$._v$ = classList(_el$2, _v$, _p$._v$);
435
+ _v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
436
+ _v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
437
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
438
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
439
+ return _p$;
440
+ }, {
441
+ _v$: undefined,
442
+ _v$2: undefined,
443
+ _v$3: undefined,
444
+ _v$4: undefined,
445
+ _v$5: undefined
446
+ });
447
+ return _el$2;
448
+ }
449
+ });
450
+ }
451
+ }));
452
+ effect(() => className(_el$, styles$1.PianoRollKeys));
453
+ return _el$;
454
+ })();
455
+ };
456
+ const blackKeys = [1, 3, 6, 8, 10];
457
+ const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
458
+ const keys = Array.from({
459
+ length: 128
460
+ }).map((_, index) => ({
461
+ number: index,
462
+ name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
463
+ isBlack: blackKeys.includes(index % 12)
464
+ }));
465
+
437
466
  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
467
  var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
439
468
  styleInject(css_248z);
@@ -550,6 +579,30 @@ const PianoRollGrid = () => {
550
579
  })();
551
580
  };
552
581
 
582
+ const useNotes = () => {
583
+ const [notes, onNotesChange] = createSignal([]);
584
+ const onNoteChange = (index, note) => {
585
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
586
+ };
587
+ const onInsertNote = note => {
588
+ const index = Math.max(notes().findIndex(({
589
+ ticks
590
+ }) => ticks > note.ticks), 0);
591
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
592
+ return index;
593
+ };
594
+ const onRemoveNote = index => {
595
+ onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
596
+ };
597
+ return {
598
+ notes,
599
+ onNotesChange,
600
+ onNoteChange,
601
+ onInsertNote,
602
+ onRemoveNote
603
+ };
604
+ };
605
+
553
606
  const defaultRect = {
554
607
  left: 0,
555
608
  width: 0,
@@ -606,29 +659,198 @@ const VerticalZoomControl = props => {
606
659
  })();
607
660
  };
608
661
 
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
- })();
662
+ const _tmpl$$1 = /*#__PURE__*/template(`<ul></ul>`, 2),
663
+ _tmpl$2 = /*#__PURE__*/template(`<div><ul></ul><div><div></div></div></div>`, 8),
664
+ _tmpl$3 = /*#__PURE__*/template(`<li></li>`, 2);
665
+ const MultiTrackPianoRoll = allProps => {
666
+ const condensed = createMemo(() => !allProps.selectedTrack);
667
+ const [ownProps, restProps] = splitProps(allProps, ["tracks", "selectedTrack"]);
668
+ const [contextProps, divProps] = splitContextProps(mergeProps$1(restProps, {
669
+ notes: [],
670
+ condensed: false
671
+ }));
672
+ const [scrollerRef, setScrollerRef] = createSignal();
673
+ const clientRect = useBoundingClientRect(scrollerRef);
674
+ const zoomFactor = 500;
675
+ const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
676
+ const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
677
+ const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
678
+ const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
679
+ return createComponent(PianoRollContextProvider, {
680
+ get value() {
681
+ return {
682
+ ...contextProps
683
+ };
684
+ },
685
+ get children() {
686
+ return createComponent(ScrollZoomViewPort, {
687
+ dimensions: {
688
+ horizontal: () => ({
689
+ pixelOffset: clientRect().left,
690
+ pixelSize: clientRect().width,
691
+ position: contextProps.position,
692
+ range: contextProps.duration,
693
+ zoom: contextProps.zoom * (zoomFactor / clientRect().width),
694
+ onPositionChange: contextProps.onPositionChange,
695
+ onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
696
+ }),
697
+ vertical: () => ({
698
+ pixelOffset: clientRect().top,
699
+ pixelSize: clientRect().height,
700
+ position: contextProps.verticalPosition,
701
+ range: 128,
702
+ zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
703
+ onPositionChange: contextProps.onVerticalPositionChange,
704
+ onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
705
+ })
706
+ },
707
+ get children() {
708
+ const _el$ = _tmpl$2.cloneNode(true),
709
+ _el$2 = _el$.firstChild,
710
+ _el$3 = _el$2.nextSibling,
711
+ _el$4 = _el$3.firstChild;
712
+ _el$.style.setProperty("display", "flex");
713
+ _el$.style.setProperty("flex", "1");
714
+ _el$.style.setProperty("height", "100%");
715
+ _el$.style.setProperty("flex-direction", "row");
716
+ _el$2.style.setProperty("margin-block-start", "0");
717
+ _el$2.style.setProperty("padding-inline-start", "0");
718
+ _el$2.style.setProperty("width", "150px");
719
+ insert(_el$2, createComponent(Index, {
720
+ get each() {
721
+ return allProps.tracks;
722
+ },
723
+ children: track => (() => {
724
+ const _el$6 = _tmpl$3.cloneNode(true);
725
+ _el$6.$$click = () => {
726
+ if (track() === allProps.selectedTrack) {
727
+ allProps.onSelectedTrackChange(undefined);
728
+ } else {
729
+ allProps.onSelectedTrackChange(track());
730
+ }
731
+ };
732
+ _el$6.style.setProperty("width", "150px");
733
+ _el$6.style.setProperty("height", "30px");
734
+ _el$6.style.setProperty("list-style", "none");
735
+ _el$6.style.setProperty("display", "flex");
736
+ _el$6.style.setProperty("align-items", "center");
737
+ _el$6.style.setProperty("border-top", "1px black solid");
738
+ _el$6.style.setProperty("cursor", "pointer");
739
+ insert(_el$6, () => track().name);
740
+ effect(() => _el$6.style.setProperty("background", track() === allProps.selectedTrack ? "lightgray" : "none"));
741
+ return _el$6;
742
+ })()
743
+ }));
744
+ _el$3.style.setProperty("flex", "1");
745
+ insert(_el$4, createComponent(Show, {
746
+ get when() {
747
+ return !condensed();
748
+ },
749
+ get children() {
750
+ return createComponent(PianoRollKeys, {});
751
+ }
752
+ }), null);
753
+ insert(_el$4, createComponent(ScrollContainer, {
754
+ ref: setScrollerRef,
755
+ get children() {
756
+ const _el$5 = _tmpl$$1.cloneNode(true);
757
+ _el$5.style.setProperty("margin", "0");
758
+ _el$5.style.setProperty("margin-block-start", "0");
759
+ _el$5.style.setProperty("padding-inline-start", "0");
760
+ insert(_el$5, createComponent(Index, {
761
+ get each() {
762
+ return allProps.tracks;
763
+ },
764
+ children: track => {
765
+ const notes = useNotes();
766
+ createEffect(() => {
767
+ notes.onNotesChange(track().notes);
768
+ });
769
+ const [context, setContext] = createStore({
770
+ ...contextProps
771
+ });
772
+ createEffect(() => {
773
+ setContext({
774
+ ...contextProps,
775
+ condensed: condensed(),
776
+ notes: notes.notes(),
777
+ onNoteChange: notes.onNoteChange,
778
+ onInsertNote: notes.onInsertNote,
779
+ onRemoveNote: notes.onRemoveNote
780
+ });
781
+ });
782
+ const verticalViewPort = useViewPortDimension("vertical");
783
+ return createComponent(Show, {
784
+ get when() {
785
+ return condensed() || allProps.selectedTrack === track();
786
+ },
787
+ get children() {
788
+ return createComponent(PianoRollContextProvider, {
789
+ value: context,
790
+ get children() {
791
+ const _el$7 = _tmpl$3.cloneNode(true);
792
+ _el$7.style.setProperty("display", "flex");
793
+ _el$7.style.setProperty("position", "relative");
794
+ _el$7.style.setProperty("list-style", "none");
795
+ _el$7.style.setProperty("flex-direction", "row");
796
+ _el$7.style.setProperty("border-top", "1px black solid");
797
+ insert(_el$7, createComponent(PianoRollNotes, {}), null);
798
+ insert(_el$7, createComponent(PianoRollGrid, {}), null);
799
+ effect(() => _el$7.style.setProperty("height", condensed() ? "30px" : `${verticalViewPort.pixelSize}px`));
800
+ return _el$7;
801
+ }
802
+ });
803
+ }
804
+ });
805
+ }
806
+ }));
807
+ return _el$5;
808
+ }
809
+ }), null);
810
+ insert(_el$4, createComponent(Show, {
811
+ get when() {
812
+ return !condensed();
813
+ },
814
+ get children() {
815
+ return createComponent(VerticalZoomControl, {
816
+ get value() {
817
+ return contextProps.verticalZoom;
818
+ },
819
+ onInput: event => contextProps.onVerticalZoomChange?.(event.currentTarget.valueAsNumber)
820
+ });
821
+ }
822
+ }), null);
823
+ insert(_el$3, createComponent(HorizontalZoomControl, {
824
+ style: {
825
+ width: "100%",
826
+ "margin-left": 0
827
+ },
828
+ get value() {
829
+ return contextProps.zoom;
830
+ },
831
+ onInput: event => contextProps.onZoomChange?.(event.currentTarget.valueAsNumber)
832
+ }), null);
833
+ effect(_p$ => {
834
+ const _v$ = styles$3.PianoRoll,
835
+ _v$2 = styles$3.PianoRollContainer;
836
+ _v$ !== _p$._v$ && className(_el$3, _p$._v$ = _v$);
837
+ _v$2 !== _p$._v$2 && className(_el$4, _p$._v$2 = _v$2);
838
+ return _p$;
839
+ }, {
840
+ _v$: undefined,
841
+ _v$2: undefined
842
+ });
843
+ return _el$;
844
+ }
845
+ });
846
+ }
847
+ });
627
848
  };
849
+ delegateEvents(["click"]);
628
850
 
629
851
  const _tmpl$ = /*#__PURE__*/template(`<div><div></div></div>`, 4);
630
852
  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"]);
853
+ const [contextProps, divProps] = splitContextProps(allProps);
632
854
  const [scrollerRef, setScrollerRef] = createSignal();
633
855
  const clientRect = useBoundingClientRect(scrollerRef);
634
856
  const zoomFactor = 500;
@@ -699,33 +921,14 @@ const PianoRoll = allProps => {
699
921
 
700
922
  const usePianoRoll = () => {
701
923
  const [ppq, onPpqChange] = createSignal(120);
924
+ const [condensed, onCondensedChange] = createSignal(false);
702
925
  const [position, onPositionChange] = createSignal(0);
703
926
  const [zoom, onZoomChange] = createSignal(10);
704
927
  const [verticalZoom, onVerticalZoomChange] = createSignal(5);
705
928
  const [verticalPosition, onVerticalPositionChange] = createSignal(64);
706
- const [gridDivision, onGridDivisionChange] = createSignal(16);
929
+ const [gridDivision, onGridDivisionChange] = createSignal(4);
707
930
  const [snapToGrid, onSnapToGridChange] = createSignal(true);
708
- const [notes, onNotesChange] = createSignal([]);
709
931
  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
932
  return {
730
933
  ppq,
731
934
  onPpqChange,
@@ -741,15 +944,12 @@ const usePianoRoll = () => {
741
944
  onGridDivisionChange,
742
945
  snapToGrid,
743
946
  onSnapToGridChange,
744
- notes,
745
- onNotesChange,
746
- onNoteChange,
747
- onInsertNote,
748
- onRemoveNote,
947
+ condensed,
948
+ onCondensedChange,
749
949
  duration,
750
950
  onDurationChange
751
951
  };
752
952
  };
753
953
 
754
- export { PianoRoll, usePianoRoll };
954
+ export { MultiTrackPianoRoll, PianoRoll, useNotes, usePianoRoll };
755
955
  //# sourceMappingURL=index.js.map