use StrudelMirror directly in MicroRepl

This commit is contained in:
Felix Roos 2023-12-16 13:08:09 +01:00
parent 48e06bd213
commit fc034830d0
5 changed files with 93 additions and 50 deletions

View File

@ -1 +1,2 @@
export * from './repl-component.mjs'; export * from './repl-component.mjs';
export * from './prebake.mjs';

View File

@ -103,8 +103,6 @@ if (typeof HTMLElement !== 'undefined') {
// init settings // init settings
this.editor.updateSettings(this.settings); this.editor.updateSettings(this.settings);
this.editor.setCode(this.code); this.editor.setCode(this.code);
// settingsMap.listen((settings, key) => editor.changeSetting(key, settings[key]));
// onEvent('strudel-toggle-play', () => this.editor.toggle());
} }
// Element functionality written in here // Element functionality written in here
} }

3
pnpm-lock.yaml generated
View File

@ -793,6 +793,9 @@ importers:
react-dom: react-dom:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.2.0(react@18.2.0) version: 18.2.0(react@18.2.0)
react-hook-inview:
specifier: ^4.5.0
version: 4.5.0(react-dom@18.2.0)(react@18.2.0)
rehype-autolink-headings: rehype-autolink-headings:
specifier: ^6.1.1 specifier: ^6.1.1
version: 6.1.1 version: 6.1.1

View File

@ -34,9 +34,9 @@
"@strudel.cycles/transpiler": "workspace:*", "@strudel.cycles/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*", "@strudel.cycles/webaudio": "workspace:*",
"@strudel.cycles/xen": "workspace:*", "@strudel.cycles/xen": "workspace:*",
"@strudel/hydra": "workspace:*",
"@strudel/codemirror": "workspace:*", "@strudel/codemirror": "workspace:*",
"@strudel/desktopbridge": "workspace:*", "@strudel/desktopbridge": "workspace:*",
"@strudel/hydra": "workspace:*",
"@strudel/repl": "workspace:*", "@strudel/repl": "workspace:*",
"@supabase/supabase-js": "^2.21.0", "@supabase/supabase-js": "^2.21.0",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.3",
@ -54,6 +54,7 @@
"nanostores": "^0.8.1", "nanostores": "^0.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-inview": "^4.5.0",
"rehype-autolink-headings": "^6.1.1", "rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1", "rehype-slug": "^5.0.1",
"rehype-urls": "^1.1.1", "rehype-urls": "^1.1.1",

View File

