add AppModel

This commit is contained in:
Bowen Tan 2021-12-20 18:11:11 +08:00
parent 3d51429240
commit 3a505db5e2
6 changed files with 310 additions and 0 deletions

View File

@ -0,0 +1,69 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentModel } from './ComponentModel';
import {
ComponentId,
ComponentType,
IApplicationModel,
IComponentModel,
IModuleModel,
ModuleId,
ModuleType,
SlotName,
} from './IAppModel';
export class ApplicationModel implements IApplicationModel {
components: IComponentModel[] = [];
modules: IModuleModel[] = [];
allComponents: IComponentModel[] = [];
private origin: ApplicationComponent[] = [];
private componentMap: Record<ComponentId, IComponentModel> = {};
constructor(components: ApplicationComponent[]) {
this.origin = components;
this.resolveTree(components);
}
resolveTree(components: ApplicationComponent[]) {
this.allComponents = components.map(c => {
const comp = new ComponentModel(c);
this.componentMap[c.id as ComponentId] = comp;
return comp;
});
this.allComponents.forEach(child => {
if (child.parentId && child.parentSlot) {
const parent = this.componentMap[child.parentId];
if (parent) {
if (parent.children[child.parentSlot]) {
parent.children[child.parentSlot].push(child);
} else {
parent.children[child.parentSlot] = [child];
}
}
child.parent = parent;
} else {
this.components.push(child);
}
});
}
get json(): ApplicationComponent[] {
return this.origin;
}
// createComponent (
// componentType: ComponentType,
// componentId: ComponentId,
// properties: Record<string, string>
// ) {
// return
// }
// createModule: (moduleId: ModuleId, moduleType: ModuleType) => IModuleModel;
// removeComponent: (componentId: ComponentId) => void;
// removeModule: (moduleId: ModuleId) => void;
// findComponent: (componentId: ComponentId) => IComponentModel | undefined;
// moveComponent: (
// fromId: ComponentId,
// toId: ComponentId,
// slot: SlotName,
// afterId: ComponentId
// ) => void;
}

View File

@ -0,0 +1,86 @@
import { ApplicationComponent, RuntimeComponentSpec } from '@sunmao-ui/core';
import { registry } from '../../setup';
import {
ComponentId,
ComponentType,
IApplicationModel,
IComponentModel,
IModuleModel,
ModuleId,
ModuleType,
SlotName,
StyleSlotName,
MethodName,
StateKey,
ITraitModel,
IFieldModel,
EventName,
} from './IAppModel';
import { TraitModel } from './TraitModel';
export class ComponentModel implements IComponentModel {
private origin: ApplicationComponent;
private spec: RuntimeComponentSpec;
id: ComponentId;
type: ComponentType;
properties: Record<string, IFieldModel> = {};
children: Record<SlotName, IComponentModel[]> = {};
parent: IComponentModel | null = null;
parentId: ComponentId | null = null;
parentSlot: SlotName | null = null;
traits: ITraitModel[] = [];
constructor(component: ApplicationComponent) {
this.origin = component;
this.id = component.id as ComponentId;
this.type = component.type as ComponentType;
this.spec = registry.getComponentByType(this.type);
this.traits = component.traits.map(t => new TraitModel(t, this));
// find slot trait
this.traits.forEach(t => {
if (t.type === 'core/v1/slot') {
this.parentId = t.properties.container.id;
this.parentSlot = t.properties.container.slot;
}
})
}
get slots() {
return (this.spec ? this.spec.spec.slots : []) as SlotName[];
}
get stateKeys() {
if (!this.spec) return [];
const componentStateKeys = Object.keys(this.spec.spec.state) as StateKey[];
const traitStateKeys: StateKey[] = this.traits.reduce(
(acc, t) => acc.concat(t.stateKeys),
[] as StateKey[]
);
return [...componentStateKeys, ...traitStateKeys]
}
get events() {
return (this.spec ? this.spec.spec.events : []) as EventName[];
}
get methods() {
if (!this.spec) return [];
const componentMethods = this.spec.spec.methods.map(m => m.name) as MethodName[];
const traitMethods: MethodName[] = this.traits.reduce(
(acc, t) => acc.concat(t.methods),
[] as MethodName[]
);
return [...componentMethods, ...traitMethods]
}
get styleSlots() {
return (this.spec ? this.spec.spec.styleSlots : []) as StyleSlotName[];
}
get json(): ApplicationComponent {
return this.origin;
}
}

View File

@ -0,0 +1,14 @@
import { IFieldModel } from './IAppModel';
const regExp = new RegExp('.*{{.*}}.*');
export class FieldModel implements IFieldModel {
value: any;
isDynamic = false;
// refs: Array<ComponentId | ModuleId> = []
constructor(value: unknown) {
this.value = value;
this.isDynamic = typeof value === 'string' && regExp.test(value);
}
}

