diff --git a/src/client/resources/entity/entity.jsx b/src/client/resources/entity/entity.jsx
index 0bb796c..f49584e 100644
--- a/src/client/resources/entity/entity.jsx
+++ b/src/client/resources/entity/entity.jsx
@@ -29,7 +29,7 @@ const EntityComponent = (props) => {
);
diff --git a/src/client/resources/entity/state.js b/src/client/resources/entity/state.js
index 173d2b8..99975e0 100644
--- a/src/client/resources/entity/state.js
+++ b/src/client/resources/entity/state.js
@@ -46,7 +46,15 @@ export const selectEntityByUri = createSelector(
const slice = createSlice({
name: 'entities',
initialState: adapter.getInitialState({uris: {}}),
- reducers: {},
+ reducers: {
+ setTraitProperty: (state, {payload: {target, trait, type, key, value}}) => {
+ const {traits} = state.entities[target];
+ traits[trait] = traits[trait] || {};
+ traits[trait][type] = traits[trait][type] || {};
+ traits[trait][type][key] = value;
+ state.entities[target].traits = traits;
+ },
+ },
extraReducers: {
[fetchEntity.fulfilled]: (state, action) => {
adapter.upsertMany(state, action.payload.entities);
@@ -56,4 +64,8 @@ const slice = createSlice({
},
});
+export const {
+ setTraitProperty,
+} = slice.actions;
+
export default slice.reducer;
diff --git a/src/client/resources/entity/traits.jsx b/src/client/resources/entity/traits.jsx
index 868a030..8c3828c 100644
--- a/src/client/resources/entity/traits.jsx
+++ b/src/client/resources/entity/traits.jsx
@@ -6,6 +6,7 @@ import {produce} from 'immer';
import PropTypes from 'prop-types';
import React, {useEffect, useState} from 'react';
// import ReactMarkdown from 'react-markdown';
+import {useDispatch} from 'react-redux';
import {
Tab,
Tabs,
@@ -17,6 +18,8 @@ import {deregisterHooks, registerHooks} from 'scwp';
import Value from '~/client/value';
+import {setTraitProperty} from './state';
+
const SCROLL_MAG = 80;
const decorate = compose(
@@ -44,7 +47,7 @@ const ensureTraitComponents = () => {
}
};
-const makeTabSelector = (context, type) => createSelector(
+const makeTabSelector = (context, dispatch, target, type) => createSelector(
(_) => _,
(trait) => {
ensureTraitComponents();
@@ -55,7 +58,7 @@ const makeTabSelector = (context, type) => createSelector(
const state = Trait ? {...Trait.defaultState(), ...stateRaw} : stateRaw;
const paramsDescription = Trait?.describeParams() || {};
const stateDescription = Trait?.describeState() || {};
- const renderComponents = (description, values) => (
+ const renderComponents = (traitHalf, description, values) => (
// eslint-disable-next-line no-shadow
Object.values(mapObject(description, (description, key) => {
const {label, options} = description;
@@ -68,6 +71,13 @@ const makeTabSelector = (context, type) => createSelector(
dispatch(setTraitProperty({
+ target,
+ trait: type,
+ type: traitHalf,
+ key,
+ value,
+ }))}
options={options}
value={values[key]}
/>
@@ -79,55 +89,56 @@ const makeTabSelector = (context, type) => createSelector(
?
: (
);
},
);
const Traits = (props) => {
- const {context, traits} = props;
- const [tabSelectorMap, setTabSelectorMap] = useState({});
+ const {context, target, traits} = props;
+ const dispatch = useDispatch();
+ const [traitForms, setTraitForms] = useState({});
+ const [mts, setMts] = useState();
useEffect(() => {
+ if (!mts) {
+ setMts(() => (type) => makeTabSelector(context, dispatch, target, type));
+ }
+ }, [mts, setMts]);
+ useEffect(() => {
+ if (!mts) {
+ return;
+ }
const entries = Object.entries(traits);
- setTabSelectorMap(produce(tabSelectorMap, (draft) => {
+ setTraitForms(produce(traitForms, (draft) => {
for (let i = 0; i < entries.length; i++) {
const [type] = entries[i];
- if (!draft[type]) {
- // eslint-disable-next-line no-param-reassign
- draft[type] = new WeakMap();
- }
- if (!draft[type].has(traits)) {
- draft[type].set(traits, makeTabSelector(context, type));
- }
+ draft[type] = mts(type);
}
}));
const M = {
autoreg$accept: (type, M2) => {
if ('trait' === type) {
const {default: Trait} = M2;
- setTabSelectorMap(produce(tabSelectorMap, (draft) => {
- const traitType = Trait.type();
- if (!draft[traitType]) {
- // eslint-disable-next-line no-param-reassign
- draft[traitType] = new WeakMap();
- }
- draft[traitType].set(traits, makeTabSelector(traitType));
+ setTraitForms(produce(traitForms, (draft) => {
+ draft[Trait.type()] = mts(Trait.type());
}));
}
},
};
registerHooks(M, __filename);
return () => deregisterHooks(M);
- }, [context, tabSelectorMap, traits]);
+ }, [mts, traits]);
const [tabIndex, setTabIndex] = useState(0);
let listRef;
const entries = Object.entries(traits);
const tabs = [];
for (let i = 0; i < entries.length; i++) {
const [type, trait] = entries[i];
- tabs.push([type, tabSelectorMap[type]?.get(traits)(trait)]);
+ if (type in traitForms) {
+ tabs.push([type, traitForms[type](trait)]);
+ }
}
return (
diff --git a/src/client/types/literal.type-renderer.jsx b/src/client/types/literal.type-renderer.jsx
index d3907a4..9f141a2 100644
--- a/src/client/types/literal.type-renderer.jsx
+++ b/src/client/types/literal.type-renderer.jsx
@@ -14,6 +14,7 @@ const decorate = compose(
const Literal = ({
context,
+ onChange,
value,
}) => {
const typeRenderers = useTypeRenderers();
@@ -36,7 +37,7 @@ const Literal = ({
.map((tierOption) => )
}
- {Component ? : null}
+ {Component ? : null}
);
};
diff --git a/src/client/types/string.type-renderer.jsx b/src/client/types/string.type-renderer.jsx
index d7e1a24..e6f92f5 100644
--- a/src/client/types/string.type-renderer.jsx
+++ b/src/client/types/string.type-renderer.jsx
@@ -4,6 +4,7 @@ import React from 'react';
import propTypes from './prop-types';
const String = ({
+ onChange,
options,
value,
}) => (
@@ -17,7 +18,13 @@ const String = ({
))}
)
- :
+ : (
+ onChange(event.target.value)}
+ type="text"
+ value={value}
+ />
+ )
}
);
diff --git a/src/client/value.jsx b/src/client/value.jsx
index 1812182..a93c71e 100644
--- a/src/client/value.jsx
+++ b/src/client/value.jsx
@@ -14,6 +14,7 @@ const decorate = compose(
const Value = ({
context,
+ onChange,
options,
value,
}) => {
@@ -25,7 +26,7 @@ const Value = ({
{
Component
- ?
+ ?
: ?
}