From 2b0d8bc2c6c2fab7f264d70bb2ca379388e8d6ec Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Mon, 12 May 2025 00:02:14 +0200 Subject: [PATCH] a bit more progress --- src/CallBlock.css | 4 ++-- src/CallBlock.tsx | 8 +++++-- src/Editor.tsx | 56 +++++++++++++++++++++++++++++++++++++--------- src/InputBlock.css | 6 ++++- src/InputBlock.tsx | 41 ++++++++++++++++++++++++--------- src/ShowIf.tsx | 9 ++++++++ src/Value.tsx | 8 ++++++- src/index.css | 5 +++++ 8 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 src/ShowIf.tsx diff --git a/src/CallBlock.css b/src/CallBlock.css index c279edc..1611057 100644 --- a/src/CallBlock.css +++ b/src/CallBlock.css @@ -5,7 +5,7 @@ } .functionName { - text-align: center; + /* text-align: center; */ } @@ -20,7 +20,7 @@ } .inputParam { - height: 20px; + /* height: 20px; */ margin-right: 20px; display: inline-block; background-color: rgba(242, 253, 146); diff --git a/src/CallBlock.tsx b/src/CallBlock.tsx index faf4fee..bd164f6 100644 --- a/src/CallBlock.tsx +++ b/src/CallBlock.tsx @@ -22,7 +22,7 @@ interface CallBlockProps extends State2Props { } export function CallBlock({ state: {kind, env, fn, input, resolved, rollback }, setState, onResolve }: CallBlockProps) { - const setResolved = (resolved: Dynamic) => { + const setResolved = (resolved?: Dynamic) => { setState({kind, env, fn, input, resolved, rollback}); } @@ -53,7 +53,11 @@ export function CallBlock({ state: {kind, env, fn, input, resolved, rollback }, makeTheCall(input, fnState); } else { - setFn(fnState); + // setFn(fnState); + setResolved(undefined); + onResolve({ + kind, env, fn: fnState, input, resolved: undefined, rollback + }); } } const onInputResolve = (inputState) => { diff --git a/src/Editor.tsx b/src/Editor.tsx index 8d94fd5..4b4acb3 100644 --- a/src/Editor.tsx +++ b/src/Editor.tsx @@ -7,7 +7,7 @@ import { useEffect, useState } from "react"; import { Type } from "./Type"; import "./Editor.css" -import { focusNextElement } from "./util/dom_trickery"; +import { focusNextElement, focusPrevElement } from "./util/dom_trickery"; interface LetInBlockState { kind: "let"; @@ -49,22 +49,43 @@ interface EditorProps extends State2Props { const dontFilter = () => true; +function getCommands(type) { + const commands = ['u', 't', 'Enter', 'Backspace', 'ArrowLeft', 'Tab']; + if (getSymbol(type) === symbolFunction) { + commands.push('c'); + } + return commands; +} + export function Editor({state, setState, onResolve, onCancel}: EditorProps) { - const [proxyState, setProxyState] = useState<'unresolved'|'command'|'resolved'>('unresolved'); + const [needCommand, setNeedCommand] = useState(false); const onMyResolve = (editorState: EditorState) => { setState(editorState); if (editorState.resolved) { - setProxyState('command'); + setNeedCommand(true); } else { - setProxyState('unresolved'); + // unresolved + setNeedCommand(false); + onResolve(editorState); // pass up the fact that we're unresolved } } // const onMyCancel const onCommand = (e: React.KeyboardEvent) => { const type = getType(state.resolved); - if (e.key === "c" && getSymbol(type) === symbolFunction) { - e.preventDefault(); + const commands = getCommands(type); + if (!commands.includes(e.key)) { + return; + } + e.preventDefault(); + setNeedCommand(false); + // u -> pass Up + if (e.key === "u" || e.key === "Enter" || e.key === "Tab") { + onResolve(state); + return; + } + // c -> Call + if (e.key === "c") { // we become CallBlock setState({ kind: "call", @@ -74,11 +95,24 @@ export function Editor({state, setState, onResolve, onCancel}: EditorProps) { resolved: undefined, rollback: state, }); - setProxyState('resolved'); + return; } - if (e.key === "u" || e.key === "Enter") { - setProxyState('resolved'); - onResolve(state); + // t -> Transform + if (e.key === "t") { + // we become CallBlock + setState({ + kind: "call", + env: state.env, + fn: initialEditorState, + input: state, + resolved: undefined, + rollback: state, + }); + return; + } + if (e.key === "Backspace" || e.key === "ArrowLeft") { + focusPrevElement(); + return; } }; @@ -100,7 +134,7 @@ export function Editor({state, setState, onResolve, onCancel}: EditorProps) { (state.resolved) ?
:: - { (proxyState === 'command') + { (needCommand) ? : <> } diff --git a/src/InputBlock.css b/src/InputBlock.css index 4114912..7115fd4 100644 --- a/src/InputBlock.css +++ b/src/InputBlock.css @@ -14,7 +14,11 @@ font-variation-settings: "wdth" 100; } -.suggestions { +.suggestions { + display: none; +} +.suggestions { + display: block; text-align: left; position: absolute; border: solid 1px dodgerblue; diff --git a/src/InputBlock.tsx b/src/InputBlock.tsx index 62ddd0d..8b9835f 100644 --- a/src/InputBlock.tsx +++ b/src/InputBlock.tsx @@ -8,6 +8,7 @@ import { Type } from "./Type"; import "./InputBlock.css"; import type { Dynamic, State2Props } from "./util/extra"; import type { EditorState } from "./Editor"; +import { ShowIf } from "./ShowIf"; export interface InputBlockState { kind: "input"; @@ -27,9 +28,6 @@ export function InputBlock({ state: {kind, env, text, resolved, rollback}, setSt const ref = useRef(null); useEffect(() => { ref.current?.focus(); - if (ref.current) { - // ref.current.textContent = text; - } }, []); const [i, setI] = useState(0); // selected suggestion @@ -111,6 +109,10 @@ export function InputBlock({ state: {kind, env, text, resolved, rollback}, setSt setRightMostCaretPosition(ref.current); e.preventDefault(); } + else { + onSelectSuggestion(suggestions[i]); + e.preventDefault(); + } } }, ArrowDown: () => { @@ -149,21 +151,38 @@ export function InputBlock({ state: {kind, env, text, resolved, rollback}, setSt return - setHaveFocus(true)} onBlur={() => setHaveFocus(false)}/> + setHaveFocus(true)} onBlur={() => setTimeout(() => setHaveFocus(false), 200)}/> {singleSuggestion} - { - (haveFocus) - ? - : <> - } + + + ; } function Suggestions({ suggestions, onSelect, i, setI }) { + const onMouseEnter = j => () => { + setI(j); + }; + const onMouseDown = j => () => { + setI(j); + onSelect(suggestions[i]); + }; + return (suggestions.length > 0) ? -
- {suggestions.map(([name, dynamic], j) =>
onSelect(suggestions[i])}>{name} ::
)} +
+ {suggestions.map(([name, dynamic], j) => +
+ {name} :: +
) + }
: <>; } \ No newline at end of file diff --git a/src/ShowIf.tsx b/src/ShowIf.tsx new file mode 100644 index 0000000..182f239 --- /dev/null +++ b/src/ShowIf.tsx @@ -0,0 +1,9 @@ +// syntactic sugar +export function ShowIf({cond, children}) { + if (cond) { + return <>{children}; + } + else { + return <>; + } +} \ No newline at end of file diff --git a/src/Value.tsx b/src/Value.tsx index 5ae6b4c..a58aab1 100644 --- a/src/Value.tsx +++ b/src/Value.tsx @@ -1,4 +1,4 @@ -import {getType, getInst, getSymbol, Double, Int, symbolFunction, symbolProduct, symbolSum, symbolDict, symbolSet, symbolList, eqType, match} from "dope2"; +import {getType, getInst, getSymbol, Double, Int, symbolFunction, symbolProduct, symbolSum, symbolDict, symbolSet, symbolList, eqType, match, getLeft, getRight} from "dope2"; import "./Value.css"; @@ -20,6 +20,9 @@ export function Value({dynamic}) { // return ; case symbolSum: return ; + case symbolProduct: + return ; + // case symbolDict: // return ; // case symbolSet: @@ -51,4 +54,7 @@ function ValueSum({val, leftType, rightType}) { return match(val) (l => <>L ) (r => <>R ); +} +function ValueProduct({val, leftType, rightType}) { + return <>(); } \ No newline at end of file diff --git a/src/index.css b/src/index.css index 90d5294..7529615 100644 --- a/src/index.css +++ b/src/index.css @@ -10,4 +10,9 @@ body { font-variation-settings: "wdth" 100; +} + +:focus-within:not(body) { + /* outline: 2px solid black; */ + /* background-color: aqua; */ } \ No newline at end of file