refactor: literal handles its typing

This commit is contained in:
cha0s 2021-01-31 14:12:48 -06:00
parent 67a6caa62d
commit fc25cbe3f5
3 changed files with 169 additions and 130 deletions

View File

@ -3,9 +3,6 @@ import {join} from 'path';
import {
PropTypes,
React,
useEffect,
useRef,
useState,
} from '@latus/react';
import {useJsonPatcher} from '@persea/json';
@ -19,91 +16,48 @@ const Invocation = ({
op,
path,
}) => {
const literalTypeRef = useRef();
const [literalType, setLiteralType] = useState(false);
useEffect(() => {
literalTypeRef.current?.focus();
});
const patch = useJsonPatcher();
const argComponent = (arg, i) => {
const argPath = join(path, 'args', i.toString());
if ('undefined' === arg.type) {
const confirmLiteralType = () => {
let value = null;
switch (literalType) {
case 'expressions':
value = {
type: 'expressions',
expressions: [],
};
break;
case 'number': value = 0; break;
case 'string': value = ''; break;
case 'array': value = []; break;
case 'object': value = {}; break;
case 'vector': value = [0, 0]; break;
default:
}
patch({
op: 'replace',
path: argPath,
value: {
type: 'literal',
value,
},
});
setLiteralType(false);
};
return false === literalType
? (
<Key
childrenDescription={{
'...': {label: '', type: 'undefined'},
'[literal]': {label: '', type: 'undefined'},
...context.describe().children,
'[key]': {label: '', type: 'undefined'},
}}
key={path}
onChange={(event, value) => {
if ('[literal]' === value) {
setLiteralType('');
}
else {
patch({
type: 'add',
path: argPath,
value: {
type: 'expression',
ops: [
{
type: 'key',
},
],
return (
<Key
childrenDescription={{
'...': {label: '', type: 'undefined'},
'[literal]': {label: '', type: 'undefined'},
...context.describe().children,
'[key]': {label: '', type: 'undefined'},
}}
key={path}
onChange={(event, value) => {
if ('[literal]' === value) {
patch({
type: 'add',
path: argPath,
value: {
type: 'literal',
},
});
return;
}
patch({
type: 'add',
path: argPath,
value: {
type: 'expression',
ops: [
{
type: 'key',
},
});
onChange(false, value, join(argPath, 'ops/0/key'));
}
}}
path={argPath}
value="..."
/>
)
: (
<input
type="text"
onBlur={confirmLiteralType}
onChange={({target: {value}}) => {
setLiteralType(value);
}}
onKeyPress={(event) => {
if ('Enter' === event.key) {
confirmLiteralType(event);
}
}}
ref={literalTypeRef}
value={literalType}
/>
);
],
},
});
onChange(false, value, join(argPath, 'ops/0/key'));
}}
path={argPath}
value="..."
/>
);
}
const j = description.vararg ? Math.min(description?.args?.length - 1, i) : i;
const options = description?.args?.[j].options;

View File

@ -1,7 +1,13 @@
import {join} from 'path';
import {Context} from '@avocado/behavior';
import {PropTypes, React} from '@latus/react';
import {
PropTypes,
React,
useEffect,
useRef,
useState,
} from '@latus/react';
import {
Number,
Vector,
@ -23,9 +29,42 @@ const Literal = ({
value,
vararg,
}) => {
const literalTypeRef = useRef();
const patch = useJsonPatcher();
const [literalType, setLiteralType] = useState(false);
useEffect(() => {
literalTypeRef.current?.focus();
});
const confirmLiteralType = () => {
if (literalType) {
let value = null;
switch (literalType) {
case 'expressions':
value = {
type: 'expressions',
expressions: [],
};
break;
case 'number': value = 0; break;
case 'string': value = ''; break;
case 'array': value = []; break;
case 'object': value = {}; break;
case 'vector': value = [0, 0]; break;
default:
}
patch({
op: 'replace',
path,
value: {
type: 'literal',
value,
},
});
}
setLiteralType(false);
};
// eslint-disable-next-line react/destructuring-assignment
const contextDescription = context.describe();
const patch = useJsonPatcher();
const valueComponent = (path, type, {value}) => {
switch (type) {
case 'bool': {
@ -97,55 +136,99 @@ const Literal = ({
case 'null':
case 'array':
return null;
default:
return 'undefined' !== typeof value
? valueComponent(path, Context.inferTypeOf(value), {value})
: null;
default: {
const elements = [];
if ('undefined' === type || 'any' === type) {
elements.push(
<select
key={join(path, 'equality')}
onChange={({target: {value}}) => {
if ('≟' === value) {
setLiteralType('');
}
}}
value={false === literalType ? '=' : '≟'}
>
<option>=</option>
<option></option>
</select>,
);
}
if ('undefined' !== typeof value) {
elements.push(
<div className="component" key={join(path, 'component')}>
{valueComponent(path, Context.inferTypeOf(value), {value})}
</div>,
);
}
return <>{elements}</>;
}
}
};
return (
<>
<Key
childrenDescription={{
...(
'undefined' === type
? {'.': {label: '', type: 'undefined'}}
: {}
),
...(
vararg
? {'...': {label: '', type: 'undefined'}}
: {}
),
'[literal]': {label: '', type: value.type},
...contextDescription.children,
'[key]': {label: '', type: value.type},
}}
onChange={(event, value) => {
if ('.' === value || '...' === value) {
patch({
op: 'remove',
path,
});
return;
}
patch({
op: 'replace',
path,
value: {
type: 'expression',
ops: [
{
type: 'key',
key: value,
},
],
},
});
}}
path={path}
value="[literal]"
/>
{
false !== literalType
? (
<input
type="text"
onBlur={confirmLiteralType}
onChange={({target: {value}}) => {
setLiteralType(value);
}}
onKeyPress={(event) => {
if ('Enter' === event.key) {
confirmLiteralType(event);
}
}}
ref={literalTypeRef}
value={literalType}
/>
)
: (
<Key
childrenDescription={{
...(
'undefined' === type
? {'.': {label: '', type: 'undefined'}}
: {}
),
...(
vararg
? {'...': {label: '', type: 'undefined'}}
: {}
),
'[literal]': {label: '', type: value.type},
...contextDescription.children,
'[key]': {label: '', type: value.type},
}}
onChange={(event, value) => {
if ('.' === value || '...' === value) {
patch({
op: 'remove',
path,
});
return;
}
patch({
op: 'replace',
path,
value: {
type: 'expression',
ops: [
{
type: 'key',
key: value,
},
],
},
});
}}
path={path}
value="[literal]"
/>
)
}
<div className="literal">
{
options.length > 0

View File

@ -1,3 +1,5 @@
.literal {
align-items: center;
display: flex;
pointer-events: auto;
}