feat: params, actions, etc
This commit is contained in:
parent
a6aeb66809
commit
c88c5e5c02
84
src/client/components/properties/actions.jsx
Normal file
84
src/client/components/properties/actions.jsx
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import {compose} from '@avocado/core';
|
||||||
|
import contempo from 'contempo';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import propertyPropTypes from './property-prop-types';
|
||||||
|
|
||||||
|
const reduceStep = (r, step) => {
|
||||||
|
switch (step.type) {
|
||||||
|
case 'key':
|
||||||
|
return `${r}.${step.key}`;
|
||||||
|
case 'invoke':
|
||||||
|
return (
|
||||||
|
<span className="step">
|
||||||
|
<span className="invocation">{r}</span>
|
||||||
|
<span className="paren open">(</span>
|
||||||
|
<div className="args">
|
||||||
|
{step.args.map(renderValue).map((element) => <div className="arg">{element}</div>)}
|
||||||
|
</div>
|
||||||
|
<span className="paren close">)</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderValue = (value) => {
|
||||||
|
switch (value.type) {
|
||||||
|
case 'traversal': {
|
||||||
|
const {steps} = value;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{steps.length > 0 && (
|
||||||
|
steps.slice(1).reduce(
|
||||||
|
reduceStep,
|
||||||
|
steps[0].key,
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'literal':
|
||||||
|
return <input value={value.value} />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const decorate = compose(
|
||||||
|
contempo(require('./actions.raw.scss')),
|
||||||
|
);
|
||||||
|
|
||||||
|
const Actions = ({
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
options,
|
||||||
|
value,
|
||||||
|
}) => (
|
||||||
|
<label>
|
||||||
|
<span className="text">
|
||||||
|
{label}
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
<div className="invisible-separator" />
|
||||||
|
<div className="actions">
|
||||||
|
<ol>
|
||||||
|
{
|
||||||
|
value.traversals.length > 0 && (
|
||||||
|
value.traversals.map(renderValue).map((o) => <li>{o}</li>)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
|
||||||
|
Actions.propTypes = {
|
||||||
|
...propertyPropTypes,
|
||||||
|
value: PropTypes.shape({}).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default decorate(Actions);
|
3
src/client/components/properties/actions.raw.scss
Normal file
3
src/client/components/properties/actions.raw.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.args {
|
||||||
|
margin-left: 2em;
|
||||||
|
}
|
|
@ -9,7 +9,10 @@ const Bool = ({
|
||||||
value,
|
value,
|
||||||
}) => (
|
}) => (
|
||||||
<label>
|
<label>
|
||||||
<span className="text">{label}</span>
|
<span className="text">
|
||||||
|
{label}
|
||||||
|
:
|
||||||
|
</span>
|
||||||
<div className="invisible-separator" />
|
<div className="invisible-separator" />
|
||||||
<input name={name} type="checkbox" checked={value} />
|
<input name={name} type="checkbox" checked={value} />
|
||||||
</label>
|
</label>
|
||||||
|
|
94
src/client/components/properties/condition.jsx
Normal file
94
src/client/components/properties/condition.jsx
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import {compose} from '@avocado/core';
|
||||||
|
import contempo from 'contempo';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import propertyPropTypes from './property-prop-types';
|
||||||
|
|
||||||
|
const renderValue = (value) => {
|
||||||
|
switch (value.type) {
|
||||||
|
case 'traversal': {
|
||||||
|
const {steps} = value;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{steps.length > 0 && (
|
||||||
|
steps.slice(1).reduce((r, step) => `${r}.${step.key}`, steps[0].key)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'literal':
|
||||||
|
return <input value={value.value} />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderOperand = (operand) => (
|
||||||
|
<span className="operand">
|
||||||
|
{renderValue(operand)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const binaryOps = [
|
||||||
|
['is', 'is equal to'],
|
||||||
|
['isnt', "isn't equal to"],
|
||||||
|
['>', 'is greater than'],
|
||||||
|
['>=', 'is greater than or equal to'],
|
||||||
|
['<', 'is less than'],
|
||||||
|
['<=', 'is less than or equal to'],
|
||||||
|
];
|
||||||
|
|
||||||
|
const decorate = compose(
|
||||||
|
contempo(require('./condition.raw.scss')),
|
||||||
|
);
|
||||||
|
|
||||||
|
const Condition = ({
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
options,
|
||||||
|
value,
|
||||||
|
}) => (
|
||||||
|
<label>
|
||||||
|
<span className="text">
|
||||||
|
{label}
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
<div className="invisible-separator" />
|
||||||
|
<div className="condition">
|
||||||
|
{
|
||||||
|
value.operands.length > 0 && (() => {
|
||||||
|
switch (value.operator) {
|
||||||
|
case 'is':
|
||||||
|
case 'isnt':
|
||||||
|
case '>':
|
||||||
|
case '>=':
|
||||||
|
case '<':
|
||||||
|
case '<=':
|
||||||
|
return value.operands.slice(1).reduce(
|
||||||
|
(r, operand) => (
|
||||||
|
<>
|
||||||
|
{r}
|
||||||
|
<select className="operator" value={value.operator}>
|
||||||
|
{binaryOps.map(([k, v]) => <option value={k}>{v}</option>)}
|
||||||
|
</select>
|
||||||
|
{renderOperand(operand)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
renderOperand(value.operands[0]),
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
|
||||||
|
Condition.propTypes = {
|
||||||
|
...propertyPropTypes,
|
||||||
|
value: PropTypes.shape({}).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default decorate(Condition);
|
14
src/client/components/properties/condition.raw.scss
Normal file
14
src/client/components/properties/condition.raw.scss
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.condition {
|
||||||
|
// flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator {
|
||||||
|
margin: 0 0.5em;
|
||||||
|
text-align: center;
|
||||||
|
text-align-last: center;
|
||||||
|
}
|
|
@ -10,7 +10,10 @@ const Number = ({
|
||||||
value,
|
value,
|
||||||
}) => (
|
}) => (
|
||||||
<label>
|
<label>
|
||||||
<span className="text">{label}</span>
|
<span className="text">
|
||||||
|
{label}
|
||||||
|
:
|
||||||
|
</span>
|
||||||
<div className="invisible-separator" />
|
<div className="invisible-separator" />
|
||||||
{
|
{
|
||||||
options
|
options
|
||||||
|
@ -21,7 +24,7 @@ const Number = ({
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)
|
)
|
||||||
: <input name={name} size={5} type="text" value={value} />
|
: <input name={name} type="text" value={value} />
|
||||||
}
|
}
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
|
import Actions from './actions';
|
||||||
import Bool from './bool';
|
import Bool from './bool';
|
||||||
|
import Condition from './condition';
|
||||||
import Number from './number';
|
import Number from './number';
|
||||||
import String from './string';
|
import String from './string';
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
export function propertyComponents() {
|
export function propertyComponents() {
|
||||||
return {
|
return {
|
||||||
|
actions: Actions,
|
||||||
bool: Bool,
|
bool: Bool,
|
||||||
|
condition: Condition,
|
||||||
number: Number,
|
number: Number,
|
||||||
string: String,
|
string: String,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,10 @@ const String = ({
|
||||||
value,
|
value,
|
||||||
}) => (
|
}) => (
|
||||||
<label>
|
<label>
|
||||||
<span className="text">{label}</span>
|
<span className="text">
|
||||||
|
{label}
|
||||||
|
:
|
||||||
|
</span>
|
||||||
<div className="invisible-separator" />
|
<div className="invisible-separator" />
|
||||||
{
|
{
|
||||||
options
|
options
|
||||||
|
@ -21,7 +24,7 @@ const String = ({
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)
|
)
|
||||||
: <input name={name} size={5} type="text" value={value} />
|
: <input name={name} type="text" value={value} />
|
||||||
}
|
}
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
|
|
|
@ -59,8 +59,11 @@ const makeTabSelector = (type) => createSelector(
|
||||||
const Trait = lookupTrait(type);
|
const Trait = lookupTrait(type);
|
||||||
const params = Trait ? {...Trait.defaultParams(), ...paramsRaw} : paramsRaw;
|
const params = Trait ? {...Trait.defaultParams(), ...paramsRaw} : paramsRaw;
|
||||||
const state = Trait ? {...Trait.defaultState(), ...stateRaw} : stateRaw;
|
const state = Trait ? {...Trait.defaultState(), ...stateRaw} : stateRaw;
|
||||||
|
const paramsDescription = Trait?.describeParams() || {};
|
||||||
const stateDescription = Trait?.describeState() || {};
|
const stateDescription = Trait?.describeState() || {};
|
||||||
const Components = Object.values(mapObject(stateDescription, (description, key) => {
|
const renderComponents = (description, values) => (
|
||||||
|
// eslint-disable-next-line no-shadow
|
||||||
|
Object.values(mapObject(description, (description, key) => {
|
||||||
const {label, options, type: componentType} = description;
|
const {label, options, type: componentType} = description;
|
||||||
const Component = PropertyComponents[componentType];
|
const Component = PropertyComponents[componentType];
|
||||||
return Component
|
return Component
|
||||||
|
@ -70,14 +73,20 @@ const makeTabSelector = (type) => createSelector(
|
||||||
label={label}
|
label={label}
|
||||||
name={key}
|
name={key}
|
||||||
options={options}
|
options={options}
|
||||||
value={state[key]}
|
value={values[key]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
}));
|
}))
|
||||||
|
);
|
||||||
return TraitComponent
|
return TraitComponent
|
||||||
? <TraitComponent params={params} state={state} />
|
? <TraitComponent params={params} state={state} />
|
||||||
: <form>{Components}</form>;
|
: (
|
||||||
|
<form>
|
||||||
|
{renderComponents(paramsDescription, params)}
|
||||||
|
{renderComponents(stateDescription, state)}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ form {
|
||||||
}
|
}
|
||||||
|
|
||||||
.invisible-separator {
|
.invisible-separator {
|
||||||
margin: 0.25em 0;
|
flex-grow: 1;
|
||||||
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user