@ -1,32 +1,78 @@
import { useState, useRef, useCallback, useEffect } from 'react'; import { useState, useRef, useCallback, useEffect } from 'react';
import { Icon } from './Icon'; import { Icon } from './Icon';
import '@strudel/repl'; import { getDrawContext, silence } 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';
import { useInView } from 'react-hook-inview';
// import { useInView } from 'react-hook-inview'; const initialSettings = {
keybindings: 'strudelTheme',
isLineNumbersDisplayed: false,
isActiveLineHighlighted: true,
isAutoCompletionEnabled: false,
isPatternHighlightingEnabled: true,
isFlashEnabled: true,
isTooltipEnabled: false,
isLineWrappingEnabled: false,
theme: 'strudelTheme',
fontFamily: 'monospace',
fontSize: 18,
};
export function MicroRepl({ code, hideHeader = false }) { export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchcard, punchcardLabels }) {
/* const [ref, isVisible] = useInView({ const init = useCallback(({ code }) => {
const drawContext = getDrawContext();
const drawTime = [-2, 2];
const editor = new StrudelMirror({
defaultOutput: webaudioOutput,
getTime: () => getAudioContext().currentTime,
transpiler,
root: containerRef.current,
initialCode: '// LOADING',
pattern: silence,
settings: initialSettings,
drawTime,
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 });
});
},
prebake,
onUpdateState: (state) => {
setReplState({ ...state });
},
});
// init settings
editor.updateSettings(initialSettings);
editor.setCode(code);
editorRef.current = editor;
}, []);
const [ref, isVisible] = useInView({
threshold: 0.01, threshold: 0.01,
}); */ onEnter: () => {
if (!editorRef.current) {
init({ code });
}
},
});
const [replState, setReplState] = useState({}); const [replState, setReplState] = useState({});
const { started, isDirty, error } = replState; const { started, isDirty, error } = replState;
const wc = useRef(); const editorRef = useRef();
function togglePlay() { const containerRef = useRef();
if (wc.current) {
wc.current?.editor.toggle(); const [canvasId] = useState(Date.now());
} const drawContext = useCallback(
} punchcard ? (canvasId) => document.querySelector('#' + canvasId)?.getContext('2d') : null,
const listener = useCallback((e) => setReplState({ ...e.detail }), []); [punchcard],
useEffect(() => { );
return () => {
wc.current.removeEventListener('update', listener);
};
}, []);
return ( return (
<div <div className="overflow-hidden rounded-t-md bg-background border border-lineHighlight" ref={ref}>
className="overflow-hidden rounded-t-md bg-background border border-lineHighlight"
//ref={ref}
>
{!hideHeader && ( {!hideHeader && (
<div className="flex justify-between bg-lineHighlight"> <div className="flex justify-between bg-lineHighlight">
<div className="flex"> <div className="flex">
@ -35,7 +81,7 @@ export function MicroRepl({ code, hideHeader = false }) {
'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background', 'cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground bg-lineHighlight hover:bg-background',
started ? 'animate-pulse' : '', started ? 'animate-pulse' : '',
)} )}
onClick={() => togglePlay()} onClick={() => editorRef.current?.toggle()}
> >
<Icon type={started ? 'stop' : 'play'} /> <Icon type={started ? 'stop' : 'play'} />
</button> </button>
@ -44,40 +90,34 @@ export function MicroRepl({ code, hideHeader = false }) {
'w-16 flex items-center justify-center p-1 text-foreground border-lineHighlight bg-lineHighlight', 'w-16 flex items-center justify-center p-1 text-foreground border-lineHighlight bg-lineHighlight',
isDirty ? 'text-foreground hover:bg-background cursor-pointer' : 'opacity-50 cursor-not-allowed', isDirty ? 'text-foreground hover:bg-background cursor-pointer' : 'opacity-50 cursor-not-allowed',
)} )}
onClick={() => activateCode()} onClick={() => editorRef.current?.evaluate()}
> >
<Icon type="refresh" /> <Icon type="refresh" />
</button> </button>
</div> </div>
</div> </div>
)} )}
<div className="overflow-auto relative"> <div className="overflow-auto relative p-1">
<strudel-editor <div ref={containerRef}></div>
is-line-numbers-displayed="0"
is-active-line-highlighted="0"
code={code}
ref={(el) => {
if (wc.current) {
return;
}
wc.current = el;
el.addEventListener('update', listener);
}}
></strudel-editor>
{error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>} {error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>}
</div> </div>
{/* punchcard && ( {/* punchcard && (
<canvas <canvas
id={canvasId} id={canvasId}
className="w-full pointer-events-none" className="w-full pointer-events-none border-t border-lineHighlight"
height={canvasHeight} height={canvasHeight}
ref={(el) => { ref={(el) => {
if (el && el.width !== el.clientWidth) { if (el && el.width !== el.clientWidth) {
el.width = el.clientWidth; el.width = el.clientWidth;
} }
}} //const ratio = el.clientWidth / canvasHeight;
></canvas> //const targetWidth = Math.round(el.width * ratio);
) */} //if (el.width !== targetWidth) {
// el.width = targetWidth;
//}
}}
></canvas>
) */}
{/* !!log.length && ( {/* !!log.length && (
<div className="bg-gray-800 rounded-md p-2"> <div className="bg-gray-800 rounded-md p-2">
{log.map(({ message }, i) => ( {log.map(({ message }, i) => (