module can expose state

This commit is contained in:
Bowen Tan 2021-10-29 17:31:46 +08:00
parent aee0af21db
commit a0a75aca02
4 changed files with 49 additions and 20 deletions

View File

@ -17,6 +17,7 @@ type ModuleSpec = {
components: ApplicationComponent[];
properties: JSONSchema7Object;
events: string[];
stateMap: Record<string, string>;
};
// extended runtime

View File

@ -1,13 +1,17 @@
import { Static } from '@sinclair/typebox';
import React from 'react';
import { RuntimeApplication } from '@meta-ui/core';
import { MetaUIServices } from '../../types/RuntimeSchema';
import { MetaUIServices, RuntimeApplicationComponent } from '../../types/RuntimeSchema';
import { EventHandlerSchema } from '../../types/TraitPropertiesSchema';
import { parseTypeComponents } from '../chakra-ui/List';
import { resolveAppComponents } from '../../services/resolveAppComponents';
import { ImplWrapper } from '../../services/ImplWrapper';
import { watch } from '../../utils/watchReactivity';
import { get } from 'lodash';
import { useEffect } from 'react';
export type RuntimeModuleSchema = {
id: string;
type: string;
properties: Record<string, string>;
handlers: Array<Static<typeof EventHandlerSchema>>;
@ -20,10 +24,9 @@ type Props = RuntimeModuleSchema & {
};
export const ModuleRenderer: React.FC<Props> = props => {
const { type, properties, handlers, evalScope, services, app } = props;
const moduleTemplate = services.registry.getModuleByType(type);
const parsedtemplete = moduleTemplate.spec.components.map(parseTypeComponents);
const { id, type, properties, handlers, evalScope, services, app } = props;
// first eval the property of module
const { properties: moduleProperties, handlers: modulesHandlers } =
services.stateManager.mapValuesDeep({ properties, handlers }, ({ value }) => {
if (typeof value === 'string') {
@ -32,15 +35,41 @@ export const ModuleRenderer: React.FC<Props> = props => {
return value;
});
const evaledModuleTemplate = services.stateManager.mapValuesDeep(
{ template: parsedtemplete },
({ value }) => {
if (typeof value === 'string') {
return services.stateManager.maskedEval(value, true, moduleProperties);
const runtimeModule = services.registry.getModuleByType(type);
const parsedtemplete = runtimeModule.spec.components.map(parseTypeComponents);
// then eval the template and stateMap of module
const { parsedtemplete: evaledModuleTemplate, stateMap: evaledStateMap } =
services.stateManager.mapValuesDeep(
{ parsedtemplete, stateMap: runtimeModule.spec.stateMap },
({ value }) => {
if (typeof value === 'string') {
return services.stateManager.maskedEval(value, true, moduleProperties);
}
return value;
}
return value;
);
// listen component state change
useEffect(() => {
const stops: ReturnType<typeof watch>[] = [];
for (const stateKey in evaledStateMap) {
const stop = watch(
() => {
return get(services.stateManager.store, evaledStateMap[stateKey]);
},
newV => {
services.stateManager.store[id] = {
...services.stateManager.store[id],
[stateKey]: newV,
};
}
);
stops.push(stop);
}
).template;
return () => {
stops.forEach(s => s());
};
}, [evaledStateMap, services]);
const { topLevelComponents, slotComponentsMap } = resolveAppComponents(
evaledModuleTemplate,

View File

@ -24,6 +24,7 @@ export function parseTypeComponents(
}
const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
component,
listData,
template,
app,
@ -49,6 +50,7 @@ const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
const listItemEle = (
<BaseListItem key={listItem.id} spacing={3}>
<ModuleRenderer
id={`${component.id}ListItem${i}`}
type={template.type}
properties={template.properties}
handlers={[]}

View File

@ -66,7 +66,6 @@ const exampleModule: RuntimeModule = {
metadata: {
name: 'littleItem',
},
// name: 'littleItem',
spec: {
components: [
{
@ -97,14 +96,9 @@ const exampleModule: RuntimeModule = {
],
},
{
id: '{{$id}}2',
type: 'core/v1/text',
properties: {
value: {
raw: '**{{value2}}**',
format: 'md',
},
},
id: '{{$id}}input',
type: 'chakra_ui/v1/input',
properties: {},
traits: [
{
type: 'core/v1/slot',
@ -120,6 +114,9 @@ const exampleModule: RuntimeModule = {
],
properties: {},
events: [],
stateMap: {
value: '{{$id}}input.value',
},
},
};