modify module spec

This commit is contained in:
Bowen Tan 2021-11-04 17:31:27 +08:00
parent 4424b5281a
commit 7ef978a677
11 changed files with 194 additions and 201 deletions

View File

@ -2,7 +2,6 @@ import { JSONSchema7Object } from 'json-schema';
import { parseVersion } from './version';
import { Metadata } from './metadata';
import { Version } from './version';
import { ApplicationComponent } from './application';
// spec
@ -14,7 +13,6 @@ export type Module = {
};
type ModuleSpec = {
components: ApplicationComponent[];
properties: JSONSchema7Object;
events: string[];
stateMap: Record<string, string>;

View File

@ -20,97 +20,97 @@
name: 'littleItem',
},
spec: {
components: [
{
id: '{{$moduleId}}hstack',
type: 'chakra_ui/v1/hstack',
properties: {},
traits: [],
},
{
id: '{{$moduleId}}1',
type: 'core/v1/text',
properties: {
value: {
raw: '**{{value}}**',
format: 'md',
},
},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}hstack',
slot: 'content',
},
},
},
],
},
{
id: '{{$moduleId}}input',
type: 'chakra_ui/v1/input',
properties: {},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}hstack',
slot: 'content',
},
},
},
],
},
{
id: '{{$moduleId}}button',
type: 'chakra_ui/v1/button',
properties: {
text: {
raw: 'click',
format: 'md',
},
},
traits: [
{
type: 'core/v1/event',
properties: {
handlers: [
{
type: 'onClick',
componentId: '$module',
method: {
name: 'onEdit',
parameters: {
moduleId: '{{$moduleId}}',
},
},
wait: {},
disabled: false,
},
],
},
},
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}hstack',
slot: 'content',
},
},
},
],
},
],
properties: {},
events: ['onEdit'],
stateMap: {
value: '{{$moduleId}}input.value',
},
},
components: [
{
id: '{{$moduleId}}hstack',
type: 'chakra_ui/v1/hstack',
properties: {},
traits: [],
},
{
id: '{{$moduleId}}1',
type: 'core/v1/text',
properties: {
value: {
raw: '**{{value}}**',
format: 'md',
},
},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}hstack',
slot: 'content',
},
},
},
],
},
{
id: '{{$moduleId}}input',
type: 'chakra_ui/v1/input',
properties: {},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}hstack',
slot: 'content',
},
},
},
],
},
{
id: '{{$moduleId}}button',
type: 'chakra_ui/v1/button',
properties: {
text: {
raw: 'click{{value}}',
format: 'md',
},
},
traits: [
{
type: 'core/v1/event',
properties: {
handlers: [
{
type: 'onClick',
componentId: '$module',
method: {
name: 'onEdit',
parameters: {
moduleId: '{{$moduleId}}',
},
},
wait: {},
disabled: false,
},
],
},
},
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}hstack',
slot: 'content',
},
},
},
],
},
],
};
registry.registerModule(exampleModule);
@ -177,9 +177,9 @@
properties: {
listData: '{{ root.listData }}',
template: {
id: 'littleItem{{$listItem.id}}',
type: 'core/v1/littleItem',
properties: {
$moduleId: '{{$listItem.id}}{{$i}}',
value: '{{$listItem.name}}',
},
handlers: [
@ -188,7 +188,7 @@
componentId: '$utils',
method: {
name: 'alert',
parameters: '监听到模块事件了:{{ $listItem.name }}',
parameters: 'listen module vent{{ littleItem1.value }}',
},
wait: {},
disabled: false,

View File

@ -21,70 +21,6 @@
name: 'littleForm',
},
spec: {
components: [
{
id: '{{$moduleId}}__hstack',
type: 'chakra_ui/v1/hstack',
properties: {},
traits: [],
},
{
id: '{{$moduleId}}__input',
type: 'chakra_ui/v1/input',
properties: {},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}__hstack',
slot: 'content',
},
},
},
],
},
{
id: '{{$moduleId}}__button',
type: 'chakra_ui/v1/button',
properties: {
text: {
raw: '{{littleFormModule__input.value}}',
format: 'md',
},
},
traits: [
{
type: 'core/v1/event',
properties: {
handlers: [
{
type: 'onClick',
componentId: '$module',
method: {
name: 'onSubmit',
parameters: {
moduleId: '{{$moduleId}}',
},
},
wait: {},
disabled: false,
},
],
},
},
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}__hstack',
slot: 'content',
},
},
},
],
},
],
properties: {
btnText: Type.String(),
},
@ -93,6 +29,70 @@
value: '{{$moduleId}}__input.value',
},
},
components: [
{
id: '{{$moduleId}}__hstack',
type: 'chakra_ui/v1/hstack',
properties: {},
traits: [],
},
{
id: '{{$moduleId}}__input',
type: 'chakra_ui/v1/input',
properties: {},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}__hstack',
slot: 'content',
},
},
},
],
},
{
id: '{{$moduleId}}__button',
type: 'chakra_ui/v1/button',
properties: {
text: {
raw: '{{littleFormModule__input.value}}',
format: 'md',
},
},
traits: [
{
type: 'core/v1/event',
properties: {
handlers: [
{
type: 'onClick',
componentId: '$module',
method: {
name: 'onSubmit',
parameters: {
moduleId: '{{$moduleId}}',
},
},
wait: {},
disabled: false,
},
],
},
},
{
type: 'core/v1/slot',
properties: {
container: {
id: '{{$moduleId}}__hstack',
slot: 'content',
},
},
},
],
},
],
};
registry.registerModule(exampleModule);

