import { useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Icon } from './Icon'; import { silence, getPunchcardPainter } from '@strudel.cycles/core'; import { transpiler } from '@strudel.cycles/transpiler'; import { getAudioContext, webaudioOutput } from '@strudel.cycles/webaudio'; import { StrudelMirror } from '@strudel/codemirror'; import { prebake } from '@strudel/repl'; export function MicroRepl({ code, hideHeader = false, canvasHeight = 100, onTrigger, onPaint, punchcard, punchcardLabels = true, }) { const id = useMemo(() => s4(), []); const canvasId = useMemo(() => `canvas-${id}`, [id]); const shouldDraw = !!punchcard; const init = useCallback(({ code, shouldDraw }) => { const drawTime = [0, 4]; const drawContext = shouldDraw ? document.querySelector('#' + canvasId)?.getContext('2d') : null; let onDraw; if (shouldDraw) { onDraw = (haps, time, frame, painters) => { painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2); painters?.forEach((painter) => { // ctx time haps drawTime paintOptions painter(drawContext, time, haps, drawTime, { clear: false }); }); }; } const editor = new StrudelMirror({ id, defaultOutput: webaudioOutput, getTime: () => getAudioContext().currentTime, transpiler, autodraw: !!shouldDraw, root: containerRef.current, initialCode: '// LOADING', pattern: silence, drawTime, onDraw, editPattern: (pat, id) => { if (onTrigger) { pat = pat.onTrigger(onTrigger, false); } if (onPaint) { editor.painters.push(onPaint); } else if (punchcard) { editor.painters.push(getPunchcardPainter({ labels: !!punchcardLabels })); } return pat; }, prebake, onUpdateState: (state) => { setReplState({ ...state }); }, }); // init settings editor.setCode(code); editorRef.current = editor; }, []); const [replState, setReplState] = useState({}); const { started, isDirty, error } = replState; const editorRef = useRef(); const containerRef = useRef(); const [client, setClient] = useState(false); useEffect(() => { setClient(true); if (!editorRef.current) { setTimeout(() => { init({ code, shouldDraw }); }); } return () => { editor.clear(); }; }, []); if (!client) { return
{code}
; } return (
{!hideHeader && (
)}
{error &&
{error.message}
}
{shouldDraw && ( { if (el && el.width !== el.clientWidth) { el.width = el.clientWidth; } }} > )} {/* !!log.length && (
{log.map(({ message }, i) => (
{message}
))}
) */}
); } function cx(...classes) { // : Array return classes.filter(Boolean).join(' '); } function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); }