mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-04-12 21:50:23 +08:00
modify module spec
This commit is contained in:
parent
4424b5281a
commit
7ef978a677
@ -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>;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
@ -14,7 +14,6 @@ const ModuleContainer: ComponentImplementation<Props> = ({
|
||||
services,
|
||||
app,
|
||||
}) => {
|
||||
console.log('render');
|
||||
return (
|
||||
<ModuleRenderer
|
||||
id={id}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user