View File

@ -27,29 +27,29 @@
},
events: [],
stateMap: {},
components: [
// list item
{
id: '{{$moduleId}}name',
type: 'core/v1/text',
properties: {
value: {
raw: '{{ isActive ? "yes" : "no" }}',
format: 'plain',
},
components: [
// list item
{
id: '{{$moduleId}}name',
type: 'core/v1/text',
properties: {
value: {
raw: '{{ isActive ? "yes" : "no" }}',
format: 'plain',
},
},
traits: [
{
type: 'core/v1/style',
properties: {
styleSlot: 'content',
style: 'color: {{isActive ? "green" : "red"}}',
},
},
traits: [
{
type: 'core/v1/style',
properties: {
styleSlot: 'content',
style: 'color: {{isActive ? "green" : "red"}}',
},
},
],
},
],
},
],
},
],
};
registry.registerModule(tdModule);

View File

@ -50,12 +50,12 @@ export const ModuleRenderer: React.FC<Props> = props => {
const moduleSpec = useMemo(() => services.registry.getModuleByType(type), [type]);
const parsedtemplete = useMemo(
() => moduleSpec.spec.components.map(parseTypeComponents),
() => moduleSpec.components.map(parseTypeComponents),
[moduleSpec]
);
// then eval the template and stateMap of module
const evaledStateMap = useDeepCompareMemo(() => {
const evaledStateMap = useMemo(() => {
// stateMap only use state i
return evalWithScope(moduleSpec.spec.stateMap, { $moduleId: moduleId });
}, [moduleSpec, moduleId]);
@ -75,6 +75,9 @@ export const ModuleRenderer: React.FC<Props> = props => {
const stops: ReturnType<typeof watch>[] = [];
if (!services.stateManager.store[moduleId]) {
services.stateManager.store[moduleId] = {};
}
for (const stateKey in evaledStateMap) {
// init state
services.stateManager.store[moduleId][stateKey] = get(

View File

@ -1,4 +1,3 @@
import { useRef } from 'react';
import { createComponent } from '@meta-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { List as BaseList, ListItem as BaseListItem } from '@chakra-ui/react';
@ -8,7 +7,6 @@ import { RuntimeModuleSchema } from '../../types/RuntimeSchema';
import { ModuleRenderer } from '../_internal/ModuleRenderer';
const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
component,
listData,
template,
app,
@ -17,15 +15,8 @@ const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
if (!listData) {
return null;
}
const itemElementMemo = useRef(new Map());
const listItems = listData.map((listItem, i) => {
// this memo only diff listItem, dosen't compare expressions
if (itemElementMemo.current.has(listItem.id)) {
if (itemElementMemo.current.get(listItem.id).value === listItem) {
return itemElementMemo.current.get(listItem.id).ele;
}
}
const evalScope = {
[LIST_ITEM_EXP]: listItem,
[LIST_ITEM_INDEX_EXP]: i,
@ -33,7 +24,7 @@ const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
const listItemEle = (
<BaseListItem key={listItem.id} spacing={3}>
<ModuleRenderer
id={`${component.id}ListItem${i}`}
id={template.id}
type={template.type}
properties={template.properties}
handlers={template.handlers}
@ -44,10 +35,6 @@ const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
</BaseListItem>
);
itemElementMemo.current.set(listItem.id, {
value: listItem,
ele: listItemEle,
});
return listItemEle;
});

View File

@ -37,7 +37,6 @@ export const TableImpl: ComponentImplementation<{
columns: Static<typeof ColumnsPropertySchema>;
isMultiSelect: Static<typeof IsMultiSelectPropertySchema>;
}> = ({
component,
data,
majorKey,
rowsPerPage,
@ -194,7 +193,6 @@ export const TableImpl: ComponentImplementation<{
{isMultiSelect ? checkbox : undefined}
{columns.map(column => (
<TableTd
tableId={component.id}
index={i}
key={column.key}
item={item}

View File

@ -7,7 +7,6 @@ import { MetaUIServices } from 'src/types/RuntimeSchema';
import { ModuleRenderer } from '../../_internal/ModuleRenderer';
export const TableTd: React.FC<{
tableId: string;
index: number;
item: any;
column: Static<typeof ColumnSchema>;
@ -15,7 +14,7 @@ export const TableTd: React.FC<{
services: MetaUIServices;
app?: RuntimeApplication;
}> = props => {
const { tableId, item, index, column, onClickItem, services, app } = props;
const { item, index, column, onClickItem, services, app } = props;
let value = item[column.key];
if (column.displayValue) {
@ -56,7 +55,7 @@ export const TableTd: React.FC<{
};
content = (
<ModuleRenderer
id={`${tableId}tdItem${column.key}`}
id={column.module.id}
type={column.module.type}
properties={column.module.properties}
handlers={column.module.handlers}

View File

@ -14,7 +14,6 @@ const ModuleContainer: ComponentImplementation<Props> = ({
services,
app,
}) => {
console.log('render');
return (
<ModuleRenderer
id={id}

View File

@ -1,4 +1,9 @@
import { RuntimeComponentSpec, RuntimeTraitSpec, RuntimeModuleSpec } from '@meta-ui/core';
import {
RuntimeComponentSpec,
RuntimeTraitSpec,
RuntimeModuleSpec,
ApplicationComponent,
} from '@meta-ui/core';
// components
/* --- plain --- */
import PlainButton from '../components/plain/Button';
@ -57,10 +62,14 @@ type ImplementedRuntimeTrait = RuntimeTraitSpec & {
impl: TraitImplementation;
};
type ImplementedRuntimeModule = RuntimeModuleSpec & {
components: ApplicationComponent[];
};
export class Registry {
components: Map<string, Map<string, ImplementedRuntimeComponent>> = new Map();
traits: Map<string, Map<string, ImplementedRuntimeTrait>> = new Map();
modules: Map<string, Map<string, RuntimeModuleSpec>> = new Map();
modules: Map<string, Map<string, ImplementedRuntimeModule>> = new Map();
registerComponent(c: ImplementedRuntimeComponent) {
if (this.components.get(c.version)?.has(c.metadata.name)) {
@ -122,7 +131,7 @@ export class Registry {
return res;
}
registerModule(c: RuntimeModuleSpec) {
registerModule(c: ImplementedRuntimeModule) {
if (this.modules.get(c.version)?.has(c.metadata.name)) {
throw new Error(
`Already has module ${c.version}/${c.metadata.name} in this registry.`
@ -134,7 +143,7 @@ export class Registry {
this.modules.get(c.version)?.set(c.metadata.name, c);
}
getModule(version: string, name: string): RuntimeModuleSpec {
getModule(version: string, name: string): ImplementedRuntimeModule {
const m = this.modules.get(version)?.get(name);
if (!m) {
throw new Error(`Module ${version}/${name} has not registered yet.`);
@ -142,7 +151,7 @@ export class Registry {
return m;
}
getModuleByType(type: string): RuntimeModuleSpec {
getModuleByType(type: string): ImplementedRuntimeModule {
const { version, name } = parseType(type);
return this.getModule(version, name);
}