trying to simplify things a bit more... will get rid of 'onResolve'
This commit is contained in:
parent
897824e07d
commit
9c0c2dab90
7 changed files with 85 additions and 45 deletions
15
src/App.tsx
15
src/App.tsx
|
|
@ -50,11 +50,11 @@ export function App() {
|
|||
window.onkeydown = onKeyDown;
|
||||
}, []);
|
||||
|
||||
const commands = [
|
||||
["call" , "[c] call" ],
|
||||
["eval" , "[e] [Tab] [Enter] eval"],
|
||||
["transform", "[t] [.] transform" ],
|
||||
["let" , "[l] [=] let ... in ..." ],
|
||||
const commands: [string, string[], string][] = [
|
||||
["call" , ['c' ], "call" ],
|
||||
["eval" , ['e','Tab','Enter' ], "eval" ],
|
||||
["transform", ['t', '.' ], "transform" ],
|
||||
["let" , ['l', '=', 'a' ], "let ... in ..."],
|
||||
];
|
||||
|
||||
const [highlighted, setHighlighted] = useState(
|
||||
|
|
@ -74,8 +74,9 @@ export function App() {
|
|||
<button disabled={future.length===0} onClick={onRedo}>Redo ({future.length}) [Ctrl+Shift+Z]</button>
|
||||
Commands:
|
||||
{
|
||||
commands.map(([_, descr], i) =>
|
||||
commands.map(([_, keys, descr], i) =>
|
||||
<span key={i} className={'command' + (highlighted[i] ? (' highlighted') : '')}>
|
||||
{keys.map((key, j) => <kbd key={j}>{key}</kbd>)}
|
||||
{descr}
|
||||
</span>)
|
||||
}
|
||||
|
|
@ -91,6 +92,8 @@ export function App() {
|
|||
filter={() => true}
|
||||
/>
|
||||
</CommandContext>
|
||||
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
|
|
|
|||
|
|
@ -73,12 +73,26 @@
|
|||
border-left-color: darkred;
|
||||
}
|
||||
.functionBlock.unifyError > .functionParams > .outputParam > .inputParam > .inputParam {
|
||||
background-color: rgb(95, 4, 4);
|
||||
color: white;
|
||||
/* background-color: rgb(95, 4, 4); */
|
||||
background-color: pink;
|
||||
/* color: white; */
|
||||
color: black;
|
||||
}
|
||||
.functionBlock.unifyError > .functionParams > .outputParam > .inputParam > .inputParam:after {
|
||||
border-left-color: rgb(95, 4, 4);
|
||||
/* border-left-color: rgb(95, 4, 4); */
|
||||
border-left-color: pink;
|
||||
}
|
||||
.functionBlock.unifyError > .functionParams > .outputParam > .inputParam > .inputParam > .inputParam {
|
||||
/* background-color: rgb(95, 4, 4); */
|
||||
background-color: pink;
|
||||
/* color: white; */
|
||||
color: black;
|
||||
}
|
||||
.functionBlock.unifyError > .functionParams > .outputParam > .inputParam > .inputParam > .inputParam:after {
|
||||
/* border-left-color: rgb(95, 4, 4); */
|
||||
border-left-color: pink;
|
||||
}
|
||||
|
||||
|
||||
.functionBlock.unifyError > .functionParams > .outputParam {
|
||||
background-color: pink;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ function headlessCallBlock({state, setState, onResolve}: CallBlockProps) {
|
|||
}
|
||||
};
|
||||
const onFnResolve = (fnState) => {
|
||||
if (input.resolved) {
|
||||
if (fnState && input.resolved) {
|
||||
makeTheCall(input, fnState);
|
||||
}
|
||||
else {
|
||||
|
|
@ -70,7 +70,7 @@ function headlessCallBlock({state, setState, onResolve}: CallBlockProps) {
|
|||
}
|
||||
};
|
||||
const onInputResolve = (inputState) => {
|
||||
if (fn.resolved) {
|
||||
if (fn.resolved && inputState) {
|
||||
makeTheCall(inputState, fn);
|
||||
}
|
||||
else {
|
||||
|
|
@ -90,13 +90,14 @@ function headlessCallBlock({state, setState, onResolve}: CallBlockProps) {
|
|||
}
|
||||
|
||||
export function CallBlock({ state, setState, onResolve }: CallBlockProps) {
|
||||
const {unifyError, setFn, setInput, onFnResolve, onInputResolve, onInputCancel}
|
||||
const {unifyError, setFn, setInput, onFnResolve, onFnCancel, onInputResolve, onInputCancel}
|
||||
= headlessCallBlock({ state, setState, onResolve });
|
||||
return <span className={"functionBlock" + (unifyError ? " unifyError" : "")}>
|
||||
<FunctionHeader
|
||||
fn={state.fn}
|
||||
setFn={setFn}
|
||||
onFnResolve={onFnResolve}
|
||||
onFnCancel={onFnCancel}
|
||||
input={state.input} />
|
||||
<div className="functionParams">
|
||||
<div className="outputParam">
|
||||
|
|
@ -109,26 +110,29 @@ export function CallBlock({ state, setState, onResolve }: CallBlockProps) {
|
|||
|
||||
{/* Output (or Error) */}
|
||||
{state.resolved && <Value dynamic={state.resolved} />}
|
||||
{ state.resolved && <>☑</>}
|
||||
{unifyError && unifyError.toString()}
|
||||
</div>
|
||||
</div>
|
||||
</span>;
|
||||
}
|
||||
|
||||
function FunctionHeader({ fn, setFn, input, onFnResolve }) {
|
||||
function FunctionHeader({ fn, setFn, input, onFnResolve, onFnCancel }) {
|
||||
if (fn.kind === "call") {
|
||||
// if the function we're calling is itself the result of a function call,
|
||||
// then we are anonymous, and so we don't draw a function name
|
||||
|
||||
// recurse:
|
||||
const {
|
||||
onFnResolve : onFnFnResolve
|
||||
onFnResolve : onFnFnResolve,
|
||||
onFnCancel : onFnFnCancel,
|
||||
} = headlessCallBlock({state: fn, setState: setFn, onResolve: onFnResolve});
|
||||
|
||||
return <FunctionHeader
|
||||
fn={fn.fn}
|
||||
setFn={fnFn => setFn({...fn, fn: fnFn})}
|
||||
onFnResolve={onFnFnResolve}
|
||||
onFnCancel={onFnFnCancel}
|
||||
input={fn.input} />;
|
||||
}
|
||||
else {
|
||||
|
|
@ -151,15 +155,15 @@ function FunctionHeader({ fn, setFn, input, onFnResolve }) {
|
|||
}
|
||||
|
||||
// end of recursion - draw function name
|
||||
return <div className="functionName">
|
||||
return <span className="functionName">
|
||||
𝑓𝑛
|
||||
<Editor
|
||||
state={fn}
|
||||
setState={setFn}
|
||||
onResolve={onFnResolve}
|
||||
onCancel={() => {/*todo*/}}
|
||||
onCancel={onFnCancel}
|
||||
filter={filterCompatibleFns} />
|
||||
</div>;
|
||||
</span>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
}
|
||||
|
||||
.commandInput {
|
||||
width: 160px;
|
||||
width: 90px;
|
||||
}
|
||||
|
|
@ -62,6 +62,10 @@ export function Editor({state, setState, onResolve, onCancel, filter}: EditorPro
|
|||
}, [needCommand]);
|
||||
const onMyResolve = (editorState: EditorState) => {
|
||||
setState(editorState);
|
||||
onResolve(editorState);
|
||||
return;
|
||||
|
||||
|
||||
if (editorState.resolved) {
|
||||
setNeedCommand(true);
|
||||
}
|
||||
|
|
@ -74,8 +78,9 @@ export function Editor({state, setState, onResolve, onCancel, filter}: EditorPro
|
|||
|
||||
const globalContext = useContext(CommandContext);
|
||||
const onCommand = (e: React.KeyboardEvent) => {
|
||||
const type = getType(state.resolved);
|
||||
const commands = getCommands(type);
|
||||
// const type = getType(state.resolved);
|
||||
// const commands = getCommands(type);
|
||||
const commands = ['e', 't', 'Enter', 'Backspace', 'ArrowLeft', 'ArrowRight', 'Tab', 'l', '=', '.', 'c'];
|
||||
if (!commands.includes(e.key)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -172,19 +177,16 @@ export function Editor({state, setState, onResolve, onCancel, filter}: EditorPro
|
|||
(state.resolved)
|
||||
? <div className="typeSignature">
|
||||
:: <Type type={getType(state.resolved)} />
|
||||
{ (needCommand)
|
||||
? <input
|
||||
ref={commandInputRef}
|
||||
spellCheck={false}
|
||||
className="editable commandInput"
|
||||
placeholder={`<command: ${getShortCommands(getType(state.resolved))}>`}
|
||||
onKeyDown={onCommand}
|
||||
value={""}
|
||||
onChange={() => {}} /> /* gets rid of React warning */
|
||||
: <></>
|
||||
}
|
||||
</div>
|
||||
: <></>
|
||||
}
|
||||
<input
|
||||
ref={commandInputRef}
|
||||
spellCheck={false}
|
||||
className="editable commandInput"
|
||||
placeholder={`<command>`}
|
||||
onKeyDown={onCommand}
|
||||
value={""}
|
||||
onChange={() => {}} />
|
||||
</>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ export function InputBlock({ state, setState, filter, onResolve, onCancel }: Inp
|
|||
}, [focus]);
|
||||
|
||||
const onSelectSuggestion = ([name, dynamic]) => {
|
||||
console.log('resolving input block', text, '->', name);
|
||||
|
||||
onResolve({
|
||||
kind: "input",
|
||||
text: name,
|
||||
|
|
@ -69,23 +71,10 @@ export function InputBlock({ state, setState, filter, onResolve, onCancel }: Inp
|
|||
});
|
||||
};
|
||||
|
||||
const onInput = e => {
|
||||
setText(e.target.value);
|
||||
if (resolved) {
|
||||
// un-resolve
|
||||
onResolve({
|
||||
kind: "input",
|
||||
text: e.target.value,
|
||||
resolved: undefined,
|
||||
focus: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getCaretPosition = () => {
|
||||
return inputRef.current?.selectionStart || -1;
|
||||
}
|
||||
|
||||
// fired before onInput
|
||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||
const fns = {
|
||||
Tab: () => {
|
||||
|
|
@ -141,6 +130,24 @@ export function InputBlock({ state, setState, filter, onResolve, onCancel }: Inp
|
|||
fns[e.key]?.();
|
||||
};
|
||||
|
||||
const onInput = e => {
|
||||
const found = trie.get(env.name2dyn)(e.target.value);
|
||||
if (found) {
|
||||
console.log('resolving input block..', e.target.value);
|
||||
onResolve({...state, text: e.target.value, resolved: found});
|
||||
}
|
||||
else {
|
||||
if (resolved) {
|
||||
// un-resolve
|
||||
console.log('un-resolving input block..', e.target.value);
|
||||
onResolve({...state, text: e.target.value, resolved: undefined});
|
||||
}
|
||||
else {
|
||||
setText(e.target.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return <span>
|
||||
<span className="">
|
||||
{/* Dropdown suggestions */}
|
||||
|
|
@ -164,6 +171,7 @@ export function InputBlock({ state, setState, filter, onResolve, onCancel }: Inp
|
|||
spellCheck={false}/>
|
||||
{/* Single 'grey' suggestion */}
|
||||
<span className="text-block suggest">{singleSuggestion}</span>
|
||||
{ resolved && <>☑</>}
|
||||
</span>
|
||||
</span>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,3 +9,12 @@ body {
|
|||
font-style: normal;
|
||||
font-variation-settings: "wdth" 100;
|
||||
}
|
||||
|
||||
kbd {
|
||||
border: 2px darkgrey;
|
||||
color: rgb(63, 63, 63);
|
||||
border-style: outset;
|
||||
background-color: whitesmoke;
|
||||
border-radius: 3px;
|
||||
margin: 0 2px 0 2px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue