/* eslint-disable @typescript-eslint/ban-ts-comment */ import styled from "styles" import { useStateDesigner } from "@state-designer/react" import React, { useEffect, useRef } from "react" import { motion } from "framer-motion" import state, { useSelector } from "state" import { CodeFile } from "types" import CodeDocs from "./code-docs" import CodeEditor from "./code-editor" import { generateFromCode } from "lib/code/generate" import * as Panel from "../panel" import { IconButton } from "../shared" import { X, Code, Info, PlayCircle, ChevronUp, ChevronDown, } from "react-feather" const getErrorLineAndColumn = (e: any) => { if ("line" in e) { return { line: Number(e.line), column: e.column } } const result = e.stack.match(/:([0-9]+):([0-9]+)/) if (result) { return { line: Number(result[1]) - 1, column: result[2] } } } export default function CodePanel() { const rContainer = useRef(null) const isReadOnly = useSelector((s) => s.data.isReadOnly) const fileId = useSelector((s) => s.data.currentCodeFileId) const file = useSelector( (s) => s.data.document.code[s.data.currentCodeFileId] ) const isOpen = useSelector((s) => s.data.settings.isCodeOpen) const fontSize = useSelector((s) => s.data.settings.fontSize) const local = useStateDesigner({ data: { code: file.code, error: null as { message: string; line: number; column: number } | null, }, on: { MOUNTED: "setCode", CHANGED_FILE: "loadFile", }, initial: "editingCode", states: { editingCode: { on: { RAN_CODE: ["saveCode", "runCode"], SAVED_CODE: ["saveCode", "runCode"], CHANGED_CODE: { secretlyDo: "setCode" }, CLEARED_ERROR: { if: "hasError", do: "clearError" }, TOGGLED_DOCS: { to: "viewingDocs" }, }, }, viewingDocs: { on: { TOGGLED_DOCS: { to: "editingCode" }, }, }, }, conditions: { hasError(data) { return !!data.error }, }, actions: { loadFile(data, payload: { file: CodeFile }) { data.code = payload.file.code }, setCode(data, payload: { code: string }) { data.code = payload.code }, runCode(data) { let error = null try { const { shapes, controls } = generateFromCode(data.code) state.send("GENERATED_FROM_CODE", { shapes, controls }) } catch (e) { console.error(e) error = { message: e.message, ...getErrorLineAndColumn(e) } } data.error = error }, saveCode(data) { const { code } = data state.send("SAVED_CODE", { code }) }, clearError(data) { data.error = null }, }, }) useEffect(() => { local.send("CHANGED_FILE", { file }) }, [file]) useEffect(() => { local.send("MOUNTED", { code: state.data.document.code[fileId].code }) return () => { state.send("CHANGED_CODE", { fileId, code: local.data.code }) } }, []) const { error } = local.data return ( {isOpen ? ( state.send("TOGGLED_CODE_PANEL_OPEN")}>

Code

state.send("INCREASED_CODE_FONT_SIZE")} > state.send("DECREASED_CODE_FONT_SIZE")} > local.send("TOGGLED_DOCS")}> local.send("SAVED_CODE")} >
local.send("CHANGED_CODE", { code })} onSave={() => local.send("SAVED_CODE")} onKey={() => local.send("CLEARED_ERROR")} /> {error && (error.line ? `(${Number(error.line) - 2}:${error.column}) ${error.message}` : error.message)}
) : ( state.send("TOGGLED_CODE_PANEL_OPEN")}> )}
) } const ButtonsGroup = styled("div", { gridRow: "1", gridColumn: "3", display: "flex", }) const FontSizeButtons = styled("div", { paddingRight: 4, display: "flex", flexDirection: "column", "& > button": { height: "50%", "&:nth-of-type(1)": { alignItems: "flex-end", }, "&:nth-of-type(2)": { alignItems: "flex-start", }, "& svg": { height: 12, }, }, })