import { useEffect, useRef } from "react"; import { observer } from "mobx-react-lite"; import { runInAction } from "mobx"; import * as Blockly from "blockly"; import type { ObjectType } from "../../types"; import './ScriptEditorView.scss'; const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = { kind: 'flyoutToolbox', contents: [ { kind: 'block', type: 'controls_if' }, { kind: 'block', type: 'controls_repeat_ext' }, { kind: 'block', type: 'logic_compare' }, { kind: 'block', type: 'math_number' }, { kind: 'block', type: 'math_arithmetic' }, { kind: 'block', type: 'text' }, { kind: 'block', type: 'text_print' }, ], }; type ScriptEditorViewProps = { objectType: ObjectType; } export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorViewProps) { const containerRef = useRef(null); const workspaceRef = useRef(null); const isLoadingRef = useRef(false); useEffect(() => { if (!containerRef.current) return; const workspace = Blockly.inject(containerRef.current, { toolbox: TOOLBOX }); workspaceRef.current = workspace; if (objectType.program) { try { isLoadingRef.current = true; Blockly.serialization.workspaces.load(JSON.parse(objectType.program), workspace); } catch { // corrupt program, start fresh } finally { isLoadingRef.current = false; } } const listener = (e: Blockly.Events.Abstract) => { if (isLoadingRef.current || e.isUiEvent) return; const serialized = JSON.stringify(Blockly.serialization.workspaces.save(workspace)); runInAction(() => { objectType.program = serialized; }); }; workspace.addChangeListener(listener); const resizeObserver = new ResizeObserver(() => Blockly.svgResize(workspace)); resizeObserver.observe(containerRef.current); return () => { resizeObserver.disconnect(); workspace.removeChangeListener(listener); workspace.dispose(); workspaceRef.current = null; }; }, []); useEffect(() => { const workspace = workspaceRef.current; if (!workspace) return; isLoadingRef.current = true; workspace.clear(); if (objectType.program) { try { Blockly.serialization.workspaces.load(JSON.parse(objectType.program), workspace); } catch { // corrupt program, start fresh } } isLoadingRef.current = false; }, [objectType.id]); return
; });