Merge pull request #204 from webzard-io/refactor/type

rename types in core and runtime
This commit is contained in:
yz-yu 2022-01-11 09:36:40 +08:00 committed by GitHub
commit 862c9d71ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 536 additions and 530 deletions

View File

@ -4,14 +4,14 @@ import {
implementRuntimeComponent,
LIST_ITEM_EXP,
LIST_ITEM_INDEX_EXP,
RuntimeModuleSchema,
ModuleSchema,
ModuleRenderer,
} from '@sunmao-ui/runtime';
import { css } from '@emotion/css';
const PropsSchema = Type.Object({
listData: Type.Array(Type.Record(Type.String(), Type.String())),
template: RuntimeModuleSchema,
template: ModuleSchema,
});
const exampleProperties = {

View File

@ -1,5 +1,5 @@
import { Type } from '@sinclair/typebox';
import { RuntimeModuleSchema, EventHandlerSchema } from '@sunmao-ui/runtime';
import { ModuleSchema, EventHandlerSchema } from '@sunmao-ui/runtime';
export const MajorKeyPropertySchema = Type.String();
export const RowsPerPagePropertySchema = Type.Number();
@ -30,7 +30,7 @@ export const ColumnSchema = Type.Object({
text: Type.String(),
handlers: Type.Array(EventHandlerSchema),
}),
module: RuntimeModuleSchema,
module: ModuleSchema,
});
export const ColumnsPropertySchema = Type.Array(ColumnSchema);

View File

