dope2-webapp/src/LetInBlock.tsx

68 lines
1.8 KiB
TypeScript

import { useContext, useEffect, useRef } from "react";
import { Editor, type EditorState } from "./Editor";
import { EnvContext } from "./EnvContext";
import type { Dynamic, State2Props } from "./util/extra";
import { growEnv } from "dope2";
import { autoInputWidth } from "./util/dom_trickery";
export interface LetInBlockState {
kind: "let";
name: string;
value: EditorState;
inner: EditorState;
resolved: undefined | Dynamic;
}
interface LetInBlockProps extends State2Props<LetInBlockState> {
onResolve: (resolved: EditorState) => void;
}
export function LetInBlock({state, setState, onResolve}: LetInBlockProps) {
const {name, value, inner} = state;
const env = useContext(EnvContext);
const nameRef = useRef<HTMLInputElement>(null);
const onChangeName = (e: React.ChangeEvent<HTMLInputElement>) => {
setState({...state, name: e.target.value});
}
useEffect(() => {
nameRef.current?.focus();
}, []);
useEffect(() => autoInputWidth(nameRef, name), [nameRef, name]);
const innerEnv = (name !== '') && value.resolved
&& growEnv(env)(name)(value.resolved) || env;
return <span className="letIn">
<div className="decl">
let <input
ref={nameRef}
className='editable'
value={name}
placeholder="<variable name>"
onChange={onChangeName}
/> =
<Editor
state={value}
filter={() => true}
onResolve={(state: EditorState) => {} }
onCancel={() => {} }
setState={(state: EditorState) => {} }
/>
&nbsp;in
</div>
<div className="inner">
<EnvContext value={innerEnv}>
<Editor
state={inner}
setState={innerState => setState({...state, inner})}
filter={() => true}
onResolve={onResolve}
onCancel={() => {}}
/>
</EnvContext>
</div>
</span>
}