fix: shove logic out of react

This commit is contained in:
Felix Roos
2026-02-13 10:02:58 +01:00
parent c515ba89a0
commit 27a22d7609
2 changed files with 42 additions and 41 deletions
@@ -1,5 +1,5 @@
import { defaultSettings, settingsMap, useSettings, storePrebakeScript, setSettingsTab } from '../../../settings.mjs';
import { themes, codemirrorSettings } from '@strudel/codemirror';
import { themes } from '@strudel/codemirror';
import { PrebakeCodeMirror } from '../../../repl/prebakeCodeMirror.mjs';
import { confirmAndReloadPage, isUdels } from '../../util.mjs';
import { ButtonGroup } from './Forms.jsx';
@@ -9,8 +9,7 @@ import { confirmDialog } from '../../util.mjs';
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio';
import { ActionButton, SpecialActionButton } from '../button/action-button.jsx';
import { exportScript, ImportPrebakeScriptButton } from './ImportPrebakeScriptButton.jsx';
import { useCallback, useEffect, useRef } from 'react';
import { Code } from '../Code.jsx';
import { useEffect, useRef } from 'react';
function cx(...classes) {
// : Array<string | undefined>
@@ -360,46 +359,25 @@ function MainSettingsContent({ started }) {
function PrebakeSettingsContent() {
const { fontFamily, includePrebakeScriptInShare, prebakeScript } = useSettings();
const init = useCallback(() => {
const settings = codemirrorSettings.get();
// TODO: This instance need to be created at the top level to not create a new instance here
const prebakeCodemirror = new PrebakeCodeMirror(
prebakeScript,
(code) => storePrebakeScript(code),
containerRef,
editorRef,
settings,
);
editorRef.current = prebakeCodemirror;
}, []);
const editorRef = useRef();
const containerRef = useRef();
const handleSaveEvent = async (e) => {
await editorRef.current?.savePrebake();
e?.cancelable && e.preventDefault?.();
};
const handleToggleComment = (e) => {
if (e.detail.view !== editorRef.current.view) {
return; // ignore events from other editors
}
editorRef.current?.toggleComment();
e?.cancelable && e.preventDefault?.();
};
const handleSetCode = (code) => {
editorRef.current?.setCode(code);
};
useEffect(() => {
document.addEventListener('repl-evaluate', handleSaveEvent);
document.addEventListener('repl-toggle-comment', handleToggleComment);
return () => {
document.removeEventListener('prebake-evaluate', handleSaveEvent);
document.removeEventListener('prebake-toggle-comment', handleToggleComment);
editorRef.current?.cleanup();
};
}, []);
});
return (
<div className="flex flex-col h-full text-foreground w-full overflow-auto" style={{ fontFamily }}>
<div className="flex flex-col grow overflow-hidden h-full bg-background">
<Code containerRef={containerRef} editorRef={editorRef} init={init} />
<section
className="pb-0 overflow-auto grow z-10 code-container"
ref={(el) => {
if (editorRef.current) {
return;
}
editorRef.current = new PrebakeCodeMirror(prebakeScript, (code) => storePrebakeScript(code), el);
}}
></section>
</div>
<div className="flex justify-between items-center border-t border-muted px-4 whitespace-nowrap">
<Checkbox
@@ -409,7 +387,7 @@ function PrebakeSettingsContent() {
value={includePrebakeScriptInShare}
/>
<div className="py-2 flex flex-row items-center space-x-3 ">
<ImportPrebakeScriptButton updateEditor={handleSetCode} />
<ImportPrebakeScriptButton updateEditor={(code) => editorRef.current?.editor.setCode(code)} />
<ActionButton onClick={() => exportScript(prebakeScript)}>export</ActionButton>
<ActionButton onClick={() => editorRef.current?.savePrebake()}>save</ActionButton>
</div>
+27 -4
View File
@@ -4,10 +4,11 @@ import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language'
import { Compartment, EditorState, Prec } from '@codemirror/state';
import { drawSelection, EditorView, keymap } from '@codemirror/view';
import { logger } from '@strudel/core';
import { basicSetup, flash, initTheme, extensions, parseBooleans } from '@strudel/codemirror';
import { basicSetup, flash, initTheme, extensions, parseBooleans, codemirrorSettings } from '@strudel/codemirror';
export class PrebakeCodeMirror {
constructor(initialCode, storePrebake, containerRef, editorRef, settings) {
constructor(initialCode, storePrebake, container) {
const settings = codemirrorSettings.get();
this.storePrebake = storePrebake;
const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
const initialSettings = Object.keys(compartments).map((key) =>
@@ -55,12 +56,34 @@ export class PrebakeCodeMirror {
),
],
});
editorRef.current = state;
this.code = initialCode;
this.view = new EditorView({
state,
parent: containerRef.current,
parent: container,
});
const handleSaveEvent = async (e) => {
if (e.detail.view !== this.view) {
return; // ignore events from other editors
}
await this.savePrebake();
e?.cancelable && e.preventDefault?.();
};
const handleToggleComment = (e) => {
if (e.detail.view !== this.view) {
return; // ignore events from other editors
}
this.toggleComment();
e?.cancelable && e.preventDefault?.();
};
document.addEventListener('repl-evaluate', handleSaveEvent);
document.addEventListener('repl-toggle-comment', handleToggleComment);
this.cleanup = () => {
document.removeEventListener('prebake-evaluate', handleSaveEvent);
document.removeEventListener('prebake-toggle-comment', handleToggleComment);
};
}
async savePrebake() {