diff --git a/packages/entity/src/behavior-components/expression.jsx b/packages/entity/src/behavior-components/expression.jsx index 20f4f63..70835f5 100644 --- a/packages/entity/src/behavior-components/expression.jsx +++ b/packages/entity/src/behavior-components/expression.jsx @@ -1,7 +1,11 @@ import {join, relative} from 'path'; -import {isInvocation, isKey} from '@avocado/behavior'; -import {PropTypes, React} from '@latus/react'; +import {compile, isInvocation, isKey} from '@avocado/behavior'; +import { + PropTypes, + React, + useLatus, +} from '@latus/react'; import {useJsonPatcher} from '@persea/json'; import classnames from 'classnames'; @@ -10,18 +14,18 @@ import Key from './expression/key'; const Expression = ({ context, - expression, + value, path, type, }) => { + const latus = useLatus(); const patch = useJsonPatcher(); let i = 0; - const {ops} = expression; + const {ops} = value; const Renderables = []; let opsCount = 0; - let walk = context; // eslint-disable-next-line react/destructuring-assignment - let description = context.constructor.descriptionFor(walk); + let description = context.constructor.descriptionFor(context); const onChange = (event, value, localPath) => { const patches = []; const j = parseInt(relative(path, localPath).split('/')[1], 10); @@ -100,8 +104,8 @@ const Expression = ({ onChange(event, value, localPath); } }} - op={op} path={opPath} + value={op.key} />, ); opsCount += 1; @@ -136,15 +140,10 @@ const Expression = ({ opsCount += 1; } if (isKey(op)) { - if (context === walk) { - [walk] = context.get(op.key); - } - else { - walk = walk[op.key]; - } + const current = compile({type: 'expression', ops: ops.slice(0, i + 1)}, latus)(context); description = { - ...context.constructor.descriptionFor(walk), - ...description.children[op.key], + ...context.constructor.descriptionFor(current), + ...description?.children?.[op.key] || {}, }; if (description.args && (!nextOp || !isInvocation(nextOp))) { Renderables.push( @@ -154,17 +153,16 @@ const Expression = ({ onClick={((description, opPath) => () => { const parts = opPath.split('/'); parts.push(parseInt(parts.pop(), 10) + 1); - const invocation = { - type: 'invoke', - args: description.args.map(() => ({ - type: 'literal', - value: null, - })), - }; patch({ op: 'add', path: parts.join('/'), - value: invocation, + value: { + type: 'invoke', + args: description.args.map(() => ({ + type: 'literal', + value: null, + })), + }, }); })(description, opPath)} type="button" @@ -218,7 +216,7 @@ Expression.propTypes = { describe: PropTypes.func, get: PropTypes.func, }).isRequired, - expression: PropTypes.shape({ + value: PropTypes.shape({ ops: PropTypes.arrayOf( PropTypes.shape({ key: PropTypes.string, diff --git a/packages/entity/src/behavior-components/expression/invocation.jsx b/packages/entity/src/behavior-components/expression/invocation.jsx index 010c087..808de71 100644 --- a/packages/entity/src/behavior-components/expression/invocation.jsx +++ b/packages/entity/src/behavior-components/expression/invocation.jsx @@ -1,22 +1,33 @@ import {join} from 'path'; import {PropTypes, React} from '@latus/react'; -import {useJsonPatcher} from '@persea/json'; -import Literal from '../literal'; -import Key from './key'; +import Variant from '../variant'; const Invocation = ({ context, description, - Expression, onChange, op, path, }) => { // eslint-disable-next-line react/destructuring-assignment - const contextDescription = context.describe(); - const patch = useJsonPatcher(); + const argComponent = (arg, i) => { + const argPath = join(path, 'args', i.toString()); + const options = description?.args?.[i].options; + const type = description?.args?.[i].type || 'undefined'; + return ( + + ); + }; return (
( @@ -26,55 +37,7 @@ const Invocation = ({ key={join(path, 'args', i.toString())} className="invocation__arg" > - { - 'literal' === arg.type - ? ( - <> - ': { - label: '', - type: arg.type, - }, - ...contextDescription.children, - }} - onChange={(event, value) => { - patch({ - op: 'replace', - path: join(path, 'args', i.toString()), - value: { - type: 'expression', - ops: [ - { - type: 'key', - key: value, - }, - ], - }, - }); - }} - op={op} - path={path} - /> - - - ) - : ( - - ) - } + {argComponent(arg, i)} {i < op.args.length - 1 && , }
)) @@ -85,9 +48,7 @@ const Invocation = ({ }; Invocation.propTypes = { - context: PropTypes.shape({ - describe: PropTypes.func, - }).isRequired, + context: PropTypes.shape({}).isRequired, description: PropTypes.shape({ args: PropTypes.arrayOf( PropTypes.shape({ @@ -96,7 +57,6 @@ Invocation.propTypes = { }), ), }).isRequired, - Expression: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, op: PropTypes.shape({ args: PropTypes.arrayOf(PropTypes.any), diff --git a/packages/entity/src/behavior-components/expression/key.jsx b/packages/entity/src/behavior-components/expression/key.jsx index 9da4b9d..739025f 100644 --- a/packages/entity/src/behavior-components/expression/key.jsx +++ b/packages/entity/src/behavior-components/expression/key.jsx @@ -5,8 +5,8 @@ import {PropTypes, React} from '@latus/react'; const Key = ({ childrenDescription, onChange, - op, path, + value, }) => { const options = Object.entries(childrenDescription) .map(([key]) => ( @@ -18,7 +18,7 @@ const Key = ({ onChange={(event) => { onChange(event, event.target.value, join(path, 'key')); }} - value={op.key} + value={value} > {options} @@ -29,10 +29,8 @@ const Key = ({ Key.propTypes = { childrenDescription: PropTypes.shape({}).isRequired, onChange: PropTypes.func.isRequired, - op: PropTypes.shape({ - key: PropTypes.string, - }).isRequired, path: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, }; export default Key; diff --git a/packages/entity/src/behavior-components/expressions.jsx b/packages/entity/src/behavior-components/expressions.jsx index 4030561..4bdf955 100644 --- a/packages/entity/src/behavior-components/expressions.jsx +++ b/packages/entity/src/behavior-components/expressions.jsx @@ -6,7 +6,7 @@ import Expression from './expression'; const Expressions = ({ context, - expressions: {expressions}, + value: {expressions}, path, }) => (
@@ -14,7 +14,7 @@ const Expressions = ({ expressions.map((expression, i) => ( { - const valueComponent = (path, type, value) => { + // eslint-disable-next-line react/destructuring-assignment + const contextDescription = context.describe(); + const patch = useJsonPatcher(); + const valueComponent = (path, type, {value}) => { switch (type) { case 'number': return ( @@ -19,7 +31,7 @@ const Literal = ({ onChange={(event, value) => { onChange(event, value, path); }} - value={value} + value={null === value ? 0 : value} /> ); case 'string': @@ -29,7 +41,7 @@ const Literal = ({ onChange={(event) => { onChange(event, value, path); }} - value={value || ''} + value={null === value ? '' : value} /> ); case 'object': @@ -38,7 +50,7 @@ const Literal = ({ onChange={(event, value) => { onChange(event, value, path); }} - json={value} + json={null === value ? {} : value} /> ); default: @@ -46,32 +58,58 @@ const Literal = ({ } }; return ( -
- { - options.length > 0 - ? ( - - ) - : valueComponent(path, type, value) - } -
+ <> + ': { + label: '', + type: value.type, + }, + ...contextDescription.children, + }} + onChange={(event, value) => { + patch({ + op: 'replace', + path, + value: { + type: 'expression', + ops: [ + { + type: 'key', + key: value, + }, + ], + }, + }); + }} + op={op} + path={path} + /> +
+ { + options.length > 0 + ? ( + + ) + : valueComponent(join(path, 'value'), type, value) + } +
+ ); }; @@ -80,8 +118,14 @@ Literal.defaultProps = { }; Literal.propTypes = { + context: PropTypes.shape({ + describe: PropTypes.func, + }).isRequired, type: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, + op: PropTypes.shape({ + key: PropTypes.string, + }).isRequired, options: PropTypes.arrayOf(PropTypes.any), path: PropTypes.string.isRequired, // eslint-disable-next-line react/forbid-prop-types diff --git a/packages/entity/src/behavior-components/variant.jsx b/packages/entity/src/behavior-components/variant.jsx new file mode 100644 index 0000000..40961d1 --- /dev/null +++ b/packages/entity/src/behavior-components/variant.jsx @@ -0,0 +1,30 @@ +import { + PropTypes, + React, + useLatus, +} from '@latus/react'; + +const Variant = (props) => { + const {value} = props; + const {type} = value; + const latus = useLatus(); + const BehaviorControllers = latus.get('%behavior-controllers'); + const Controller = BehaviorControllers[type]; + return ( + + ); +}; + +Variant.propTypes = { + onChange: PropTypes.func.isRequired, + path: PropTypes.string.isRequired, + value: PropTypes.shape({ + type: PropTypes.string, + }).isRequired, +}; + +export default Variant; diff --git a/packages/entity/src/index.js b/packages/entity/src/index.js index d5a1f41..b4f1153 100644 --- a/packages/entity/src/index.js +++ b/packages/entity/src/index.js @@ -2,6 +2,9 @@ import {basename, extname} from 'path'; import {camelCase} from '@latus/core'; +import Expression from './behavior-components/expression'; +import Expressions from './behavior-components/expressions'; +import Literal from './behavior-components/literal'; import EntityResourceController from './resource-controllers/entity'; export {EntityResourceController}; @@ -11,6 +14,11 @@ export default { '@latus/core/starting': async (latus) => { const TraitRenderers = latus.invokeReduce('@persea/entity/trait-components'); latus.set('%trait-components', TraitRenderers); + latus.set('%behavior-controllers', { + expression: Expression, + expressions: Expressions, + literal: Literal, + }); }, '@persea/core/resource-controllers': () => [ EntityResourceController, diff --git a/packages/entity/src/trait-components/alive.jsx b/packages/entity/src/trait-components/alive.jsx index 7a18aaf..0937e05 100644 --- a/packages/entity/src/trait-components/alive.jsx +++ b/packages/entity/src/trait-components/alive.jsx @@ -14,7 +14,7 @@ const Alive = ({ Death actions