@ -7,47 +7,45 @@ export type Application = {
version: string;
kind: 'Application';
metadata: Metadata;
spec: ApplicationSpec;
spec: {
components: ComponentSchema[];
};
};
type ApplicationSpec = {
components: ApplicationComponent[];
};
export type ApplicationComponent = {
export type ComponentSchema = {
id: string;
type: string;
// do runtime type check
properties: Record<string, unknown>;
traits: ComponentTrait[];
traits: TraitSchema[];
// scopes TBD
};
export type ComponentTrait = {
export type TraitSchema = {
type: string;
// do runtime type check
properties: Record<string, unknown>;
};
export type RuntimeTraitSchema = TraitSchema & {
parsedType: VersionAndName;
}
type VersionAndName = {
version: string;
name: string;
};
export type RuntimeComponentSchema = Omit<ComponentSchema, 'traits'> & {
parsedType: VersionAndName;
traits: RuntimeTraitSchema[];
};
// extended runtime
export type RuntimeApplication = Omit<Application, 'spec'> & {
parsedVersion: Version;
spec: Omit<ApplicationSpec, 'components'> & {
components: Array<
Omit<ApplicationComponent, 'traits'> & {
parsedType: VersionAndName;
traits: Array<
ComponentTrait & {
parsedType: VersionAndName;
}
>;
}
>;
spec: {
components: RuntimeComponentSchema[];
};
};

View File

@ -20,7 +20,7 @@ type ComponentSpec<
events: ReadonlyArray<KEvent>;
};
export type ComponentDefinition<
export type Component<
KMethodName extends string,
KStyleSlot extends string,
KSlot extends string,
@ -32,12 +32,12 @@ export type ComponentDefinition<
spec: ComponentSpec<KMethodName, KStyleSlot, KSlot, KEvent>;
};
export type RuntimeComponentSpec<
export type RuntimeComponent<
KMethodName extends string,
KStyleSlot extends string,
KSlot extends string,
KEvent extends string
> = ComponentDefinition<KMethodName, KStyleSlot, KSlot, KEvent> & {
> = Component<KMethodName, KStyleSlot, KSlot, KEvent> & {
parsedVersion: Version;
};
@ -46,7 +46,7 @@ export type CreateComponentOptions<
KStyleSlot extends string,
KSlot extends string,
KEvent extends string
> = Omit<ComponentDefinition<KMethodName, KStyleSlot, KSlot, KEvent>, 'kind'>;
> = Omit<Component<KMethodName, KStyleSlot, KSlot, KEvent>, 'kind'>;
export function createComponent<
KMethodName extends string,
@ -55,7 +55,7 @@ export function createComponent<
KEvent extends string
>(
options: CreateComponentOptions<KMethodName, KStyleSlot, KSlot, KEvent>
): RuntimeComponentSpec<KMethodName, KStyleSlot, KSlot, KEvent> {
): RuntimeComponent<KMethodName, KStyleSlot, KSlot, KEvent> {
return {
...options,
kind: 'Component',

View File

@ -19,18 +19,18 @@ type ModuleSpec = {
};
// extended runtime
export type RuntimeModuleSpec = Module & {
export type RuntimeModule = Module & {
parsedVersion: Version;
};
// partial some fields, use as param createModule
export type ModuleDefinition = {
type CreateModuleOptions = {
version: string;
metadata: Metadata;
spec?: Partial<ModuleSpec>;
};
export function createModule(options: ModuleDefinition): RuntimeModuleSpec {
export function createModule(options: CreateModuleOptions): RuntimeModule {
return {
version: options.version,
kind: 'Module',

View File

@ -19,33 +19,32 @@ type TraitSpec = {
};
// extended runtime
export type RuntimeTraitSpec = Trait & {
export type RuntimeTrait = Trait & {
parsedVersion: Version;
};
// partial some fields, use as param createTrait
export type TraitDefinition = {
// partial some fields, use as param createModule
type CreateTraitOptions = {
version: string;
metadata: Metadata;
spec?: Partial<TraitSpec>;
};
export function createTrait(options: TraitDefinition): RuntimeTraitSpec {
return (
{
version: options.version,
kind: ('Trait' as any),
parsedVersion: parseVersion(options.version),
metadata: {
name: options.metadata.name,
description: options.metadata.description || '',
},
spec: {
properties: {},
state: {},
methods: [],
...options.spec
},
}
);
// partial some field
export function createTrait(options: CreateTraitOptions): RuntimeTrait {
return {
version: options.version,
kind: 'Trait' as any,
parsedVersion: parseVersion(options.version),
metadata: {
name: options.metadata.name,
description: options.metadata.description || '',
},
spec: {
properties: {},
state: {},
methods: [],
...options.spec,
},
};
}

View File

@ -1,4 +1,4 @@
import { Application, ApplicationComponent } from '@sunmao-ui/core';
import { Application, ComponentSchema } from '@sunmao-ui/core';
export const AppSchema: Application = {
kind: 'Application',
@ -128,7 +128,7 @@ export const AppSchema: Application = {
},
};
export const DuplicatedIdSchema: ApplicationComponent[] = [
export const DuplicatedIdSchema: ComponentSchema[] = [
{
id: 'hstack1',
type: 'chakra_ui/v1/hstack',

View File

@ -1,6 +1,6 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
export const OrphanComponentSchema: ApplicationComponent[] = [
export const OrphanComponentSchema: ComponentSchema[] = [
{
id: 'hstack1',
type: 'chakra_ui/v1/hstack',
@ -31,7 +31,7 @@ export const OrphanComponentSchema: ApplicationComponent[] = [
},
];
export const ComponentInvalidSchema: ApplicationComponent[] = [
export const ComponentInvalidSchema: ComponentSchema[] = [
{
id: 'text1',
type: 'core/v1/text',
@ -55,7 +55,7 @@ export const ComponentInvalidSchema: ApplicationComponent[] = [
},
];
export const ComponentPropertyExpressionSchema: ApplicationComponent[] = [
export const ComponentPropertyExpressionSchema: ComponentSchema[] = [
{
id: 'text1',
type: 'chakra_ui/v1/list',
@ -67,7 +67,7 @@ export const ComponentPropertyExpressionSchema: ApplicationComponent[] = [
},
];
export const TraitInvalidSchema: ApplicationComponent[] = [
export const TraitInvalidSchema: ComponentSchema[] = [
{
id: 'text1',
type: 'core/v1/text',
@ -102,7 +102,7 @@ export const TraitInvalidSchema: ApplicationComponent[] = [
},
];
export const EventTraitSchema: ApplicationComponent[] = [
export const EventTraitSchema: ComponentSchema[] = [
{
id: 'input1',
type: 'chakra_ui/v1/input',
@ -177,7 +177,7 @@ export const EventTraitSchema: ApplicationComponent[] = [
},
];
export const EventTraitTraitMethodSchema: ApplicationComponent[] = [
export const EventTraitTraitMethodSchema: ComponentSchema[] = [
{
id: 'text1',
type: 'core/v1/text',

View File

@ -1,4 +1,4 @@
import { ApplicationComponent, parseType } from '@sunmao-ui/core';
import { ComponentSchema, parseType } from '@sunmao-ui/core';
import { ComponentModel } from './ComponentModel';
import {
ComponentId,
@ -12,11 +12,11 @@ import { genComponent } from './utils';
export class AppModel implements IAppModel {
topComponents: IComponentModel[] = [];
// modules: IModuleModel[] = [];
private schema: ApplicationComponent[] = [];
private schema: ComponentSchema[] = [];
private componentMap: Record<ComponentId, IComponentModel> = {};
private componentsCount = 0;
constructor(components: ApplicationComponent[]) {
constructor(components: ComponentSchema[]) {
this.schema = components;
this.componentsCount = components.length;
this.resolveTree(components);
@ -35,7 +35,7 @@ export class AppModel implements IAppModel {
return Object.values(this.componentMap);
}
toSchema(): ApplicationComponent[] {
toSchema(): ComponentSchema[] {
this.schema = this.allComponents.map(c => {
return c.toSchema();
});
@ -88,7 +88,7 @@ export class AppModel implements IAppModel {
return newId;
}
private resolveTree(components: ApplicationComponent[]) {
private resolveTree(components: ComponentSchema[]) {
const allComponents = components.map(c => {
if (this.componentMap[c.id as ComponentId]) {
throw new Error(`Duplicate component id: ${c.id}`);

View File

@ -1,7 +1,7 @@
import {
ApplicationComponent,
ComponentSchema,
MethodSchema,
RuntimeComponentSpec,
RuntimeComponent,
} from '@sunmao-ui/core';
import { registry } from '../setup';
import { genComponent, genTrait } from './utils';
@ -22,7 +22,7 @@ import {
} from './IAppModel';
import { TraitModel } from './TraitModel';
import { FieldModel } from './FieldModel';
type ComponentSpecModel = RuntimeComponentSpec<MethodName, StyleSlotName, SlotName, EventName>
type ComponentSpecModel = RuntimeComponent<MethodName, StyleSlotName, SlotName, EventName>
const SlotTraitType: TraitType = 'core/v1/slot' as TraitType;
export class ComponentModel implements IComponentModel {
private spec: ComponentSpecModel;
@ -37,7 +37,7 @@ export class ComponentModel implements IComponentModel {
traits: ITraitModel[] = [];
_isDirty = false;
constructor(public appModel: IAppModel, private schema: ApplicationComponent) {
constructor(public appModel: IAppModel, private schema: ComponentSchema) {
this.schema = schema;
this.id = schema.id as ComponentId;
@ -134,7 +134,7 @@ export class ComponentModel implements IComponentModel {
return result;
}
toSchema(): ApplicationComponent {
toSchema(): ComponentSchema {
if (this._isDirty) {
this._isDirty = false;
const newProperties = this.rawProperties;

View File

@ -1,4 +1,4 @@
import { ApplicationComponent, ComponentTrait, MethodSchema } from '@sunmao-ui/core';
import { ComponentSchema, TraitSchema, MethodSchema } from '@sunmao-ui/core';
export type ComponentId = string & {
kind: 'componentId';
@ -41,7 +41,7 @@ export interface IAppModel {
allComponents: IComponentModel[];
// all components, including orphan component
allComponentsWithOrphan: IComponentModel[];
toSchema(): ApplicationComponent[];
toSchema(): ComponentSchema[];
createComponent(type: ComponentType, id?: ComponentId): IComponentModel;
getComponentById(id: ComponentId): IComponentModel | undefined;
removeComponent(componentId: ComponentId): void;
@ -80,7 +80,7 @@ export interface IComponentModel {
prevSilbling: IComponentModel | null;
_isDirty: boolean;
_slotTrait: ITraitModel | null;
toSchema(): ApplicationComponent;
toSchema(): ComponentSchema;
updateComponentProperty: (property: string, value: unknown) => void;
// move component from old parent to new parent(or top level if parent is undefined).
appendTo: (parent?: IComponentModel, slot?: SlotName) => void;
@ -106,7 +106,7 @@ export interface ITraitModel {
methods: MethodSchema[];
stateKeys: StateKey[];
_isDirty: boolean;
toSchema(): ComponentTrait;
toSchema(): TraitSchema;
updateProperty: (key: string, value: any) => void;
}

View File

@ -1,4 +1,4 @@
import { ComponentTrait, RuntimeTraitSpec } from '@sunmao-ui/core';
import { TraitSchema, RuntimeTrait } from '@sunmao-ui/core';
import { registry } from '../setup';
import {
IComponentModel,
@ -14,14 +14,14 @@ import { genTrait } from './utils';
let traitIdCount = 0;
export class TraitModel implements ITraitModel {
private schema: ComponentTrait;
private spec: RuntimeTraitSpec;
private schema: TraitSchema;
private spec: RuntimeTrait;
id: TraitId;
type: TraitType;
properties: Record<string, IFieldModel> = {};
_isDirty = false;
constructor(trait: ComponentTrait, public parent: IComponentModel) {
constructor(trait: TraitSchema, public parent: IComponentModel) {
this.schema = trait;
this.parent = parent;
this.type = trait.type as TraitType;
@ -50,7 +50,7 @@ export class TraitModel implements ITraitModel {
return (this.spec ? Object.keys(this.spec.spec.state.properties || {}) : []) as StateKey[];
}
toSchema(): ComponentTrait {
toSchema(): TraitSchema {
if (this._isDirty) {
this.schema = genTrait(this.type, this.rawProperties);
}

View File

@ -1,12 +1,12 @@
import { ApplicationComponent, ComponentTrait } from '@sunmao-ui/core';
import { ComponentSchema, TraitSchema } from '@sunmao-ui/core';
import { registry } from '../setup';
export function genComponent(
type: string,
id: string,
properties?: Record<string, unknown>,
traits: ComponentTrait[] = []
): ApplicationComponent {
traits: TraitSchema[] = []
): ComponentSchema {
const cImpl = registry.getComponentByType(type);
const initProperties = properties || cImpl.metadata.exampleProperties;
return {
@ -20,7 +20,7 @@ export function genComponent(
export function genTrait(
type: string,
properties: Record<string, unknown> = {}
): ComponentTrait {
): TraitSchema {
return {
type,
properties,

View File

@ -1,5 +1,5 @@
import { observable, makeObservable, action, toJS } from 'mobx';
import { Application, ApplicationComponent } from '@sunmao-ui/core';
import { Application, ComponentSchema } from '@sunmao-ui/core';
import { ImplementedRuntimeModule } from '@sunmao-ui/runtime';
import { produce } from 'immer';
import { DefaultNewModule, EmptyAppSchema } from './constants';
@ -61,7 +61,7 @@ export class AppStorage {
type: 'app' | 'module',
version: string,
name: string,
components: ApplicationComponent[]
components: ComponentSchema[]
) {
switch (type) {
case 'app':

View File

@ -1,5 +1,5 @@
import { action, makeAutoObservable, observable, reaction, toJS } from 'mobx';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { eventBus } from './eventBus';
import { AppStorage } from './AppStorage';
import { registry, stateManager } from './setup';
@ -12,7 +12,7 @@ type EditingTarget = {
};
class EditorStore {
components: ApplicationComponent[] = [];
components: ComponentSchema[] = [];
// currentEditingComponents, it could be app's or module's components
selectedComponentId = '';
hoverComponentId = '';
@ -94,7 +94,7 @@ class EditorStore {
// origin components of app of module
// when switch app or module, components should refresh
get originComponents(): ApplicationComponent[] {
get originComponents(): ComponentSchema[] {
switch (this.currentEditingTarget.kind) {
case 'module':
const module = this.modules.find(
@ -141,7 +141,7 @@ class EditorStore {
setHoverComponentId = (val: string) => {
this.hoverComponentId = val;
};
setComponents = (val: ApplicationComponent[]) => {
setComponents = (val: ComponentSchema[]) => {
this.components = val;
};
pushDragIdStack = (val: string) => {

View File

@ -3,7 +3,7 @@ import { AddIcon } from '@chakra-ui/icons';
import { HStack, IconButton, VStack } from '@chakra-ui/react';
import { Static } from '@sinclair/typebox';
import produce from 'immer';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { EventHandlerSchema } from '@sunmao-ui/runtime';
import { eventBus } from '../../../eventBus';
import { EventHandlerForm } from './EventHandlerForm';
@ -14,7 +14,7 @@ type EventHandler = Static<typeof EventHandlerSchema>;
type Props = {
registry: Registry;
component: ApplicationComponent;
component: ComponentSchema;
};
export const EventTraitForm: React.FC<Props> = props => {

View File

@ -12,7 +12,7 @@ import { Static } from '@sinclair/typebox';
import { AddIcon, CloseIcon } from '@chakra-ui/icons';
import { useFormik } from 'formik';
import produce from 'immer';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { EventCallBackHandlerSchema, FetchTraitPropertiesSchema } from '@sunmao-ui/runtime';
import { formWrapperCSS } from '../style';
import { KeyValueEditor } from '../../KeyValueEditor';
@ -24,7 +24,7 @@ import { genOperation } from '../../../operations';
type EventHandler = Static<typeof EventCallBackHandlerSchema>;
type Props = {
component: ApplicationComponent;
component: ComponentSchema;
registry: Registry;
};

View File

@ -1,4 +1,4 @@
import { ApplicationComponent, ComponentTrait } from '@sunmao-ui/core';
import { ComponentSchema, TraitSchema } from '@sunmao-ui/core';
import { HStack, IconButton, VStack } from '@chakra-ui/react';
import { parseTypeBox } from '@sunmao-ui/runtime';
import { CloseIcon } from '@chakra-ui/icons';
@ -9,8 +9,8 @@ import { Registry } from '@sunmao-ui/runtime/lib/services/registry';
type Props = {
registry: Registry;
component: ApplicationComponent;
trait: ComponentTrait;
component: ComponentSchema;
trait: TraitSchema;
traitIndex: number;
onRemove: () => void;
};

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { parseTypeBox } from '@sunmao-ui/runtime';
import { HStack, VStack } from '@chakra-ui/react';
import { TSchema } from '@sinclair/typebox';
@ -11,7 +11,7 @@ import { genOperation } from '../../../operations';
type Props = {
registry: Registry;
component: ApplicationComponent;
component: ComponentSchema;
};
export const GeneralTraitFormList: React.FC<Props> = props => {

View File

@ -1,7 +1,7 @@
import { ComponentDefinition } from '@sunmao-ui/core';
import { Component } from '@sunmao-ui/core';
import { Registry } from '@sunmao-ui/runtime';
type Schema = ComponentDefinition<string, string, string, string>['spec']['properties'];
type Schema = Component<string, string, string, string>['spec']['properties'];
type EditorSchema = {
widget?: string;
};

View File

@ -8,7 +8,7 @@ import {
Text,
Select,
} from '@chakra-ui/react';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { Registry } from '@sunmao-ui/runtime';
import { CssEditor } from '../../../components/CodeEditor';
import { eventBus } from '../../../eventBus';
@ -19,7 +19,7 @@ import { formWrapperCSS } from '../style';
type Props = {
registry: Registry;
component: ApplicationComponent;
component: ComponentSchema;
};
type Styles = Array<{

View File

@ -1,6 +1,6 @@
import { Box } from '@chakra-ui/react';
import { css } from '@emotion/css';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import React, { useRef } from 'react';
import { eventBus } from '../eventBus';
import { genOperation } from '../operations';
@ -8,7 +8,7 @@ import { PasteManager } from '../operations/PasteManager';
type Props = {
selectedComponentId: string;
components: ApplicationComponent[];
components: ComponentSchema[];
};
export const KeyboardEventWrapper: React.FC<Props> = ({

View File

@ -1,5 +1,5 @@
import { Box, Text, VStack } from '@chakra-ui/react';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { Registry } from '@sunmao-ui/runtime/lib/services/registry';
import React, { useMemo, useState } from 'react';
import { eventBus } from '../../eventBus';
@ -10,7 +10,7 @@ import { genOperation } from '../../operations';
type Props = {
registry: Registry;
component: ApplicationComponent;
component: ComponentSchema;
childrenMap: ChildrenMap;
selectedComponentId: string;
onSelectComponent: (id: string) => void;

View File

@ -1,5 +1,5 @@
import React, { useMemo } from 'react';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { Box, Text, VStack } from '@chakra-ui/react';
import { eventBus } from '../../eventBus';
import { ComponentItemView } from './ComponentItemView';
@ -11,11 +11,11 @@ import { resolveApplicationComponents } from '../../utils/resolveApplicationComp
import ErrorBoundary from '../ErrorBoundary';
export type ChildrenMap = Map<string, SlotsMap>;
type SlotsMap = Map<string, ApplicationComponent[]>;
type SlotsMap = Map<string, ComponentSchema[]>;
type Props = {
registry: Registry;
components: ApplicationComponent[];
components: ComponentSchema[];
selectedComponentId: string;
onSelectComponent: (id: string) => void;
};
@ -24,8 +24,8 @@ export const StructureTree: React.FC<Props> = props => {
const { components, selectedComponentId, onSelectComponent, registry } = props;
const [realComponents, dataSources] = useMemo(() => {
const _realComponent: ApplicationComponent[] = [];
const _datasources: ApplicationComponent[] = [];
const _realComponent: ComponentSchema[] = [];
const _datasources: ComponentSchema[] = [];
components.forEach(c => {
if (c.type === 'core/v1/dummy') {
_datasources.push(c);

View File

@ -1,5 +1,5 @@
import mitt from 'mitt';
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { IOperation } from './operations/type';
export type EventNames = {
@ -7,9 +7,9 @@ export type EventNames = {
redo: undefined;
undo: undefined;
// when switch app or module, current components refresh
componentsRefresh: ApplicationComponent[];
componentsRefresh: ComponentSchema[];
// components change by operation
componentsChange: ApplicationComponent[];
componentsChange: ComponentSchema[];
// it is only used for some operations' side effect
selectComponent: string;
};

View File

@ -1,9 +1,9 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { eventBus } from '../eventBus';
import { IUndoRedoManager, IOperation, OperationList } from './type';
export class AppModelManager implements IUndoRedoManager {
components: ApplicationComponent[] = [];
components: ComponentSchema[] = [];
operationStack: OperationList<IOperation> = new OperationList();
constructor() {
@ -16,7 +16,7 @@ export class AppModelManager implements IUndoRedoManager {
});
}
updateComponents(components: ApplicationComponent[]) {
updateComponents(components: ComponentSchema[]) {
this.components = components;
eventBus.send('componentsChange', this.components);
}

View File

@ -1,12 +1,12 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { getComponentAndChildrens } from './util';
export class PasteManager {
rootComponentId = ''
componentsCache: ApplicationComponent[] = [];
componentsCache: ComponentSchema[] = [];
copyTimes = 0;
setPasteComponents(componentId: string, allComponents: ApplicationComponent[]) {
setPasteComponents(componentId: string, allComponents: ComponentSchema[]) {
this.rootComponentId = componentId;
const children = getComponentAndChildrens(componentId, allComponents);
this.componentsCache = [...children];

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import produce from 'immer';
import { ComponentId, SlotName } from '../../AppModel/IAppModel';
import {
@ -17,7 +17,7 @@ export type CreateComponentBranchOperationContext = {
};
export class CreateComponentBranchOperation extends BaseBranchOperation<CreateComponentBranchOperationContext> {
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
// gen component id
if (!this.context.componentId) {
this.context.componentId = genId(this.context.componentType, prev);

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { BaseBranchOperation } from '../type';
import {
ModifyComponentIdLeafOperation,
@ -11,7 +11,7 @@ export type ModifyComponentIdBranchOperationContext = {
};
export class ModifyComponentIdBranchOperation extends BaseBranchOperation<ModifyComponentIdBranchOperationContext> {
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
this.operationStack.insert(new ModifyComponentIdLeafOperation(this.context));
// update selectid

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { BaseBranchOperation } from '../type';
import { CreateTraitLeafOperation, ModifyTraitPropertiesLeafOperation, RemoveTraitLeafOperation } from '../leaf';
@ -9,7 +9,7 @@ export type MoveComponentBranchOperationContext = {
};
export class MoveComponentBranchOperation extends BaseBranchOperation<MoveComponentBranchOperationContext> {
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const from = prev.find(c => c.id === this.context.fromId);
if (!from) return prev;

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import produce from 'immer';
import { AppModel } from '../../AppModel/AppModel';
import { ComponentId } from '../../AppModel/IAppModel';
@ -13,7 +13,7 @@ export type RemoveComponentBranchOperationContext = {
};
export class RemoveComponentBranchOperation extends BaseBranchOperation<RemoveComponentBranchOperationContext> {
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const parent = appModel.getComponentById(this.context.componentId as ComponentId);

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -8,18 +8,18 @@ export type AdjustComponentOrderLeafOperationContext = {
};
export class AdjustComponentOrderLeafOperation extends BaseLeafOperation<AdjustComponentOrderLeafOperationContext> {
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
return this.move(prev, this.context.orientation);
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev)
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
return this.move(prev, this.context.orientation === 'up' ? 'down' : 'up');
}
private move(prev: ApplicationComponent[], orientation: 'up' | 'down'): ApplicationComponent[] {
private move(prev: ComponentSchema[], orientation: 'up' | 'down'): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId, ComponentType, IComponentModel, SlotName } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -13,7 +13,7 @@ export type CreateComponentLeafOperationContext = {
export class CreateComponentLeafOperation extends BaseLeafOperation<CreateComponentLeafOperationContext> {
private component!: IComponentModel;
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.createComponent(this.context.componentType as ComponentType, this.context.componentId as ComponentId);
if (this.context.parentId) {
@ -29,11 +29,11 @@ export class CreateComponentLeafOperation extends BaseLeafOperation<CreateCompon
return newSchema
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev)
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
appModel.removeComponent(this.component.id)
return appModel.toSchema()

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -9,7 +9,7 @@ export type ModifyComponentIdLeafOperationContext = {
};
export class ModifyComponentIdLeafOperation extends BaseLeafOperation<ModifyComponentIdLeafOperationContext> {
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {
@ -19,10 +19,10 @@ export class ModifyComponentIdLeafOperation extends BaseLeafOperation<ModifyComp
component.changeId(this.context.newId as ComponentId);
return appModel.toSchema();
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev);
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.newId as ComponentId)!;
component.changeId(this.context.componentId as ComponentId);

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { BaseLeafOperation } from '../../type';
import _ from 'lodash-es';
import { AppModel } from '../../../AppModel/AppModel';
@ -10,7 +10,7 @@ export type ModifyComponentPropertiesLeafOperationContext = {
export class ModifyComponentPropertiesLeafOperation extends BaseLeafOperation<ModifyComponentPropertiesLeafOperationContext> {
private previousState: Record<string, any> = {};
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (component) {
@ -34,7 +34,7 @@ export class ModifyComponentPropertiesLeafOperation extends BaseLeafOperation<Mo
const newSchema = appModel.toSchema();
return newSchema;
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {
@ -47,7 +47,7 @@ export class ModifyComponentPropertiesLeafOperation extends BaseLeafOperation<Mo
}
return appModel.toSchema();
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId, IComponentModel, SlotName } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -7,14 +7,14 @@ export type PasteComponentLeafOperationContext = {
parentId: string;
slot: string;
rootComponentId: string;
components: ApplicationComponent[];
components: ComponentSchema[];
copyTimes: number;
};
export class PasteComponentLeafOperation extends BaseLeafOperation<PasteComponentLeafOperationContext> {
private componentCopy!: IComponentModel
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const targetParent = appModel.getComponentById(this.context.parentId as ComponentId);
if (!targetParent) {
@ -34,11 +34,11 @@ export class PasteComponentLeafOperation extends BaseLeafOperation<PasteComponen
return appModel.toSchema();
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev)
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
appModel.removeComponent(this.componentCopy.id);
return appModel.toSchema()

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId, IComponentModel, SlotName } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -11,7 +11,7 @@ export class RemoveComponentLeafOperation extends BaseLeafOperation<RemoveCompon
private deletedComponent?: IComponentModel;
private prevComponent?: IComponentModel;
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
this.deletedComponent = appModel.getComponentById(
this.context.componentId as ComponentId
@ -21,11 +21,11 @@ export class RemoveComponentLeafOperation extends BaseLeafOperation<RemoveCompon
return appModel.toSchema();
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev);
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
if (!this.deletedComponent) {
return prev;
}

View File

@ -1,27 +1,27 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import produce from 'immer';
import { BaseLeafOperation } from '../type';
export type ReplaceAppLeafOperationContext = {
app: ApplicationComponent[];
app: ComponentSchema[];
};
export class ReplaceAppLeafOperation extends BaseLeafOperation<ReplaceAppLeafOperationContext> {
private previousState!: ApplicationComponent[];
do(prev: ApplicationComponent[]): ApplicationComponent[] {
private previousState!: ComponentSchema[];
do(prev: ComponentSchema[]): ComponentSchema[] {
this.previousState = prev;
return produce(prev, () => {
return this.context.app;
});
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return produce(prev, () => {
return this.context.app;
});
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
return produce(prev, () => {
return this.previousState;
});

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId, TraitId, TraitType } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -12,7 +12,7 @@ export type CreateTraitLeafOperationContext = {
export class CreateTraitLeafOperation extends BaseLeafOperation<CreateTraitLeafOperationContext> {
private traitId!: TraitId;
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {
@ -23,11 +23,11 @@ export class CreateTraitLeafOperation extends BaseLeafOperation<CreateTraitLeafO
return appModel.toSchema()
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev);
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import _ from 'lodash-es';
import { BaseLeafOperation } from '../../type';
import { AppModel } from '../../../AppModel/AppModel';
@ -12,7 +12,7 @@ export type ModifyTraitPropertiesLeafOperationContext = {
export class ModifyTraitPropertiesLeafOperation extends BaseLeafOperation<ModifyTraitPropertiesLeafOperationContext> {
private previousState: Record<string, any> = {};
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {
@ -34,7 +34,7 @@ export class ModifyTraitPropertiesLeafOperation extends BaseLeafOperation<Modify
return appModel.toSchema();
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {
@ -50,7 +50,7 @@ export class ModifyTraitPropertiesLeafOperation extends BaseLeafOperation<Modify
return appModel.toSchema();
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { AppModel } from '../../../AppModel/AppModel';
import { ComponentId, ITraitModel } from '../../../AppModel/IAppModel';
import { BaseLeafOperation } from '../../type';
@ -10,7 +10,7 @@ export type RemoveTraitLeafOperationContext = {
export class RemoveTraitLeafOperation extends BaseLeafOperation<RemoveTraitLeafOperationContext> {
private deletedTrait!: ITraitModel;
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {
@ -23,11 +23,11 @@ export class RemoveTraitLeafOperation extends BaseLeafOperation<RemoveTraitLeafO
return appModel.toSchema();
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev);
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
const appModel = new AppModel(prev);
const component = appModel.getComponentById(this.context.componentId as ComponentId);
if (!component) {

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { eventBus } from '../../eventBus';
import { BaseLeafOperation } from '../type';
@ -9,7 +9,7 @@ export type UpdateSelectComponentLeafOperationContext = {
export class UpdateSelectComponentLeafOperation extends BaseLeafOperation<UpdateSelectComponentLeafOperationContext> {
private prevId!: string;
do(prev: ApplicationComponent[]): ApplicationComponent[] {
do(prev: ComponentSchema[]): ComponentSchema[] {
this.prevId = this.context.componentId || prev[0].id;
setTimeout(() => {
eventBus.send('selectComponent', this.context.newId);
@ -17,14 +17,14 @@ export class UpdateSelectComponentLeafOperation extends BaseLeafOperation<Update
return prev;
}
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
setTimeout(() => {
eventBus.send('selectComponent', this.context.newId);
});
return prev;
}
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
setTimeout(() => {
eventBus.send('selectComponent', this.prevId);
});

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
export const leafSymbol = Symbol('leaf');
export const branchSymbol = Symbol('branch');
@ -130,9 +130,9 @@ export interface IOperation<TContext = any> extends IUndoRedo {
* infer the type of operation, leaf or branch
*/
type: symbol;
do(prev: ApplicationComponent[]): ApplicationComponent[];
redo(prev: ApplicationComponent[]): ApplicationComponent[];
undo(prev: ApplicationComponent[]): ApplicationComponent[];
do(prev: ComponentSchema[]): ComponentSchema[];
redo(prev: ComponentSchema[]): ComponentSchema[];
undo(prev: ComponentSchema[]): ComponentSchema[];
}
/**
@ -150,13 +150,13 @@ export abstract class BaseLeafOperation<TContext> implements IOperation<TContext
* @param prev prev application schema
* @returns changed application schema
*/
abstract do(prev: ApplicationComponent[]): ApplicationComponent[];
abstract do(prev: ComponentSchema[]): ComponentSchema[];
/**
* for leaf operation, most time redo is the same as do, override it if not
* @param prev prev application schema
* @returns changed application schema
*/
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.do(prev);
}
/**
@ -164,7 +164,7 @@ export abstract class BaseLeafOperation<TContext> implements IOperation<TContext
* @param prev prev application schema
* @returns changed application schema
*/
abstract undo(prev: ApplicationComponent[]): ApplicationComponent[];
abstract undo(prev: ComponentSchema[]): ComponentSchema[];
static isLeafOperation<T>(op: IOperation<T>): op is BaseLeafOperation<T> {
return op.type === leafSymbol;
@ -191,14 +191,14 @@ export abstract class BaseBranchOperation<TContext>
* @param prev prev application schema
* @returns changed application schema
*/
abstract do(prev: ApplicationComponent[]): ApplicationComponent[];
abstract do(prev: ComponentSchema[]): ComponentSchema[];
/**
* for branch operation, redo is the same as do
* @param prev prev application schema
* @returns changed application schema
*/
redo(prev: ApplicationComponent[]): ApplicationComponent[] {
redo(prev: ComponentSchema[]): ComponentSchema[] {
return this.operationStack.reduce((prev, node) => {
prev = node.redo(prev);
return prev;
@ -211,7 +211,7 @@ export abstract class BaseBranchOperation<TContext>
* @param prev prev application schema
* @returns changed application schema
*/
undo(prev: ApplicationComponent[]): ApplicationComponent[] {
undo(prev: ComponentSchema[]): ComponentSchema[] {
return this.operationStack.reduceRight((prev, node) => {
prev = node.undo(prev);
return prev;

View File

@ -1,9 +1,9 @@
import { ApplicationComponent, parseType } from '@sunmao-ui/core';
import { ComponentSchema, parseType } from '@sunmao-ui/core';
import { isDraft, original } from 'immer';
import { get } from 'lodash-es';
import { registry } from '../setup';
export function genComponent(type: string, id: string): ApplicationComponent {
export function genComponent(type: string, id: string): ComponentSchema {
const { version, name } = parseType(type);
const cImpl = registry.getComponent(version, name);
const initProperties = cImpl.metadata.exampleProperties;
@ -15,7 +15,7 @@ export function genComponent(type: string, id: string): ApplicationComponent {
};
}
export function genId(componentType: string, components: ApplicationComponent[]): string {
export function genId(componentType: string, components: ComponentSchema[]): string {
const { name } = parseType(componentType);
const componentsCount = components.filter(
component => component.type === componentType
@ -29,13 +29,13 @@ export function tryOriginal<T>(val: T): T {
export function getComponentAndChildrens(
componentId: string,
allComponents: ApplicationComponent[]
): ApplicationComponent[] {
allComponents: ComponentSchema[]
): ComponentSchema[] {
const target = allComponents.find(c => c.id === componentId);
if (!target) {
return [];
}
return allComponents.reduce<ApplicationComponent[]>(
return allComponents.reduce<ComponentSchema[]>(
(result, component) => {
const slotTrait = component.traits.find(trait => trait.type === 'core/v1/slot');
const slotId = get(slotTrait, 'properties.container.id');

View File

@ -1,13 +1,13 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
export type ChildrenMap = Map<string, SlotsMap>;
type SlotsMap = Map<string, ApplicationComponent[]>;
type SlotsMap = Map<string, ComponentSchema[]>;
export function resolveApplicationComponents(components: ApplicationComponent[]): {
topLevelComponents: ApplicationComponent[];
export function resolveApplicationComponents(components: ComponentSchema[]): {
topLevelComponents: ComponentSchema[];
childrenMap: ChildrenMap;
} {
const topLevelComponents: ApplicationComponent[] = [];
const topLevelComponents: ComponentSchema[] = [];
const childrenMap: ChildrenMap = new Map();
components.forEach(c => {
const slotTrait = c.traits.find(t => t.type === 'core/v1/slot');

View File

@ -1,4 +1,4 @@
import { ApplicationComponent, RuntimeComponentSpec } from '@sunmao-ui/core';
import { ComponentSchema, RuntimeComponent } from '@sunmao-ui/core';
import { Registry } from '@sunmao-ui/runtime';
import Ajv from 'ajv';
import { AppModel } from '../AppModel/AppModel';
@ -20,7 +20,7 @@ export class SchemaValidator implements ISchemaValidator {
private allComponentsRules: AllComponentsValidatorRule[] = [];
private componentIdSpecMap: Record<
string,
RuntimeComponentSpec<string, string, string, string>
RuntimeComponent<string, string, string, string>
> = {};
private ajv!: Ajv;
private validatorMap!: ValidatorMap;
@ -46,7 +46,7 @@ export class SchemaValidator implements ISchemaValidator {
});
}
validate(components: ApplicationComponent[]) {
validate(components: ComponentSchema[]) {
const appModel = new AppModel(components);
this.genComponentIdSpecMap(components);
this.result = [];
@ -90,7 +90,7 @@ export class SchemaValidator implements ISchemaValidator {
return this.result;
}
genComponentIdSpecMap(components: ApplicationComponent[]) {
genComponentIdSpecMap(components: ComponentSchema[]) {
components.forEach(c => {
this.componentIdSpecMap[c.id] = this.registry.getComponentByType(c.type);
});

View File

@ -1,4 +1,4 @@
import { ApplicationComponent } from '@sunmao-ui/core';
import { ComponentSchema } from '@sunmao-ui/core';
import { Registry } from '@sunmao-ui/runtime';
import Ajv, { ValidateFunction } from 'ajv';
import { IAppModel, IComponentModel, ITraitModel } from '../AppModel/IAppModel';
@ -55,7 +55,7 @@ export type ValidatorRule =
export interface ISchemaValidator {
addRules: (rule: ValidatorRule[]) => void;
validate: (components: ApplicationComponent[]) => ValidateErrorResult[];
validate: (components: ComponentSchema[]) => ValidateErrorResult[];
fix?: () => void;
}

View File

@ -1,7 +1,7 @@
import React, { useRef } from 'react';
import { initStateAndMethod } from './utils/initStateAndMethod';
import { ImplWrapper } from './components/_internal/ImplWrapper';
import { AppProps, UIServices } from './types/RuntimeSchema';
import { AppProps, UIServices } from './types';
import { DebugEvent, DebugStore } from './services/DebugComponents';
import { RuntimeAppSchemaManager } from './services/RuntimeAppSchemaManager';
import { resolveChildrenMap } from './utils/resolveChildrenMap';

View File

@ -1,18 +1,13 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { merge } from 'lodash-es';
import { RuntimeComponentSchema, RuntimeTraitSchema } from '@sunmao-ui/core';
import { watch } from '../../utils/watchReactivity';
import {
RuntimeApplicationComponent,
ImplWrapperProps,
TraitResult,
} from '../../types/RuntimeSchema';
} from '../../types';
import { shallowCompareArray } from '../../utils/shallowCompareArray';
type ArrayElement<ArrayType extends readonly unknown[]> =
ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
type ApplicationTrait = ArrayElement<RuntimeApplicationComponent['traits']>;
const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props, ref) => {
const {
component: c,
@ -23,7 +18,7 @@ const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props,
childrenMap,
} = props;
const { registry, stateManager, globalHandlerMap, apiService } = props.services;
const childrenCache = new Map<RuntimeApplicationComponent, React.ReactElement>();
const childrenCache = new Map<RuntimeComponentSchema, React.ReactElement>();
const Impl = registry.getComponent(c.parsedType.version, c.parsedType.name).impl;
@ -65,7 +60,7 @@ const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props,
);
const excecuteTrait = useCallback(
(trait: ApplicationTrait, traitProperty: ApplicationTrait['properties']) => {
(trait: RuntimeTraitSchema, traitProperty: RuntimeTraitSchema['properties']) => {
const tImpl = registry.getTrait(
trait.parsedType.version,
trait.parsedType.name
@ -91,7 +86,7 @@ const _ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>((props,
// eval traits' properties then excecute traits
useEffect(() => {
const stops: ReturnType<typeof watch>[] = [];
const properties: Array<ApplicationTrait['properties']> = [];
const properties: Array<RuntimeTraitSchema['properties']> = [];
c.traits.forEach((t, i) => {
const { result, stop } = stateManager.deepEval(
t.properties,

View File

@ -2,19 +2,19 @@ import { Static } from '@sinclair/typebox';
import React, { useCallback, useEffect, useMemo } from 'react';
import { get } from 'lodash-es';
import { useDeepCompareMemo } from 'use-deep-compare';
import { Application, parseType, RuntimeApplication } from '@sunmao-ui/core';
import {
UIServices,
RuntimeModuleSchema,
RuntimeApplicationComponent,
} from '../../types/RuntimeSchema';
import { EventHandlerSchema } from '../../types/TraitPropertiesSchema';
Application,
parseType,
RuntimeApplication,
RuntimeComponentSchema,
} from '@sunmao-ui/core';
import { UIServices, ModuleSchema } from '../../types';
import { ImplWrapper } from './ImplWrapper';
import { watch } from '../../utils/watchReactivity';
import { ImplementedRuntimeModule } from '../../services/registry';
import { ImplementedRuntimeModule, EventHandlerSchema } from '../../types';
import { resolveChildrenMap } from '../../utils/resolveChildrenMap';
type Props = Static<typeof RuntimeModuleSchema> & {
type Props = Static<typeof ModuleSchema> & {
evalScope?: Record<string, any>;
services: UIServices;
app?: RuntimeApplication;
@ -30,144 +30,141 @@ export const ModuleRenderer: React.FC<Props> = props => {
}
};
const ModuleRendererContent: React.FC<Props & { moduleSpec: ImplementedRuntimeModule }> =
props => {
const { moduleSpec, properties, handlers, evalScope, services, app } = props;
const moduleId = services.stateManager.maskedEval(
props.id,
true,
evalScope
) as string;
const ModuleRendererContent: React.FC<
Props & { moduleSpec: ImplementedRuntimeModule }
> = props => {
const { moduleSpec, properties, handlers, evalScope, services, app } = props;
const moduleId = services.stateManager.maskedEval(props.id, true, evalScope) as string;
function evalObject<T extends Record<string, any>>(obj: T): T {
function evalObject<T extends Record<string, any>>(obj: T): T {
return services.stateManager.mapValuesDeep({ obj }, ({ value }) => {
if (typeof value === 'string') {
return services.stateManager.maskedEval(value, true, evalScope);
}
return value;
}).obj;
}
const evalWithScope = useCallback(
<T extends Record<string, any>>(obj: T, scope: Record<string, any>): T => {
const hasScopeKey = (exp: string) => {
return Object.keys(scope).some(key => exp.includes('{{') && exp.includes(key));
};
return services.stateManager.mapValuesDeep({ obj }, ({ value }) => {
if (typeof value === 'string') {
return services.stateManager.maskedEval(value, true, evalScope);
if (typeof value === 'string' && hasScopeKey(value)) {
return services.stateManager.maskedEval(value, true, scope);
}
return value;
}).obj;
},
[services.stateManager]
);
// first eval the property, handlers, id of module
const evaledProperties = evalObject(properties);
const evaledHanlders = evalObject(handlers);
const parsedtemplete = useMemo(
() => moduleSpec.impl.map(parseTypeComponents),
[moduleSpec]
);
// then eval the template and stateMap of module
const evaledStateMap = useMemo(() => {
// stateMap only use state i
return evalWithScope(moduleSpec.spec.stateMap, { $moduleId: moduleId });
}, [evalWithScope, moduleSpec.spec.stateMap, moduleId]);
const evaledModuleTemplate = useDeepCompareMemo(() => {
// here should only eval with evaledProperties, any other key not in evaledProperties should be ignored
// so we can asumme that template will not change if evaledProperties is the same
return evalWithScope(parsedtemplete, {
...evaledProperties,
$moduleId: moduleId,
});
}, [parsedtemplete, evaledProperties, moduleId]);
// listen component state change
useEffect(() => {
if (!evaledStateMap) return;
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(
services.stateManager.store,
evaledStateMap[stateKey]
);
// watch state
const stop = watch(
() => {
return get(services.stateManager.store, evaledStateMap[stateKey]);
},
newV => {
services.stateManager.store[moduleId] = {
...services.stateManager.store[moduleId],
[stateKey]: newV,
};
}
);
stops.push(stop);
}
const evalWithScope = useCallback(
<T extends Record<string, any>>(obj: T, scope: Record<string, any>): T => {
const hasScopeKey = (exp: string) => {
return Object.keys(scope).some(key => exp.includes('{{') && exp.includes(key));
};
return services.stateManager.mapValuesDeep({ obj }, ({ value }) => {
if (typeof value === 'string' && hasScopeKey(value)) {
return services.stateManager.maskedEval(value, true, scope);
}
return value;
}).obj;
},
[services.stateManager]
);
return () => {
stops.forEach(s => s());
};
}, [evaledStateMap, moduleId, services]);
// first eval the property, handlers, id of module
const evaledProperties = evalObject(properties);
const evaledHanlders = evalObject(handlers);
const parsedtemplete = useMemo(
() => moduleSpec.impl.map(parseTypeComponents),
[moduleSpec]
);
// then eval the template and stateMap of module
const evaledStateMap = useMemo(() => {
// stateMap only use state i
return evalWithScope(moduleSpec.spec.stateMap, { $moduleId: moduleId });
}, [evalWithScope, moduleSpec.spec.stateMap, moduleId]);
const evaledModuleTemplate = useDeepCompareMemo(() => {
// here should only eval with evaledProperties, any other key not in evaledProperties should be ignored
// so we can asumme that template will not change if evaledProperties is the same
return evalWithScope(parsedtemplete, {
...evaledProperties,
$moduleId: moduleId,
});
}, [parsedtemplete, evaledProperties, moduleId]);
// listen component state change
useEffect(() => {
if (!evaledStateMap) return;
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(
services.stateManager.store,
evaledStateMap[stateKey]
);
// watch state
const stop = watch(
() => {
return get(services.stateManager.store, evaledStateMap[stateKey]);
},
newV => {
services.stateManager.store[moduleId] = {
...services.stateManager.store[moduleId],
[stateKey]: newV,
};
}
);
stops.push(stop);
}
return () => {
stops.forEach(s => s());
// listen module event
useEffect(() => {
if (!evaledHanlders) return;
const _handlers = evaledHanlders as Array<Static<typeof EventHandlerSchema>>;
const moduleEventHanlders: any[] = [];
_handlers.forEach(h => {
const moduleEventHanlder = ({ fromId, eventType }: Record<string, string>) => {
if (eventType === h.type && fromId === moduleId) {
services.apiService.send('uiMethod', {
componentId: h.componentId,
name: h.method.name,
parameters: h.method.parameters,
});
}
};
}, [evaledStateMap, moduleId, services]);
services.apiService.on('moduleEvent', moduleEventHanlder);
moduleEventHanlders.push(moduleEventHanlder);
});
// listen module event
useEffect(() => {
if (!evaledHanlders) return;
const _handlers = evaledHanlders as Array<Static<typeof EventHandlerSchema>>;
const moduleEventHanlders: any[] = [];
_handlers.forEach(h => {
const moduleEventHanlder = ({ fromId, eventType }: Record<string, string>) => {
if (eventType === h.type && fromId === moduleId) {
services.apiService.send('uiMethod', {
componentId: h.componentId,
name: h.method.name,
parameters: h.method.parameters,
});
}
};
services.apiService.on('moduleEvent', moduleEventHanlder);
moduleEventHanlders.push(moduleEventHanlder);
return () => {
moduleEventHanlders.forEach(h => {
services.apiService.off('moduleEvent', h);
});
};
}, [evaledHanlders, moduleId, services.apiService]);
return () => {
moduleEventHanlders.forEach(h => {
services.apiService.off('moduleEvent', h);
});
};
}, [evaledHanlders, moduleId, services.apiService]);
const result = useMemo(() => {
const { childrenMap, topLevelComponents } = resolveChildrenMap(evaledModuleTemplate);
return topLevelComponents.map(c => {
return (
<ImplWrapper
key={c.id}
component={c}
services={services}
app={app}
childrenMap={childrenMap}
/>
);
});
}, [evaledModuleTemplate, services, app]);
const result = useMemo(() => {
const { childrenMap, topLevelComponents } = resolveChildrenMap(evaledModuleTemplate);
return topLevelComponents.map(c => {
return (
<ImplWrapper
key={c.id}
component={c}
services={services}
app={app}
childrenMap={childrenMap}
/>
);
});
}, [evaledModuleTemplate, services, app]);
return <>{result}</>;
};
return <>{result}</>;
};
function parseTypeComponents(
c: Application['spec']['components'][0]
): RuntimeApplicationComponent {
): RuntimeComponentSchema {
return {
...c,
parsedType: parseType(c.type),

View File

@ -1,5 +1,5 @@
import { implementRuntimeComponent } from '../../utils/buildKit';
import { RuntimeModuleSchema } from '../../types/RuntimeSchema';
import { ModuleSchema } from '../../types';
import { ModuleRenderer } from '../_internal/ModuleRenderer';
export default implementRuntimeComponent({
@ -17,7 +17,7 @@ export default implementRuntimeComponent({
exampleSize: [6, 6],
},
spec: {
properties: RuntimeModuleSchema,
properties: ModuleSchema,
state: {},
methods: {},
slots: [],

View File

@ -22,10 +22,10 @@ import {
useNavigate,
} from './hooks';
import {
RuntimeApplicationComponent,
UIServices,
ChildrenMap,
} from '../../../types/RuntimeSchema';
} from '../../../types';
import { RuntimeComponentSchema } from '@sunmao-ui/core';
export type RouteLikeElement = PropsWithChildren<{
path?: string;
@ -63,7 +63,7 @@ export const Route: React.FC<RouteProps> = ({ match, children, mergeState }) =>
type SwitchProps = {
location?: string;
switchPolicy: SwitchPolicy;
component: RuntimeApplicationComponent;
component: RuntimeComponentSchema;
childrenMap: ChildrenMap<string>;
services: UIServices;
slotsElements: Record<string, ReactElement[]>;

View File

@ -25,7 +25,7 @@ export function initSunmaoUI(dependencies = {}) {
export * from './utils/parseTypeBox';
export * from './utils/buildKit';
export * from './utils/encodeDragDataTransfer';
export * from './types/RuntimeSchema';
export * from './types';
export * from './types/TraitPropertiesSchema';
export * from './constants';
export * from './services/registry';

View File

@ -1,15 +1,15 @@
import {
Application,
ApplicationComponent,
ComponentSchema,
RuntimeApplication,
isValidId,
parseType,
parseVersion,
RuntimeComponentSchema,
} from '@sunmao-ui/core';
import { RuntimeApplicationComponent } from '../types/RuntimeSchema';
export class RuntimeAppSchemaManager {
private runtimeComponentsCache: Record<string, RuntimeApplicationComponent> = {};
private componentsCache: Record<string, ApplicationComponent> = {};
private runtimeComponentsCache: Record<string, RuntimeComponentSchema> = {};
private componentsCache: Record<string, ComponentSchema> = {};
update(schema: Application): RuntimeApplication {
return {
@ -25,7 +25,7 @@ export class RuntimeAppSchemaManager {
};
}
genComponent(component: ApplicationComponent): RuntimeApplicationComponent {
genComponent(component: ComponentSchema): RuntimeComponentSchema {
const componentInCache = this.componentsCache[component.id];
if (componentInCache && componentInCache === component) {
return this.runtimeComponentsCache[component.id];
@ -33,7 +33,7 @@ export class RuntimeAppSchemaManager {
if (!isValidId(component.id)) {
throw new Error(`Invalid id: "${component.id}"`);
}
const componentSchema: RuntimeApplicationComponent = {
const componentSchema: RuntimeComponentSchema = {
...component,
parsedType: parseType(component.type),
traits: component.traits.map(t => {

View File

@ -1,6 +1,6 @@
type HandlerMap = Record<string, (parameters?: any) => void>;
export type GlobalHandlerMap = ReturnType<typeof initGlobalHandlerMap>;
export type GlobalHandlerMap = Map<string, HandlerMap>;
export function initGlobalHandlerMap() {
return new Map<string, HandlerMap>();

View File

@ -1,10 +1,4 @@
import {
RuntimeTraitSpec,
RuntimeModuleSpec,
ApplicationComponent,
RuntimeComponentSpec,
parseType,
} from '@sunmao-ui/core';
import { parseType } from '@sunmao-ui/core';
// components
/* --- plain --- */
import PlainButton from '../components/plain/Button';
@ -24,40 +18,13 @@ import CoreHidden from '../traits/core/hidden';
import CoreFetch from '../traits/core/fetch';
import CoreValidation from '../traits/core/validation';
import {
ComponentImplementationProps,
TraitImplementation,
} from '../types/RuntimeSchema';
ImplementedRuntimeComponent,
ImplementedRuntimeTrait,
ImplementedRuntimeModule,
} from '../types';
import { parseModuleSchema } from '../utils/parseModuleSchema';
import { cloneDeep } from 'lodash-es';
export type ImplementedRuntimeComponent<
KMethodName extends string,
KStyleSlot extends string,
KSlot extends string,
KEvent extends string
> = RuntimeComponentSpec<KMethodName, KStyleSlot, KSlot, KEvent> & {
impl: ComponentImplementation;
};
export type ComponentImplementation<
TProps = any,
TState = any,
TMethods = Record<string, any>,
KSlot extends string = string,
KStyleSlot extends string = string,
KEvent extends string = string
> = React.FC<
TProps & ComponentImplementationProps<TState, TMethods, KSlot, KStyleSlot, KEvent>
>;
export type ImplementedRuntimeTrait = RuntimeTraitSpec & {
impl: TraitImplementation;
};
export type ImplementedRuntimeModule = RuntimeModuleSpec & {
impl: ApplicationComponent[];
};
export type SunmaoLib = {
components?: ImplementedRuntimeComponent<string, string, string, string>[];
traits?: ImplementedRuntimeTrait[];

View File

@ -1,12 +1,12 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { TraitImplementation } from '../../types/RuntimeSchema';
import { TraitImpl } from '../../types';
const HasInitializedMap = new Map<string, boolean>();
type KeyValue = { key: string; value: unknown };
const ArrayStateTrait: TraitImplementation<Static<typeof PropsSchema>> = ({
const ArrayStateTrait: TraitImpl<Static<typeof PropsSchema>> = ({
key,
initialValue,
componentId,
@ -130,6 +130,7 @@ export default {
name: 'reset',
},
],
state: {},
},
}),
impl: ArrayStateTrait,

View File

@ -1,10 +1,10 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { debounce, throttle, delay } from 'lodash-es';
import { CallbackMap, TraitImplementation } from '../../types/RuntimeSchema';
import { CallbackMap, TraitImpl } from '../../types';
import { EventHandlerSchema } from '../../types/TraitPropertiesSchema';
const useEventTrait: TraitImplementation<Static<typeof PropsSchema>> = ({
const useEventTrait: TraitImpl<Static<typeof PropsSchema>> = ({
handlers,
services,
}) => {
@ -77,6 +77,8 @@ export default {
},
spec: {
properties: PropsSchema,
methods: [],
state: {},
},
}),
impl: useEventTrait,

View File

@ -1,11 +1,11 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { TraitImplementation } from '../../types/RuntimeSchema';
import { TraitImpl } from '../../types';
import { FetchTraitPropertiesSchema } from '../../types/TraitPropertiesSchema';
const hasFetchedMap = new Map<string, boolean>();
const useFetchTrait: TraitImplementation<Static<typeof FetchTraitPropertiesSchema>> = ({
const useFetchTrait: TraitImpl<Static<typeof FetchTraitPropertiesSchema>> = ({
url,
method,
lazy: _lazy,

View File

@ -1,8 +1,8 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { TraitImplementation } from '../../types/RuntimeSchema';
import { TraitImpl } from '../../types';
const useHiddenTrait: TraitImplementation<Static<typeof PropsSchema>> = ({
const useHiddenTrait: TraitImpl<Static<typeof PropsSchema>> = ({
hidden,
visually,
}) => {
@ -36,6 +36,8 @@ export default {
},
spec: {
properties: PropsSchema,
state: {},
methods: [],
},
}),
impl: useHiddenTrait,

View File

@ -19,6 +19,8 @@ export default {
},
spec: {
properties: PropsSchema,
state: {},
methods: [],
},
}),
impl: () => ({

View File

@ -1,12 +1,12 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { TraitImplementation } from '../../types/RuntimeSchema';
import { TraitImpl } from '../../types';
const HasInitializedMap = new Map<string, boolean>();
type KeyValue = { key: string; value: unknown };
const useStateTrait: TraitImplementation<Static<typeof PropsSchema>> = ({
const useStateTrait: TraitImpl<Static<typeof PropsSchema>> = ({
key,
initialValue,
componentId,

View File

@ -1,8 +1,8 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { TraitImplementation } from '../../types/RuntimeSchema';
import { TraitImpl } from '../../types';
const StyleTrait: TraitImplementation<Static<typeof PropsSchema>> = ({ styles }) => {
const StyleTrait: TraitImpl<Static<typeof PropsSchema>> = ({ styles }) => {
const customStyle: Record<string, string> = {};
styles.forEach(style => {
customStyle[style.styleSlot] = style.style;
@ -32,6 +32,8 @@ export default {
},
spec: {
properties: PropsSchema,
methods: [],
state: {},
},
}),
impl: StyleTrait,

View File

@ -1,7 +1,7 @@
import { createTrait } from '@sunmao-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { isEqual } from 'lodash-es';
import { TraitImplementation } from '../../types/RuntimeSchema';
import { TraitImpl } from '../../types';
import { ValidResultSchema } from '../../types/ValidResultSchema';
type ValidationResult = Static<typeof ValidResultSchema>;
@ -43,7 +43,7 @@ addValidationRule('phoneNumber', text => {
const ValidationResultCache: Record<string, ValidationResult> = {};
const ValidationTraitImpl: TraitImplementation<Static<typeof PropsSchema>> = props => {
const ValidationTraitImpl: TraitImpl<Static<typeof PropsSchema>> = props => {
const { value, minLength, maxLength, mergeState, componentId, rule } = props;
const result: ValidationResult = {
@ -103,6 +103,7 @@ export default {
state: Type.Object({
validResult: ValidResultSchema,
}),
methods: [],
},
}),
impl: ValidationTraitImpl,

View File

@ -0,0 +1,38 @@
import RGL from 'react-grid-layout';
import { ApiService } from '../services/apiService';
import { GlobalHandlerMap } from '../services/handler';
import { Registry } from '../services/registry';
import { StateManager } from '../services/stateStore';
import { Application, RuntimeComponentSchema } from '@sunmao-ui/core';
import React from 'react';
export type UIServices = {
registry: Registry;
stateManager: StateManager;
globalHandlerMap: GlobalHandlerMap;
apiService: ApiService;
};
export type ComponentWrapperProps = {
parentType: string;
component: RuntimeComponentSchema;
};
export type ComponentWrapperType = React.FC<ComponentWrapperProps>;
export type GridCallbacks = {
onDragStop?: (id: string, layout: RGL.Layout[]) => void;
onDrop?: (id: string, layout: RGL.Layout[], item: RGL.Layout, event: DragEvent) => void;
};
export type ComponentParamsFromApp = {
gridCallbacks?: GridCallbacks;
componentWrapper?: ComponentWrapperType;
};
export type AppProps = {
options: Application;
services: UIServices;
debugStore?: boolean;
debugEvent?: boolean;
} & ComponentParamsFromApp;

View File

@ -0,0 +1,64 @@
import {
RuntimeApplication,
RuntimeComponentSchema,
RuntimeComponent,
} from '@sunmao-ui/core';
import React from 'react';
import { UIServices, ComponentParamsFromApp } from './Application';
import { TraitResult } from './Trait';
// TODO: (type-safe), remove fallback type
export type ImplWrapperProps<KSlot extends string = string> = {
component: RuntimeComponentSchema;
childrenMap: ChildrenMap<KSlot>;
services: UIServices;
app?: RuntimeApplication;
} & ComponentParamsFromApp;
export type ComponentImplProps<
TState,
TMethods,
KSlot extends string,
KStyleSlot extends string,
KEvent extends string
> = ImplWrapperProps<KSlot> &
TraitResult<KStyleSlot, KEvent>['props'] &
RuntimeFunctions<TState, TMethods> & {
slotsElements: Record<KSlot, React.ReactElement[]>;
};
export type ComponentImpl<
TProps = any,
TState = any,
TMethods = Record<string, any>,
KSlot extends string = string,
KStyleSlot extends string = string,
KEvent extends string = string
> = React.FC<TProps & ComponentImplProps<TState, TMethods, KSlot, KStyleSlot, KEvent>>;
export type ImplementedRuntimeComponent<
KMethodName extends string,
KStyleSlot extends string,
KSlot extends string,
KEvent extends string
> = RuntimeComponent<KMethodName, KStyleSlot, KSlot, KEvent> & {
impl: ComponentImpl;
};
export type ChildrenMap<KSlot extends string> = Record<
string,
Record<KSlot, RuntimeComponentSchema[]> & {
_grandChildren?: RuntimeComponentSchema[];
_allChildren: RuntimeComponentSchema[];
}
>;
type SubscribeMethods<U> = (map: {
[K in keyof U]: (parameters: U[K]) => void;
}) => void;
type MergeState<T> = (partialState: Partial<T>) => void;
export type RuntimeFunctions<TState, TMethods> = {
mergeState: MergeState<TState>;
subscribeMethods: SubscribeMethods<TMethods>;
};

View File

@ -0,0 +1,14 @@
import { EventHandlerSchema } from './TraitPropertiesSchema';
import { Type } from '@sinclair/typebox';
import { ComponentSchema, RuntimeModule } from '@sunmao-ui/core';
export const ModuleSchema = Type.Object({
id: Type.String(),
type: Type.String(),
properties: Type.Record(Type.String(), Type.Any()),
handlers: Type.Array(EventHandlerSchema),
});
export type ImplementedRuntimeModule = RuntimeModule & {
impl: ComponentSchema[];
};

View File

@ -1,107 +0,0 @@
import RGL from 'react-grid-layout';
import { ApiService } from '../services/apiService';
import { GlobalHandlerMap } from '../services/handler';
import { Registry } from '../services/registry';
import { StateManager } from '../services/stateStore';
import { Application, RuntimeApplication } from '@sunmao-ui/core';
import { EventHandlerSchema } from './TraitPropertiesSchema';
import { Type } from '@sinclair/typebox';
import React from 'react';
export type RuntimeApplicationComponent = RuntimeApplication['spec']['components'][0];
export type UIServices = {
registry: Registry;
stateManager: StateManager;
globalHandlerMap: GlobalHandlerMap;
apiService: ApiService;
};
export type ComponentWrapperProps = {
parentType: string;
component: RuntimeApplicationComponent;
};
export type ComponentWrapperType = React.FC<ComponentWrapperProps>;
export type GridCallbacks = {
onDragStop?: (id: string, layout: RGL.Layout[]) => void;
onDrop?: (id: string, layout: RGL.Layout[], item: RGL.Layout, event: DragEvent) => void;
};
export type ComponentParamsFromApp = {
gridCallbacks?: GridCallbacks;
componentWrapper?: ComponentWrapperType;
};
export type AppProps = {
options: Application;
services: UIServices;
debugStore?: boolean;
debugEvent?: boolean;
} & ComponentParamsFromApp;
// TODO: (type-safe), remove fallback type
export type ImplWrapperProps<KSlot extends string = string> = {
component: RuntimeApplicationComponent;
childrenMap: ChildrenMap<KSlot>;
services: UIServices;
app?: RuntimeApplication;
} & ComponentParamsFromApp;
export type ChildrenMap<KSlot extends string> = Record<
string,
Record<KSlot, RuntimeApplicationComponent[]> & {
_grandChildren?: RuntimeApplicationComponent[];
_allChildren: RuntimeApplicationComponent[];
}
>;
export type CallbackMap<K extends string> = Record<K, () => void>;
export type SubscribeMethods<U> = (map: {
[K in keyof U]: (parameters: U[K]) => void;
}) => void;
export type MergeState<T> = (partialState: Partial<T>) => void;
type RuntimeFunctions<TState, TMethods> = {
mergeState: MergeState<TState>;
subscribeMethods: SubscribeMethods<TMethods>;
};
export type ComponentImplementationProps<
TState,
TMethods,
KSlot extends string,
KStyleSlot extends string,
KEvent extends string
> = ImplWrapperProps<KSlot> &
TraitResult<KStyleSlot, KEvent>['props'] &
RuntimeFunctions<TState, TMethods> & {
slotsElements: Record<KSlot, React.ReactElement[]>
};
export type TraitResult<KStyleSlot extends string, KEvent extends string> = {
props: {
data?: unknown;
customStyle?: Record<KStyleSlot, string>;
callbackMap?: CallbackMap<KEvent>;
effects?: Array<() => void>;
} | null;
unmount?: boolean;
};
export type TraitImplementation<T = any> = (
props: T &
RuntimeFunctions<unknown, unknown> & {
componentId: string;
services: UIServices;
}
) => TraitResult<string, string>;
export const RuntimeModuleSchema = Type.Object({
id: Type.String(),
type: Type.String(),
properties: Type.Record(Type.String(), Type.Any()),
handlers: Type.Array(EventHandlerSchema),
});

View File

@ -0,0 +1,27 @@
import { RuntimeTrait } from '@sunmao-ui/core';
import { UIServices } from './Application';
import { RuntimeFunctions } from './Component';
export type TraitResult<KStyleSlot extends string, KEvent extends string> = {
props: {
data?: unknown;
customStyle?: Record<KStyleSlot, string>;
callbackMap?: CallbackMap<KEvent>;
effects?: Array<() => void>;
} | null;
unmount?: boolean;
};
export type TraitImpl<T = any> = (
props: T &
RuntimeFunctions<unknown, unknown> & {
componentId: string;
services: UIServices;
}
) => TraitResult<string, string>;
export type ImplementedRuntimeTrait = RuntimeTrait & {
impl: TraitImpl;
};
export type CallbackMap<K extends string> = Record<K, () => void>;

View File

@ -0,0 +1,6 @@
export * from './Application';
export * from './Component';
export * from './Trait';
export * from './Module';
export * from './TraitPropertiesSchema';
export * from './ValidResultSchema';

View File

@ -1,9 +1,6 @@
import { Static } from '@sinclair/typebox';
import { createComponent, CreateComponentOptions } from '@sunmao-ui/core';
import {
ComponentImplementation,
ImplementedRuntimeComponent,
} from '../services/registry';
import { ComponentImpl, ImplementedRuntimeComponent } from '../types';
type ToMap<U> = {
[K in keyof U]: Static<U[K]>;
@ -20,7 +17,7 @@ export function implementRuntimeComponent<
>(
options: T
): (
impl: ComponentImplementation<
impl: ComponentImpl<
Static<T['spec']['properties']>,
Static<T['spec']['state']>,
ToMap<T['spec']['methods']>,

View File

@ -2,7 +2,7 @@ import { RuntimeApplication } from '@sunmao-ui/core';
import { Static, TSchema } from '@sinclair/typebox';
import { Registry } from '../services/registry';
import { StateManager } from '../services/stateStore';
import { RuntimeModuleSchema } from '../types/RuntimeSchema';
import { ModuleSchema } from '../types';
import { parseTypeBox } from './parseTypeBox';
export function initStateAndMethod(
@ -25,7 +25,7 @@ export function initStateAndMethod(
stateManager.store[c.id] = state;
if (c.type === 'core/v1/moduleContainer') {
const moduleSchema = c.properties as Static<typeof RuntimeModuleSchema>;
const moduleSchema = c.properties as Static<typeof ModuleSchema>;
try {
const mSpec = registry.getModuleByType(moduleSchema.type).spec;
const moduleInitState: Record<string, unknown> = {};

View File

@ -1,4 +1,4 @@
import { ImplementedRuntimeModule } from '../services/registry';
import { ImplementedRuntimeModule } from '../types';
// add {{$moduleId}} in moduleSchema
export function parseModuleSchema(

View File

@ -1,11 +1,12 @@
import { RuntimeApplicationComponent, ChildrenMap } from '../types/RuntimeSchema';
import { RuntimeComponentSchema } from '@sunmao-ui/core';
import { ChildrenMap } from '../types';
export function resolveChildrenMap(components: RuntimeApplicationComponent[]): {
export function resolveChildrenMap(components: RuntimeComponentSchema[]): {
childrenMap: ChildrenMap<string>;
topLevelComponents: RuntimeApplicationComponent[];
topLevelComponents: RuntimeComponentSchema[];
} {
const childrenMap: ChildrenMap<string> = {};
const topLevelComponents: RuntimeApplicationComponent[] = [];
const topLevelComponents: RuntimeComponentSchema[] = [];
for (const c of components) {
const slotTrait = c.traits.find(t => t.parsedType.name === 'slot');
@ -28,7 +29,7 @@ export function resolveChildrenMap(components: RuntimeApplicationComponent[]): {
}
// get allChildren and grand children
function getAllChildren(id: string): RuntimeApplicationComponent[] {
function getAllChildren(id: string): RuntimeComponentSchema[] {
if (!childrenMap[id]) {
return [];
}