View File

@ -0,0 +1,89 @@
import { ApplicationComponent } from "@sunmao-ui/core";
export type ComponentId = string & {
kind: 'componentId';
};
export type ComponentType = string & {
kind: 'componentType';
};
export type ModuleId = string & {
kind: 'moduleId';
};
export type ModuleType = string & {
kind: 'moduleType';
};
export type TraitType = string & {
kind: 'traitType';
};
export type SlotName = string & {
kind: 'slotName';
};
export type MethodName = string & {
kind: 'methodName';
};
export type StyleSlotName = string & {
kind: 'styleSlotName';
};
export type StateKey = string & {
kind: 'stateKey';
};
export type EventName = string & {
kind: 'eventName';
};
export interface IApplicationModel {
components: IComponentModel[];
modules: IModuleModel[];
allComponents: IComponentModel[];
json: ApplicationComponent[];
// createComponent: (componentType: ComponentType, componentId: ComponentId, properties: Record<string, string>) => IComponentModel;
// createModule: (moduleId: ModuleId, moduleType: ModuleType) => IModuleModel;
// removeComponent: (componentId: ComponentId) => void;
// removeModule: (moduleId: ModuleId) => void;
// findComponent: (componentId: ComponentId) => IComponentModel | undefined;
// moveComponent: (fromId: ComponentId, toId: ComponentId, slot: SlotName, afterId: ComponentId) => void;
}
export interface IModuleModel {
id: ModuleId;
type: ModuleType;
property: Record<string, IFieldModel>;
}
export interface IComponentModel {
id: ComponentId;
get json (): ApplicationComponent;
type: ComponentType;
properties: Record<string, IFieldModel>;
children: Record<SlotName, IComponentModel[]>;
parent: IComponentModel | null;
parentId: ComponentId | null;
parentSlot: SlotName | null;
traits: ITraitModel[];
stateKeys: StateKey[];
slots: SlotName[];
styleSlots: StyleSlotName[];
methods: MethodName[];
events: EventName[];
// addTrait: (traitType: TraitType, properties: Record<string, string>) => ITraitModel;
// removeTrait: (traitType: TraitType) => void;
// modifyProperty: (propertyName: string, value: any) => void;
// modifyId: (newId: ComponentId) => void;
}
export interface ITraitModel {
parent: IComponentModel;
type: TraitType;
properties: Record<string, any>;
propertiesMedatadata: Record<string, IFieldModel>;
methods: MethodName[];
stateKeys: StateKey[];
}
export interface IFieldModel {
value: any;
isDynamic: boolean;
// used components' id in the expression
// refs: Array<ComponentId | ModuleId>;
}

View File

@ -0,0 +1,49 @@
import {
ComponentTrait,
RuntimeTraitSpec,
} from '@sunmao-ui/core';
import { registry } from '../../setup';
import {
IComponentModel,
MethodName,
TraitType,
ITraitModel,
IFieldModel,
StateKey,
} from './IAppModel';
import { FieldModel } from './FieldModel';
export class TraitModel implements ITraitModel {
private origin: ComponentTrait;
private spec: RuntimeTraitSpec;
type: TraitType;
properties: Record<string, any>;
propertiesMedatadata: Record<string, IFieldModel> = {};
parent: IComponentModel;
constructor(trait: ComponentTrait, parent: IComponentModel) {
this.origin = trait;
this.parent = parent;
this.type = trait.type as TraitType;
this.spec = registry.getTraitByType(this.type);
this.properties = trait.properties || {};
for (const key in trait.properties) {
this.propertiesMedatadata[key] = new FieldModel(trait.properties[key]);
}
this.propertiesMedatadata;
}
get json(): ComponentTrait {
return this.origin;
}
get methods() {
return (this.spec ? this.spec.spec.methods.map(m => m.name) : []) as MethodName[];
}
get stateKeys() {
return (this.spec ? Object.keys(this.spec.spec.state) : []) as StateKey[];
}
}

View File

@ -1,5 +1,6 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { eventBus } from '../eventBus';
import { ApplicationModel } from './AppModel/AppModel';
import { IUndoRedoManager, IOperation, OperationList } from './type';
export class AppModelManager implements IUndoRedoManager {
@ -19,6 +20,8 @@ export class AppModelManager implements IUndoRedoManager {
updateComponents(components: ApplicationComponent[]) {
this.components = components;
eventBus.send('componentsChange', this.components);
(window as any).app = new ApplicationModel(this.components)
console.log((window as any).app)
}
do(operation: IOperation): void {