import h, { classNames } from 'lib/h' import * as soundsLib from 'sounds' import { Sound } from 'sounds' import * as play from 'view/sequencer/play' import * as addRemoveBeat from 'view/sequencer/addRemoveBeat' import * as block from 'view/sequencer/block' export function view() { let index = -1 let columns = [soundsLib.record(sound => sound == Sound.Kick)] let blocksNode = h('div', { className: 'g-Sequencer__Blocks' }, block.column( soundsLib.all().map(sound => ({ checked: sound == Sound.Kick, onCheck: checked => columns[0][sound] = checked })) ) ) let onNextStep = (sounds: soundsLib.Sounds) => { let oldIndex = index let newIndex = (index + 1) % columns.length index = newIndex let oldColumn = blocksNode.childNodes[oldIndex] as HTMLElement if (oldColumn !== undefined) oldColumn.classList.remove('g-Sequencer__Column--Beat') let newColumn = blocksNode.childNodes[newIndex] as HTMLElement // Trigger reflow between removing and adding the classname. // Allow to re-trigger the animation if there is only one column. // See https://css-tricks.com/restart-css-animation/ void newColumn.offsetWidth newColumn.classList.add('g-Sequencer__Column--Beat') soundsLib.all().forEach(sound => { if (columns[newIndex][sound]) soundsLib.play(sounds, sound) }) } let sequencer = h('div', { className: 'g-Sequencer' }, play.view({ onNextStep, onStop: () => { let column = blocksNode.childNodes[index] as HTMLElement column.classList.remove('g-Sequencer__Column--Beat') index = -1 } }), addRemoveBeat.view({ initBeats: 1, onRemove: index => { let lastColumn = blocksNode.childNodes[index] blocksNode.removeChild(lastColumn) columns.pop() }, onAdd: index => { columns.push(soundsLib.record(sound => false)) blocksNode.appendChild(block.column( soundsLib.all().map(sound => ({ checked: false, onCheck: checked => columns[index][sound] = checked })) )) } }), h('div', { className: 'g-Sequencer__Grid' }, h('ol', { className: 'g-Sequencer__Column' }, ...soundsLib.all().map(soundItem) ), blocksNode ) ) return sequencer } function soundItem(sound: Sound): Element { return h('li', { onclick: async () => { let sounds = await soundsLib.load() soundsLib.play(sounds, sound) } }, soundsLib.toString(sound) ) }