From c682e3b360ed0d1df4ea3af967752487358b06df Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Thu, 28 Oct 2021 15:46:39 +0800 Subject: [PATCH] add basic module --- packages/core/src/index.ts | 1 + packages/core/src/module.ts | 33 ++++++ packages/runtime/example/list/listModule.html | 100 ++++++++++++++++++ .../runtime/src/components/chakra-ui/List.tsx | 26 +++-- packages/runtime/src/services/registry.tsx | 97 ++++++++++++++++- 5 files changed, 250 insertions(+), 7 deletions(-) create mode 100644 packages/core/src/module.ts create mode 100644 packages/runtime/example/list/listModule.html diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c3c66720..17875721 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3,3 +3,4 @@ export * from './trait'; export * from './scope'; export * from './application'; export * from './method'; +export * from './module'; diff --git a/packages/core/src/module.ts b/packages/core/src/module.ts new file mode 100644 index 00000000..c880a4fc --- /dev/null +++ b/packages/core/src/module.ts @@ -0,0 +1,33 @@ +import { JSONSchema7Object } from 'json-schema'; +import { parseVersion } from './version'; +import { Metadata } from './metadata'; +import { Version } from './version'; +import { ApplicationComponent } from './application'; + +// spec + +export type Module = { + version: string; + kind: 'Module'; + metadata: Metadata; + spec: ModuleSpec; +}; + +type ModuleSpec = { + components: ApplicationComponent[]; + properties: JSONSchema7Object; + events: string[]; +}; + +// extended runtime +export type RuntimeModule = Module & { + parsedVersion: Version; +}; + +export function createModule(options: Omit): RuntimeModule { + return { + ...options, + kind: 'Module', + parsedVersion: parseVersion(options.version), + }; +} diff --git a/packages/runtime/example/list/listModule.html b/packages/runtime/example/list/listModule.html new file mode 100644 index 00000000..f18dfc1d --- /dev/null +++ b/packages/runtime/example/list/listModule.html @@ -0,0 +1,100 @@ + + + + + + meta-ui runtime example: list component + + +
+ + + diff --git a/packages/runtime/src/components/chakra-ui/List.tsx b/packages/runtime/src/components/chakra-ui/List.tsx index 8067759b..6416e1b2 100644 --- a/packages/runtime/src/components/chakra-ui/List.tsx +++ b/packages/runtime/src/components/chakra-ui/List.tsx @@ -34,7 +34,8 @@ const List: ComponentImplementation> = ({ return null; } const itemElementMemo = useRef(new Map()); - const parsedtemplete = template.map(parseTypeComponents); + const moduleTemplate = services.registry.getModuleByType(template.type); + const parsedtemplete = moduleTemplate.spec.components.map(parseTypeComponents); const listItems = listData.map((listItem, i) => { // this memo only diff listItem, dosen't compare expressions @@ -44,8 +45,8 @@ const List: ComponentImplementation> = ({ } } - const evaledTemplate = services.stateManager.mapValuesDeep( - { parsedtemplete }, + const evaledModuleProperties = services.stateManager.mapValuesDeep( + template.properties, ({ value }) => { if (typeof value === 'string') { return services.stateManager.maskedEval(value, true, { @@ -55,10 +56,20 @@ const List: ComponentImplementation> = ({ } return value; } - ).parsedtemplete; + ); + + const eventModuleTemplate = services.stateManager.mapValuesDeep( + { template: parsedtemplete }, + ({ value }) => { + if (typeof value === 'string') { + return services.stateManager.maskedEval(value, true, evaledModuleProperties); + } + return value; + } + ).template; const { topLevelComponents, slotComponentsMap } = resolveAppComponents( - evaledTemplate, + eventModuleTemplate, { services, app, @@ -96,7 +107,10 @@ const List: ComponentImplementation> = ({ const PropsSchema = Type.Object({ listData: Type.Array(Type.Record(Type.String(), Type.String())), - template: Type.Array(Type.Any()), + template: Type.Object({ + type: Type.String(), + properties: Type.Object({}), + }), }); const exampleProperties = { diff --git a/packages/runtime/src/services/registry.tsx b/packages/runtime/src/services/registry.tsx index 725b17d4..ee4c21c6 100644 --- a/packages/runtime/src/services/registry.tsx +++ b/packages/runtime/src/services/registry.tsx @@ -1,4 +1,4 @@ -import { RuntimeComponent, RuntimeTrait } from '@meta-ui/core'; +import { RuntimeComponent, RuntimeTrait, RuntimeModule } from '@meta-ui/core'; // components /* --- plain --- */ import PlainButton from '../components/plain/Button'; @@ -56,9 +56,77 @@ type ImplementedRuntimeTrait = RuntimeTrait & { impl: TraitImplementation; }; +const exampleModule: RuntimeModule = { + version: 'core/v1', + kind: 'Module', + parsedVersion: { + category: 'core/v1', + value: 'littleItem', + }, + metadata: { + name: 'littleItem', + }, + // name: 'littleItem', + spec: { + components: [ + { + id: '{{$id}}hstack', + type: 'chakra_ui/v1/hstack', + properties: {}, + traits: [], + }, + { + id: '{{$id}}1', + type: 'core/v1/text', + properties: { + value: { + raw: '**{{value}}**', + format: 'md', + }, + }, + traits: [ + { + type: 'core/v1/slot', + properties: { + container: { + id: '{{$id}}hstack', + slot: 'content', + }, + }, + }, + ], + }, + { + id: '{{$id}}2', + type: 'core/v1/text', + properties: { + value: { + raw: '**{{value2}}**', + format: 'md', + }, + }, + traits: [ + { + type: 'core/v1/slot', + properties: { + container: { + id: '{{$id}}hstack', + slot: 'content', + }, + }, + }, + ], + }, + ], + properties: {}, + events: [], + }, +}; + export class Registry { components: Map> = new Map(); traits: Map> = new Map(); + modules: Map> = new Map(); registerComponent(c: ImplementedRuntimeComponent) { if (this.components.get(c.version)?.has(c.metadata.name)) { @@ -119,6 +187,31 @@ export class Registry { } return res; } + + registerModule(c: RuntimeModule) { + if (this.modules.get(c.version)?.has(c.metadata.name)) { + throw new Error( + `Already has module ${c.version}/${c.metadata.name} in this registry.` + ); + } + if (!this.modules.has(c.version)) { + this.modules.set(c.version, new Map()); + } + this.modules.get(c.version)?.set(c.metadata.name, c); + } + + getModule(version: string, name: string): RuntimeModule { + const m = this.modules.get(version)?.get(name); + if (!m) { + throw new Error(`Module ${version}/${name} has not registered yet.`); + } + return m; + } + + getModuleByType(type: string): RuntimeModule { + const { version, name } = parseType(type); + return this.getModule(version, name); + } } export function initRegistry(): Registry { @@ -162,5 +255,7 @@ export function initRegistry(): Registry { registry.registerTrait(CoreFetch); registry.registerTrait(CoreValidation); + registry.registerModule(exampleModule); + return registry; }