refactor: type renderers

This commit is contained in:
cha0s 2020-06-18 04:29:29 -05:00
parent 3f1a94545b
commit c84caf601e
13 changed files with 148 additions and 142 deletions

View File

@ -1,16 +0,0 @@
import Actions from './actions';
import Bool from './bool';
import Condition from './condition';
import Number from './number';
import String from './string';
// eslint-disable-next-line import/prefer-default-export
export function propertyComponents() {
return {
actions: Actions,
bool: Bool,
condition: Condition,
number: Number,
string: String,
};
}

View File

@ -1,5 +1,5 @@
import {compose, mapObject} from '@avocado/core'; import {compose, mapObject} from '@avocado/core';
import {all} from '@avocado/entity/trait/trait-components.scwp'; import {all as allTraitComponents} from '@avocado/entity/trait/trait-components.scwp';
import {lookupTrait} from '@avocado/entity'; import {lookupTrait} from '@avocado/entity';
import contempo from 'contempo'; import contempo from 'contempo';
import {produce} from 'immer'; import {produce} from 'immer';
@ -15,6 +15,8 @@ import {
import {createSelector} from '@reduxjs/toolkit'; import {createSelector} from '@reduxjs/toolkit';
import {deregisterHooks, invokeHookFlat, registerHooks} from 'scwp'; import {deregisterHooks, invokeHookFlat, registerHooks} from 'scwp';
import {all as allTypeRenderers} from './types/type-renderers.scwp';
const SCROLL_MAG = 80; const SCROLL_MAG = 80;
const decorate = compose( const decorate = compose(
@ -35,24 +37,26 @@ const decorate = compose(
let TraitComponents; let TraitComponents;
const ensureTraitComponents = () => { const ensureTraitComponents = () => {
if (!TraitComponents) { if (!TraitComponents) {
TraitComponents = Object.values(all()).reduce((r, M) => { TraitComponents = Object.values(allTraitComponents()).reduce((r, M) => {
const {default: TraitComponent} = M; const {default: TraitComponent} = M;
return {...r, [TraitComponent.type]: TraitComponent}; return {...r, [TraitComponent.type]: TraitComponent};
}, {}); }, {});
} }
}; };
let PropertyComponents; let TypeRenderers;
const ensurePropertyComponents = () => { const ensureTypeRenderers = () => {
if (!PropertyComponents) { if (!TypeRenderers) {
const results = invokeHookFlat('propertyComponents'); TypeRenderers = Object.values(allTypeRenderers()).reduce((r, M) => {
PropertyComponents = results.reduce((r, map) => ({...r, ...map}), {}); const {default: {type, component}} = M;
return {...r, [type]: component};
}, {});
} }
}; };
const makeTabSelector = (type) => createSelector( const makeTabSelector = (type) => createSelector(
(_) => _, (_) => _,
(trait) => { (trait) => {
ensurePropertyComponents(); ensureTypeRenderers();
ensureTraitComponents(); ensureTraitComponents();
const {params: paramsRaw, state: stateRaw} = trait; const {params: paramsRaw, state: stateRaw} = trait;
const {[type]: TraitComponent} = TraitComponents; const {[type]: TraitComponent} = TraitComponents;
@ -65,9 +69,15 @@ const makeTabSelector = (type) => createSelector(
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
Object.values(mapObject(description, (description, key) => { Object.values(mapObject(description, (description, key) => {
const {label, options, type: componentType} = description; const {label, options, type: componentType} = description;
const Component = PropertyComponents[componentType]; const Component = TypeRenderers[componentType];
return Component return Component
? ( ? (
<label>
<span className="text">
{label}
:
</span>
<div className="invisible-separator" />
<Component <Component
key={key} key={key}
label={label} label={label}
@ -75,6 +85,7 @@ const makeTabSelector = (type) => createSelector(
options={options} options={options}
value={values[key]} value={values[key]}
/> />
</label>
) )
: null; : null;
})) }))

View File

@ -0,0 +1,41 @@
import {compose} from '@avocado/core';
import classnames from 'classnames';
import contempo from 'contempo';
import PropTypes from 'prop-types';
import React from 'react';
import propertyPropTypes from './property-prop-types';
import Value from './value.type-renderer';
const decorate = compose(
contempo(require('./actions.raw.scss')),
);
const Actions = ({
name,
label,
options,
value,
}) => (
<div className="actions">
<ol>
{
value.traversals.length > 0 && (
value.traversals.map(
(traversal) => <li><Value.component value={traversal} /></li>,
)
)
}
</ol>
</div>
);
Actions.propTypes = {
...propertyPropTypes,
value: PropTypes.shape({}).isRequired,
};
export default {
type: 'actions',
component: decorate(Actions),
};

View File

@ -8,14 +8,7 @@ const Bool = ({
label, label,
value, value,
}) => ( }) => (
<label>
<span className="text">
{label}
:
</span>
<div className="invisible-separator" />
<input name={name} type="checkbox" checked={value} /> <input name={name} type="checkbox" checked={value} />
</label>
); );
Bool.propTypes = { Bool.propTypes = {
@ -23,4 +16,7 @@ Bool.propTypes = {
value: PropTypes.bool.isRequired, value: PropTypes.bool.isRequired,
}; };
export default Bool; export default {
type: 'bool',
component: Bool,
};

View File

@ -49,13 +49,7 @@ const Condition = ({
options, options,
value, value,
}) => ( }) => (
<label> <span className="condition">
<span className="text">
{label}
:
</span>
<div className="invisible-separator" />
<div className="condition">
{ {
value.operands.length > 0 && (() => { value.operands.length > 0 && (() => {
switch (value.operator) { switch (value.operator) {
@ -82,8 +76,7 @@ const Condition = ({
} }
})() })()
} }
</div> </span>
</label>
); );
Condition.propTypes = { Condition.propTypes = {
@ -91,4 +84,7 @@ Condition.propTypes = {
value: PropTypes.shape({}).isRequired, value: PropTypes.shape({}).isRequired,
}; };
export default decorate(Condition); export default {
type: 'condition',
component: decorate(Condition),
};

View File

@ -9,12 +9,7 @@ const Number = ({
options, options,
value, value,
}) => ( }) => (
<label> <span className="number">
<span className="text">
{label}
:
</span>
<div className="invisible-separator" />
{ {
options options
? ( ? (
@ -26,7 +21,7 @@ const Number = ({
) )
: <input name={name} type="text" value={value} /> : <input name={name} type="text" value={value} />
} }
</label> </span>
); );
Number.propTypes = { Number.propTypes = {
@ -34,4 +29,7 @@ Number.propTypes = {
value: PropTypes.number.isRequired, value: PropTypes.number.isRequired,
}; };
export default Number; export default {
type: 'number',
component: Number,
};

View File

@ -9,12 +9,7 @@ const String = ({
options, options,
value, value,
}) => ( }) => (
<label> <span className="string">
<span className="text">
{label}
:
</span>
<div className="invisible-separator" />
{ {
options options
? ( ? (
@ -26,7 +21,7 @@ const String = ({
) )
: <input name={name} type="text" value={value} /> : <input name={name} type="text" value={value} />
} }
</label> </span>
); );
String.propTypes = { String.propTypes = {
@ -34,4 +29,7 @@ String.propTypes = {
value: PropTypes.string.isRequired, value: PropTypes.string.isRequired,
}; };
export default String; export default {
type: 'string',
component: String,
};

View File

@ -0,0 +1,9 @@
function types(scwp) {
scwp.enterSelf();
scwp.loadSelf('scwp/autoreg', {
paths: scwp.paths,
root: scwp.root,
type: 'type-renderer',
});
}
module.exports = types;

View File

@ -13,7 +13,7 @@ const reduceStep = (r, step) => {
case 'invoke': case 'invoke':
return ( return (
<span className="step"> <span className="step">
<span className="invocation"><input value={r} /></span> <span className="fn"><input value={r} /></span>
<span className="paren open">(</span> <span className="paren open">(</span>
<div className="args"> <div className="args">
{ {
@ -22,22 +22,12 @@ const reduceStep = (r, step) => {
(r2, element, i) => ( (r2, element, i) => (
<> <>
{r2} {r2}
<div <div className={classnames('arg', step.args[i + 1].type)}>
className={classnames(
'arg',
step.args[i + 1].type,
)}
>
{element} {element}
</div> </div>
</> </>
), ),
<div <div className={classnames('arg', step.args[0].type)}>
className={classnames(
'arg',
step.args[0].type,
)}
>
{renderValue(step.args[0])} {renderValue(step.args[0])}
</div>, </div>,
) )
@ -76,7 +66,6 @@ const renderValue = (value) => {
return <span className="wrapper"><input value={value.value} /></span>; return <span className="wrapper"><input value={value.value} /></span>;
} }
return ( return (
<>
<div className="object"> <div className="object">
<span className="bracket open">{'{'}</span> <span className="bracket open">{'{'}</span>
<pre contentEditable> <pre contentEditable>
@ -87,45 +76,29 @@ const renderValue = (value) => {
</pre> </pre>
<span className="bracket close">{'}'}</span> <span className="bracket close">{'}'}</span>
</div> </div>
</>
); );
default: default:
return null; return null;
} }
}
};
const decorate = compose( const decorate = compose(
contempo(require('./actions.raw.scss')), contempo(require('./value.raw.scss')),
); );
const Actions = ({ const Value = ({
name, name,
label, label,
options, options,
value, value,
}) => ( }) => renderValue(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 = { Value.propTypes = {
...propertyPropTypes, ...propertyPropTypes,
value: PropTypes.shape({}).isRequired, value: PropTypes.shape({}).isRequired,
}; };
export default decorate(Actions); export default {
type: 'value',
component: decorate(Value),
};