chore: ded
This commit is contained in:
parent
250f057d0c
commit
b8d775eaa6
|
@ -1,131 +0,0 @@
|
||||||
import './condition.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {useJsonPatcher} from '@avocado/resource-persea';
|
|
||||||
import {
|
|
||||||
classnames,
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import Variant from './help/variant';
|
|
||||||
|
|
||||||
const Condition = ({context, path, value}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const operands = value.operands.map((operand, i) => {
|
|
||||||
const operandKey = join(path, 'operands', i.toString());
|
|
||||||
return (
|
|
||||||
<Variant
|
|
||||||
context={context}
|
|
||||||
key={operandKey}
|
|
||||||
onChange={(event, value, localPath) => {
|
|
||||||
patch({
|
|
||||||
path: localPath,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
path={operandKey}
|
|
||||||
type="any"
|
|
||||||
value={operand}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const operator = (
|
|
||||||
<select
|
|
||||||
key={join(path, 'operator')}
|
|
||||||
onChange={(event) => {
|
|
||||||
patch({
|
|
||||||
path: join(path, 'operator'),
|
|
||||||
value: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
value={value.operator}
|
|
||||||
>
|
|
||||||
<option value="is">is</option>
|
|
||||||
<option value="isnt">isnt</option>
|
|
||||||
<option value=">">></option>
|
|
||||||
<option value=">=">>=</option>
|
|
||||||
<option value="<"><</option>
|
|
||||||
<option value="<="><=</option>
|
|
||||||
<option value="or">or</option>
|
|
||||||
<option value="and">and</option>
|
|
||||||
<option value="contains">contains</option>
|
|
||||||
</select>
|
|
||||||
);
|
|
||||||
const renderables = [];
|
|
||||||
switch (value.operator) {
|
|
||||||
case 'or':
|
|
||||||
case 'and':
|
|
||||||
renderables.push(operator);
|
|
||||||
renderables.push(...operands.map((operand, i) => (
|
|
||||||
<div className="operand__wrapper">
|
|
||||||
{operand}
|
|
||||||
<button
|
|
||||||
className="condition__remove-operand"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: join(path, 'operands', i.toString()),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
x
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)));
|
|
||||||
renderables.push(
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, 'operands/-'),
|
|
||||||
value: {
|
|
||||||
type: 'literal',
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Add operand
|
|
||||||
</button>,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
renderables.push(operands.shift());
|
|
||||||
renderables.push(operator);
|
|
||||||
renderables.push(...operands);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
'condition',
|
|
||||||
{'condition--vertical': -1 !== ['and', 'or'].indexOf(value.operator)},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{renderables}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Condition.defaultProps = {};
|
|
||||||
|
|
||||||
Condition.displayName = 'Condition';
|
|
||||||
|
|
||||||
Condition.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
get: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
operator: PropTypes.string,
|
|
||||||
operands: PropTypes.arrayOf(
|
|
||||||
PropTypes.any,
|
|
||||||
),
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Condition;
|
|
|
@ -1,49 +0,0 @@
|
||||||
.condition {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
&.condition--vertical {
|
|
||||||
align-items: flex-start;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition--vertical {
|
|
||||||
|
|
||||||
> select {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
> .expression,
|
|
||||||
> .key,
|
|
||||||
> .literal {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
||||||
> .expression {
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition .condition--vertical {
|
|
||||||
padding-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.operand__wrapper {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
padding-left: 0.5em;
|
|
||||||
width: 100%;
|
|
||||||
&:nth-of-type(2n+1) {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
|
||||||
> button {
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 1em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,367 +0,0 @@
|
||||||
import './expression.scss';
|
|
||||||
|
|
||||||
import {join, relative} from 'path';
|
|
||||||
|
|
||||||
import {useJsonPatcher} from '@avocado/resource-persea';
|
|
||||||
import {
|
|
||||||
classnames,
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import compile from '../../compilers/compile';
|
|
||||||
import {isInvocation, isKey} from '../../testers';
|
|
||||||
import Invocation from './expression/invocation';
|
|
||||||
import Key from './expression/key';
|
|
||||||
import Variant from './help/variant';
|
|
||||||
|
|
||||||
const Expression = ({
|
|
||||||
context,
|
|
||||||
path,
|
|
||||||
type,
|
|
||||||
value,
|
|
||||||
vararg,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const types = latus.get('%behavior-types');
|
|
||||||
let i = 0;
|
|
||||||
const {ops, value: expressionValue} = value;
|
|
||||||
const Renderables = [];
|
|
||||||
let opsCount = 0;
|
|
||||||
// eslint-disable-next-line react/destructuring-assignment
|
|
||||||
let description = context.describeChildren();
|
|
||||||
const onChange = (event, value, localPath) => {
|
|
||||||
const patches = [];
|
|
||||||
const j = parseInt(relative(path, localPath).split('/')[1], 10);
|
|
||||||
if (j < ops.length - 1) {
|
|
||||||
for (let k = j + 1; k < ops.length; ++k) {
|
|
||||||
patches.unshift({
|
|
||||||
op: 'remove',
|
|
||||||
path: join(path, 'ops', k.toString()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event && j === ops.length) {
|
|
||||||
patches.push({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, 'ops', j.toString()),
|
|
||||||
value: {
|
|
||||||
type: 'key',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
patches.push({
|
|
||||||
path: localPath,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
patch(patches);
|
|
||||||
};
|
|
||||||
do {
|
|
||||||
const op = ops[i];
|
|
||||||
const opPath = join(path, 'ops', opsCount.toString());
|
|
||||||
const nextOp = i === ops.length - 1 ? undefined : ops[i + 1];
|
|
||||||
if (isKey(op)) {
|
|
||||||
const isFirst = 0 === i;
|
|
||||||
const isLast = i === ops.length - 1 ? true : isInvocation(ops[i + 1]);
|
|
||||||
Renderables.push(
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
...(
|
|
||||||
isFirst && 'void' !== type
|
|
||||||
? {
|
|
||||||
'[literal]': {label: '', type},
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...(
|
|
||||||
vararg && isFirst
|
|
||||||
? {'...': {label: '', type: description.type}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...(
|
|
||||||
isLast && !isFirst
|
|
||||||
? {'.': {label: '', type: description.type}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...description.children,
|
|
||||||
...(
|
|
||||||
isFirst
|
|
||||||
? {
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
'[invoke]': {label: '', type: 'undefined'},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
key={opPath}
|
|
||||||
onChange={((i) => (event, value, localPath) => {
|
|
||||||
if ('.' === value || '...' === value) {
|
|
||||||
const parts = localPath.split('/');
|
|
||||||
parts.pop();
|
|
||||||
parts.pop();
|
|
||||||
if ('...' === value) {
|
|
||||||
parts.pop();
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: parts.join('/'),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const patches = [];
|
|
||||||
for (let j = i; j < ops.length; ++j) {
|
|
||||||
patches.unshift(
|
|
||||||
{
|
|
||||||
op: 'remove',
|
|
||||||
path: join(parts.join('/'), j.toString()),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
patch(patches);
|
|
||||||
}
|
|
||||||
else if ('[literal]' === value) {
|
|
||||||
patch({
|
|
||||||
op: 'replace',
|
|
||||||
path,
|
|
||||||
value: {
|
|
||||||
type: 'literal',
|
|
||||||
value: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
onChange(event, value, localPath);
|
|
||||||
}
|
|
||||||
})(i)}
|
|
||||||
path={opPath}
|
|
||||||
value={op.key}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
opsCount += 1;
|
|
||||||
}
|
|
||||||
if (isInvocation(op)) {
|
|
||||||
const R = Renderables.pop();
|
|
||||||
Renderables.push(
|
|
||||||
<div
|
|
||||||
className="expression__invocation-toggle-wrapper"
|
|
||||||
key={`${opPath}-toggle-from`}
|
|
||||||
>
|
|
||||||
{R}
|
|
||||||
<button
|
|
||||||
className="expression__invocation-toggle from"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: opPath,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
→
|
|
||||||
</button>
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
Renderables.push(
|
|
||||||
<Invocation
|
|
||||||
context={context}
|
|
||||||
description={description}
|
|
||||||
Expression={Expression}
|
|
||||||
key={opPath}
|
|
||||||
onChange={onChange}
|
|
||||||
op={op}
|
|
||||||
path={opPath}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
opsCount += 1;
|
|
||||||
}
|
|
||||||
if (isKey(op)) {
|
|
||||||
const current = compile({type: 'expression', ops: ops.slice(0, i + 1)}, latus)(context);
|
|
||||||
description = description.children?.[op.key] || {type: 'undefined'};
|
|
||||||
const {args, type} = description;
|
|
||||||
if ('void' !== type) {
|
|
||||||
description = {
|
|
||||||
...context.constructor.descriptionFor(
|
|
||||||
type,
|
|
||||||
current,
|
|
||||||
latus,
|
|
||||||
),
|
|
||||||
...(args ? {args} : {}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (description.args && (!nextOp || !isInvocation(nextOp))) {
|
|
||||||
const R = Renderables.pop();
|
|
||||||
Renderables.push(
|
|
||||||
<div
|
|
||||||
className="expression__invocation-toggle-wrapper"
|
|
||||||
key={`${opPath}-toggle-to`}
|
|
||||||
>
|
|
||||||
{R}
|
|
||||||
<button
|
|
||||||
className="expression__invocation-toggle to"
|
|
||||||
onClick={((description, opPath) => () => {
|
|
||||||
const parts = opPath.split('/');
|
|
||||||
parts.push(parseInt(parts.pop(), 10) + 1);
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'invoke',
|
|
||||||
args: description.vararg
|
|
||||||
? []
|
|
||||||
: description.args.map(
|
|
||||||
(arg) => ({
|
|
||||||
...(false === arg.compile ? {compile: false} : {}),
|
|
||||||
...(
|
|
||||||
(types[arg.type] || types.undefined).create(
|
|
||||||
(arg.options?.length || 0) > 0
|
|
||||||
? arg.options[0].value
|
|
||||||
: undefined,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})(description, opPath)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
→
|
|
||||||
</button>
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isInvocation(op)) {
|
|
||||||
if ('void' !== description.type) {
|
|
||||||
description = context.constructor.descriptionFor(
|
|
||||||
description.type,
|
|
||||||
undefined,
|
|
||||||
latus,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (i++ < ops.length - 1);
|
|
||||||
if (
|
|
||||||
description.children
|
|
||||||
|| 'undefined' === description.type
|
|
||||||
) {
|
|
||||||
const opPath = join(path, 'ops', opsCount.toString());
|
|
||||||
Renderables.push(
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
'.': {label: '', type: description.type},
|
|
||||||
...(description.children || {}),
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
'[invoke]': {label: '', type: 'undefined'},
|
|
||||||
}}
|
|
||||||
key={opPath}
|
|
||||||
onChange={onChange}
|
|
||||||
path={opPath}
|
|
||||||
value="."
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
opsCount += 1;
|
|
||||||
}
|
|
||||||
const [lastOp] = ops.slice(-1);
|
|
||||||
if (
|
|
||||||
'void' === type
|
|
||||||
&& isKey(lastOp)
|
|
||||||
) {
|
|
||||||
const opPath = join(path, 'value');
|
|
||||||
Renderables.push(
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
'≡': {label: '', type: description.type},
|
|
||||||
'≔': {label: '', type: 'void'},
|
|
||||||
}}
|
|
||||||
key={opPath}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
if ('≡' === value) {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: opPath,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
patch({
|
|
||||||
path: opPath,
|
|
||||||
value: (types[description.type] || types.undefined).create(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
path={opPath}
|
|
||||||
value={expressionValue ? '≔' : '≡'}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
if (expressionValue) {
|
|
||||||
const expressionType = isKey(lastOp) && description.args
|
|
||||||
? 'function'
|
|
||||||
: description.type;
|
|
||||||
Renderables.push(
|
|
||||||
<Variant
|
|
||||||
context={context}
|
|
||||||
onChange={(event, value, localPath) => {
|
|
||||||
patch({
|
|
||||||
path: localPath,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
key={join(opPath, 'expression')}
|
|
||||||
path={opPath}
|
|
||||||
type={expressionType}
|
|
||||||
value={expressionValue}
|
|
||||||
vararg={vararg}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let realType = description.type;
|
|
||||||
if (isKey(lastOp) && description.args) {
|
|
||||||
realType = 'function';
|
|
||||||
}
|
|
||||||
if (expressionValue) {
|
|
||||||
realType = 'undefined' === description.type ? 'undefined' : 'void';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
'expression',
|
|
||||||
{'wrong-type': 'any' !== type && 'undefined' !== type && realType !== type},
|
|
||||||
{'undefined-type': 'undefined' === realType},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{Renderables}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Expression.defaultProps = {
|
|
||||||
vararg: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Expression.displayName = 'Expression';
|
|
||||||
|
|
||||||
Expression.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
constructor: PropTypes.func,
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
get: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
ops: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
key: PropTypes.string,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// eslint-disable-next-line react/forbid-prop-types
|
|
||||||
value: PropTypes.any,
|
|
||||||
}).isRequired,
|
|
||||||
vararg: PropTypes.bool,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Expression;
|
|
|
@ -1,37 +0,0 @@
|
||||||
.expression {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
button, .button {
|
|
||||||
color: #00bdd6;
|
|
||||||
}
|
|
||||||
&.wrong-type {
|
|
||||||
background-color: rgb(180, 0, 0);
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
&.undefined-type {
|
|
||||||
background-color: rgb(180, 180, 0);
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
> .expression {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.expression__invocation-toggle-wrapper {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expression__invocation-toggle {
|
|
||||||
background: #222222;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.25em;
|
|
||||||
pointer-events: auto;
|
|
||||||
&:hover {
|
|
||||||
background: #333333;
|
|
||||||
}
|
|
||||||
&.to {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
import './invocation.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {useJsonPatcher} from '@avocado/resource-persea';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import Variant from '../help/variant';
|
|
||||||
import Key from './key';
|
|
||||||
|
|
||||||
const Invocation = ({
|
|
||||||
context,
|
|
||||||
description,
|
|
||||||
onChange,
|
|
||||||
op,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const argComponent = (arg, i) => {
|
|
||||||
const argPath = join(path, 'args', i.toString());
|
|
||||||
if ('undefined' === arg.type) {
|
|
||||||
return (
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
'...': {label: '', type: 'undefined'},
|
|
||||||
'[literal]': {label: '', type: 'undefined'},
|
|
||||||
...context.describeChildren().children,
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
}}
|
|
||||||
key={path}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
if ('[literal]' === value) {
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: argPath,
|
|
||||||
value: {
|
|
||||||
type: 'literal',
|
|
||||||
value: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: argPath,
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onChange(false, value, join(argPath, 'ops/0/key'));
|
|
||||||
}}
|
|
||||||
path={argPath}
|
|
||||||
value="..."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let darg;
|
|
||||||
if ('function' === typeof description?.args) {
|
|
||||||
darg = description?.args(i);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const j = description.vararg ? i % description?.args?.length : i;
|
|
||||||
darg = description?.args?.[j];
|
|
||||||
}
|
|
||||||
const type = darg?.type || 'undefined';
|
|
||||||
return (
|
|
||||||
<Variant
|
|
||||||
context={context}
|
|
||||||
onChange={onChange}
|
|
||||||
options={darg?.options}
|
|
||||||
path={argPath}
|
|
||||||
type={type}
|
|
||||||
value={arg}
|
|
||||||
vararg={
|
|
||||||
'undefined' === type
|
|
||||||
|| description.vararg
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const isVarArg = 'undefined' === description.type || description.vararg;
|
|
||||||
const args = op.args.concat();
|
|
||||||
if (isVarArg) {
|
|
||||||
args.push({type: 'undefined'});
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="invocation">
|
|
||||||
{args.length > 0 && (
|
|
||||||
<div className="invocation__args-wrapper">
|
|
||||||
{
|
|
||||||
args.map((arg, i) => (
|
|
||||||
<div
|
|
||||||
key={join(path, 'args', i.toString())}
|
|
||||||
className="invocation__arg"
|
|
||||||
>
|
|
||||||
{argComponent(arg, i)}
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Invocation.displayName = 'Invocation';
|
|
||||||
|
|
||||||
Invocation.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
description: PropTypes.shape({
|
|
||||||
args: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
options: PropTypes.arrayOf(PropTypes.any),
|
|
||||||
type: PropTypes.string,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
type: PropTypes.string,
|
|
||||||
vararg: PropTypes.bool,
|
|
||||||
}).isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
op: PropTypes.shape({
|
|
||||||
args: PropTypes.arrayOf(PropTypes.any),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Invocation;
|
|
|
@ -1,53 +0,0 @@
|
||||||
.invocation {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
margin-left: 0.25em;
|
|
||||||
> .expression {
|
|
||||||
margin: 0 0.5em;
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
color: #00bdd6;
|
|
||||||
content: ')';
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
&:before {
|
|
||||||
color: #00bdd6;
|
|
||||||
content: '(';
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.invocation__args-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invocation__arg {
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
display: flex;
|
|
||||||
padding: 0.5em;
|
|
||||||
position: relative;
|
|
||||||
&:nth-of-type(2n+1) {
|
|
||||||
background-color: rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
color: #00bdd6;
|
|
||||||
content: ',';
|
|
||||||
font-size: 1.5em;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
&:last-of-type {
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.invocation__arg-sep {
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
import './key.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {useJsonPatcher} from '@avocado/resource-persea';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import natsort from 'natsort';
|
|
||||||
|
|
||||||
const sorter = natsort({insensitive: true});
|
|
||||||
|
|
||||||
const Key = ({
|
|
||||||
childrenDescription,
|
|
||||||
onChange,
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const customizeRef = useRef();
|
|
||||||
const [customization, setCustomization] = useState(false);
|
|
||||||
const [customizationPath, setCustomizationPath] = useState('/');
|
|
||||||
useEffect(() => {
|
|
||||||
customizeRef.current?.focus();
|
|
||||||
});
|
|
||||||
const optionKeys = Object.entries(childrenDescription).map(([key]) => key);
|
|
||||||
if (-1 === optionKeys.indexOf(value)) {
|
|
||||||
optionKeys.unshift(value);
|
|
||||||
}
|
|
||||||
const options = optionKeys
|
|
||||||
.sort(sorter)
|
|
||||||
.map((key) => (
|
|
||||||
<option key={key} value={key}>{key}</option>
|
|
||||||
));
|
|
||||||
const confirmCustomization = () => {
|
|
||||||
const parts = customizationPath.split('/');
|
|
||||||
parts.pop();
|
|
||||||
setCustomization(false);
|
|
||||||
setCustomizationPath('/');
|
|
||||||
if ('value' === parts[parts.length - 1]) {
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: customization,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'key',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onChange(false, customization, join(parts.join('/'), 'key'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="key"
|
|
||||||
>
|
|
||||||
{
|
|
||||||
false === customization
|
|
||||||
? (
|
|
||||||
<select
|
|
||||||
className="key__selector"
|
|
||||||
onChange={(event) => {
|
|
||||||
const localPath = join(path, 'key');
|
|
||||||
const {target: {value}} = event;
|
|
||||||
switch (value) {
|
|
||||||
case '[key]': {
|
|
||||||
setCustomization('');
|
|
||||||
setCustomizationPath(localPath);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '[invoke]': {
|
|
||||||
const parts = localPath.split('/');
|
|
||||||
parts.pop();
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'invoke',
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
onChange(event, value, localPath);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={value}
|
|
||||||
>
|
|
||||||
{options}
|
|
||||||
</select>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onBlur={confirmCustomization}
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setCustomization(value);
|
|
||||||
}}
|
|
||||||
onKeyPress={(event) => {
|
|
||||||
if ('Enter' === event.key) {
|
|
||||||
confirmCustomization(event);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
ref={customizeRef}
|
|
||||||
value={customization}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Key.displayName = 'Key';
|
|
||||||
|
|
||||||
Key.propTypes = {
|
|
||||||
childrenDescription: PropTypes.shape({}).isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Key;
|
|
|
@ -1,3 +0,0 @@
|
||||||
.key__selector {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
|
@ -1,149 +0,0 @@
|
||||||
import './expressions.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {useJsonPatcher} from '@avocado/resource-persea';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import compile from '../../compilers/compile';
|
|
||||||
import Expression from './expression';
|
|
||||||
|
|
||||||
const Expressions = ({
|
|
||||||
context,
|
|
||||||
value: {expressions},
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const createExpressionSwapper = (l, r) => () => {
|
|
||||||
const le = expressions[l];
|
|
||||||
const re = expressions[r];
|
|
||||||
patch([
|
|
||||||
{
|
|
||||||
path: join(path, 'expressions', l.toString()),
|
|
||||||
value: re,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: join(path, 'expressions', r.toString()),
|
|
||||||
value: le,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
let currentContext = context;
|
|
||||||
return (
|
|
||||||
<div className="expressions">
|
|
||||||
{
|
|
||||||
expressions.map((expression, i) => {
|
|
||||||
currentContext = currentContext.clone();
|
|
||||||
const {ops} = expression;
|
|
||||||
if (3 === ops.length && 'context' === ops[0].key && 'add' === ops[1].key) {
|
|
||||||
const [key, value] = ops[2].args;
|
|
||||||
if ('undefined' !== key.type && 'undefined' !== value.type) {
|
|
||||||
currentContext.add(
|
|
||||||
compile(key, latus)(currentContext),
|
|
||||||
compile(value, latus)(currentContext),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const expressionPath = join(path, 'expressions', i.toString());
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="expressions__expression-wrapper"
|
|
||||||
key={expressionPath}
|
|
||||||
>
|
|
||||||
<div className="expressions__move-expression">
|
|
||||||
{i > 0 && (
|
|
||||||
<button
|
|
||||||
className="expressions__move-expression-up"
|
|
||||||
onClick={createExpressionSwapper(i, i - 1)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
🠹
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<div className="expressions__move-expression-spacer" />
|
|
||||||
{i < expressions.length - 1 && (
|
|
||||||
<button
|
|
||||||
className="expressions__move-expression-down"
|
|
||||||
onClick={createExpressionSwapper(i, i + 1)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
🠻
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Expression
|
|
||||||
context={currentContext}
|
|
||||||
value={expression}
|
|
||||||
path={expressionPath}
|
|
||||||
type="void"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className="expressions__remove-expression"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: expressionPath,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
x
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
<div className="expressions__expression-wrapper">
|
|
||||||
<button
|
|
||||||
className="expressions__add-expression"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, 'expressions/-'),
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: 'Flow',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: 'nop',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'invoke',
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Add expression
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Expressions.displayName = 'Expressions';
|
|
||||||
|
|
||||||
Expressions.propTypes = {
|
|
||||||
context: PropTypes.shape({}).isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
type: PropTypes.string,
|
|
||||||
expressions: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({}),
|
|
||||||
),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Expressions;
|
|
|
@ -1,54 +0,0 @@
|
||||||
.expressions__expression-wrapper {
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
|
||||||
display: flex;
|
|
||||||
&:nth-of-type(2n+1) {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
|
||||||
button, .button {
|
|
||||||
color: #00bdd6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__move-expression {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__move-expression-up,
|
|
||||||
.expressions__move-expression-down {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 0.5em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__move-expression-up
|
|
||||||
+ .expressions__move-expression-spacer
|
|
||||||
+ .expressions__move-expression-down {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__expression-wrapper > .expression {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 0.5em;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__remove-expression {
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 1em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__add-expression {
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
const Variant = (props) => {
|
|
||||||
const {value} = props;
|
|
||||||
const {type} = value;
|
|
||||||
const latus = useLatus();
|
|
||||||
const Component = latus.get('%behavior-components')[type];
|
|
||||||
return (
|
|
||||||
<Component
|
|
||||||
value={value}
|
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Variant.displayName = 'Variant';
|
|
||||||
|
|
||||||
Variant.propTypes = {
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
type: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Variant;
|
|
|
@ -1,263 +0,0 @@
|
||||||
import './literal.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {useJsonPatcher} from '@avocado/resource-persea';
|
|
||||||
import {
|
|
||||||
Rectangle,
|
|
||||||
Vector,
|
|
||||||
} from '@avocado/math-persea';
|
|
||||||
import {
|
|
||||||
Json,
|
|
||||||
Number,
|
|
||||||
} from '@avocado/react';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import Context from '../../context';
|
|
||||||
import Key from './expression/key';
|
|
||||||
|
|
||||||
const Literal = ({
|
|
||||||
context,
|
|
||||||
onChange,
|
|
||||||
path,
|
|
||||||
type,
|
|
||||||
options,
|
|
||||||
value,
|
|
||||||
vararg,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const [selectingType, setSelectingType] = useState(false);
|
|
||||||
const types = latus.get('%behavior-types');
|
|
||||||
const setLiteralType = (type) => {
|
|
||||||
const value = (types[type] || types.undefined).create();
|
|
||||||
if (null !== value) {
|
|
||||||
patch({
|
|
||||||
op: 'replace',
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setSelectingType(false);
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line react/destructuring-assignment
|
|
||||||
const contextDescription = context.describeChildren();
|
|
||||||
const valueComponent = (path, type, {value}) => {
|
|
||||||
switch (type) {
|
|
||||||
case 'bool': {
|
|
||||||
return (
|
|
||||||
<select
|
|
||||||
onChange={(event) => {
|
|
||||||
onChange(event, !!event.target.value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? false : value}
|
|
||||||
>
|
|
||||||
<option value={false}>false</option>
|
|
||||||
<option value>true</option>
|
|
||||||
</select>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'number':
|
|
||||||
return (
|
|
||||||
<Number
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? 0 : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'string':
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onChange={(event) => {
|
|
||||||
onChange(event, event.target.value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? '' : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'object':
|
|
||||||
return (
|
|
||||||
<Json
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
json={null === value ? {} : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'vector':
|
|
||||||
return (
|
|
||||||
<Vector
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? [0, 0] : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'rectangle':
|
|
||||||
return (
|
|
||||||
<Rectangle
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? [0, 0, 0, 0] : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'function':
|
|
||||||
case 'null':
|
|
||||||
case 'array':
|
|
||||||
return null;
|
|
||||||
default: {
|
|
||||||
const elements = [];
|
|
||||||
if ('undefined' === type || 'any' === type) {
|
|
||||||
elements.push(
|
|
||||||
<select
|
|
||||||
key={join(path, 'equality')}
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setSelectingType('≟' === value);
|
|
||||||
}}
|
|
||||||
value={selectingType ? '≟' : '='}
|
|
||||||
>
|
|
||||||
<option>=</option>
|
|
||||||
<option>≟</option>
|
|
||||||
</select>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ('undefined' !== typeof value) {
|
|
||||||
elements.push(
|
|
||||||
<div className="component" key={join(path, 'component')}>
|
|
||||||
{
|
|
||||||
valueComponent(
|
|
||||||
path,
|
|
||||||
Context.descriptionFor(undefined, value, latus).type,
|
|
||||||
{value},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <>{elements}</>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const {type: inferred} = Context.descriptionFor(undefined, value.value, latus);
|
|
||||||
const typeKey = `[literal ${inferred}]`;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{
|
|
||||||
selectingType
|
|
||||||
? (
|
|
||||||
<select
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setLiteralType(value);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>- Select type -</option>
|
|
||||||
{
|
|
||||||
Object.entries(types)
|
|
||||||
.filter(([type, value]) => value.create && type)
|
|
||||||
.map(([type]) => type)
|
|
||||||
.map((type) => <option key={type} value={type}>{type}</option>)
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
...(
|
|
||||||
'undefined' === type
|
|
||||||
? {'.': {label: '', type: 'undefined'}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...(
|
|
||||||
vararg
|
|
||||||
? {'...': {label: '', type: 'undefined'}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
[typeKey]: {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={typeKey}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<div className="literal">
|
|
||||||
{
|
|
||||||
options.length > 0
|
|
||||||
? (
|
|
||||||
<select
|
|
||||||
onChange={(event) => {
|
|
||||||
onChange(event, options[event.target.value].value, join(path, 'value'));
|
|
||||||
}}
|
|
||||||
value={options.findIndex(({value: optionValue}) => value.value === optionValue)}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
Object.entries(options)
|
|
||||||
.map(([key, {label}]) => (
|
|
||||||
<option
|
|
||||||
key={label}
|
|
||||||
value={key}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</option>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
)
|
|
||||||
: valueComponent(join(path, 'value'), type, value)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Literal.defaultProps = {
|
|
||||||
options: [],
|
|
||||||
vararg: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Literal.displayName = 'Literal';
|
|
||||||
|
|
||||||
Literal.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
options: PropTypes.arrayOf(PropTypes.any),
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
// eslint-disable-next-line react/forbid-prop-types
|
|
||||||
value: PropTypes.any.isRequired,
|
|
||||||
vararg: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Literal;
|
|
|
@ -1,5 +0,0 @@
|
||||||
.literal {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user