From c85008204ac9f69921c67e88abbbff4161824c70 Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Tue, 30 Nov 2021 13:59:54 +0800 Subject: [PATCH 1/6] add mobx --- packages/editor/package.json | 2 + packages/editor/src/EditorStore.ts | 19 + .../src/components/ComponentWrapper.tsx | 12 +- packages/editor/src/components/Editor.tsx | 385 +++++++++--------- packages/editor/src/eventBus.ts | 7 +- .../updateSelectComponentLeafOperation.ts | 8 +- yarn.lock | 10 + 7 files changed, 234 insertions(+), 209 deletions(-) create mode 100644 packages/editor/src/EditorStore.ts diff --git a/packages/editor/package.json b/packages/editor/package.json index a3541fbf..bc91e55a 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -42,6 +42,8 @@ "framer-motion": "^4", "immer": "^9.0.6", "lodash-es": "^4.17.21", + "mobx": "^6.3.8", + "mobx-react-lite": "^3.2.2", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/editor/src/EditorStore.ts b/packages/editor/src/EditorStore.ts new file mode 100644 index 00000000..f9a3db0c --- /dev/null +++ b/packages/editor/src/EditorStore.ts @@ -0,0 +1,19 @@ +import { makeAutoObservable } from 'mobx'; +import { eventBus } from './eventBus'; + +class EditorStore { + selectedComponentId = ''; + + constructor() { + eventBus.on('selectComponent', id => { + this.setSelectedComponentId(id); + }); + makeAutoObservable(this); + } + + setSelectedComponentId(val: string) { + this.selectedComponentId = val; + } +} + +export const editorStore = new EditorStore() diff --git a/packages/editor/src/components/ComponentWrapper.tsx b/packages/editor/src/components/ComponentWrapper.tsx index 06f0f37f..35f7b0e3 100644 --- a/packages/editor/src/components/ComponentWrapper.tsx +++ b/packages/editor/src/components/ComponentWrapper.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import { css } from '@emotion/react'; import { ComponentWrapperType } from '@sunmao-ui/runtime'; -import { eventBus, HoverComponentEvent, SelectComponentEvent } from '../eventBus'; +import { eventBus } from '../eventBus'; // children of components in this list should render height as 100% const fullHeightList = ['core/v1/grid_layout']; @@ -15,10 +15,10 @@ export const ComponentWrapper: ComponentWrapperType = props => { useEffect(() => { const handler = (event: string, payload: any) => { switch (event) { - case SelectComponentEvent: + case 'selectComponent': setSelectedComponentId(payload); break; - case HoverComponentEvent: + case 'hoverComponentEvent': setHoverComponentId(payload); break; } @@ -52,15 +52,15 @@ export const ComponentWrapper: ComponentWrapperType = props => { `; const onClickWrapper = (e: React.MouseEvent) => { e.stopPropagation(); - eventBus.send(SelectComponentEvent as any, component.id); + eventBus.send('selectComponent' as any, component.id); }; const onMouseEnterWrapper = (e: React.MouseEvent) => { e.stopPropagation(); - eventBus.send(HoverComponentEvent as any, component.id); + eventBus.send('hoverComponentEvent' as any, component.id); }; const onMouseLeaveWrapper = (e: React.MouseEvent) => { e.stopPropagation(); - eventBus.send(HoverComponentEvent as any, ''); + eventBus.send('hoverComponentEvent' as any, ''); }; return (
; @@ -32,203 +34,198 @@ type Props = { appStorage: AppStorage; }; -export const Editor: React.FC = ({ - App, - registry, - stateStore, - appModelManager, - appStorage, -}) => { - const { components } = useAppModel(appModelManager); +export const Editor: React.FC = observer( + ({ App, registry, stateStore, appModelManager, appStorage }) => { + const { components } = useAppModel(appModelManager); - const [selectedComponentId, setSelectedComponentId] = useState( - components?.[0]?.id || '' - ); - const [scale, setScale] = useState(100); - const [preview, setPreview] = useState(false); - const [codeMode, setCodeMode] = useState(false); - const [code, setCode] = useState(''); + const [scale, setScale] = useState(100); + const [preview, setPreview] = useState(false); + const [codeMode, setCodeMode] = useState(false); + const [code, setCode] = useState(''); - useEffect(() => { - eventBus.on(SelectComponentEvent, id => { - setSelectedComponentId(id); - }); - }, [setSelectedComponentId]); + const gridCallbacks: GridCallbacks = useMemo(() => { + return { + // drag an existing component + onDragStop(id, layout) { + eventBus.send( + 'operation', + new ModifyComponentPropertiesLeafOperation({ + componentId: id, + properties: { layout }, + }) + ); + }, + // drag a new component from tool box + onDrop(id, layout, _, e) { + const component = e.dataTransfer?.getData('component') || ''; + eventBus.send( + 'operation', + new CreateComponentBranchOperation({ + componentType: component, + parentId: id, + slot: 'content', + layout, + }) + ); + }, + }; + }, []); - const gridCallbacks: GridCallbacks = useMemo(() => { - return { - // drag an existing component - onDragStop(id, layout) { - eventBus.send( - 'operation', - new ModifyComponentPropertiesLeafOperation({ - componentId: id, - properties: { layout }, - }) - ); - }, - // drag a new component from tool box - onDrop(id, layout, _, e) { - const component = e.dataTransfer?.getData('component') || ''; - eventBus.send( - 'operation', - new CreateComponentBranchOperation({ - componentType: component, - parentId: id, - slot: 'content', - layout, - }) - ); - }, - }; - }, []); + const app = useMemo(() => { + return { + version: 'sunmao/v1', + kind: 'Application', + metadata: { + name: 'some App', + }, + spec: { + components, + }, + }; + }, [components]); - const app = useMemo(() => { - return { - version: 'sunmao/v1', - kind: 'Application', - metadata: { - name: 'some App', - }, - spec: { - components, - }, - }; - }, [components]); - - const appComponent = useMemo(() => { - return ( - - ); - }, [app, gridCallbacks]); - - const renderMain = () => { - const appBox = ( - - - - {appComponent} - - - ); - - if (codeMode) { + const appComponent = useMemo(() => { return ( - - - + + ); + }, [app, gridCallbacks]); + + const renderMain = () => { + const appBox = ( + + + + {appComponent} + + + ); + + if (codeMode) { + return ( + + + + + {appBox} + + ); + } + return ( + <> + + + + Explorer + UI Tree + State + + + + + + + editorStore.setSelectedComponentId(id)} + registry={registry} + /> + + + + + + {appBox} - - ); - } - return ( - <> - - - - Explorer - UI Tree - State - - - - - - - setSelectedComponentId(id)} - registry={registry} - /> - - - - - - - - {appBox} - - - - Inspect - Insert - - - - - - - - - - - - - ); - }; - - return ( - - - setPreview(true)} - codeMode={codeMode} - onCodeMode={v => { - setCodeMode(v); - if (!v && code) { - eventBus.send('operation', new ReplaceAppLeafOperation(JSON.parse(code))); - } - }} - /> - - {renderMain()} - - - {preview && ( - setPreview(false)}> - - + + + + Inspect + Insert + + + + + + + + + + - - )} - - ); -}; + + ); + }; + + return ( + + + setPreview(true)} + codeMode={codeMode} + onCodeMode={v => { + setCodeMode(v); + if (!v && code) { + eventBus.send('operation', new ReplaceAppLeafOperation(JSON.parse(code))); + } + }} + /> + + {renderMain()} + + + {preview && ( + setPreview(false)}> + + + + + )} + + ); + } +); diff --git a/packages/editor/src/eventBus.ts b/packages/editor/src/eventBus.ts index b2424dec..80ec9d76 100644 --- a/packages/editor/src/eventBus.ts +++ b/packages/editor/src/eventBus.ts @@ -3,17 +3,14 @@ import { Application, ApplicationComponent } from '@sunmao-ui/core'; import { IOperation } from './operations/type'; import { ImplementedRuntimeModule } from '../../runtime/lib'; -export const SelectComponentEvent = 'selectComponent'; -export const HoverComponentEvent = 'hoverComponent'; - export type EventNames = { operation: IOperation; redo: undefined; undo: undefined; componentsReload: ApplicationComponent[]; componentsChange: ApplicationComponent[]; - [SelectComponentEvent]: string; - [HoverComponentEvent]: string; + selectComponent: string; + hoverComponent: string; // for state decorators appChange: Application; diff --git a/packages/editor/src/operations/leaf/updateSelectComponentLeafOperation.ts b/packages/editor/src/operations/leaf/updateSelectComponentLeafOperation.ts index 34f130f3..b00c0b0f 100644 --- a/packages/editor/src/operations/leaf/updateSelectComponentLeafOperation.ts +++ b/packages/editor/src/operations/leaf/updateSelectComponentLeafOperation.ts @@ -1,5 +1,5 @@ import { ApplicationComponent } from '@sunmao-ui/core'; -import { eventBus, SelectComponentEvent } from '../../eventBus'; +import { eventBus } from '../../eventBus'; import { BaseLeafOperation } from '../type'; export type UpdateSelectComponentLeafOperationContext = { @@ -12,21 +12,21 @@ export class UpdateSelectComponentLeafOperation extends BaseLeafOperation { - eventBus.send(SelectComponentEvent, this.context.newId); + eventBus.send('selectComponent', this.context.newId); }); return prev; } redo(prev: ApplicationComponent[]): ApplicationComponent[] { setTimeout(() => { - eventBus.send(SelectComponentEvent, this.context.newId); + eventBus.send('selectComponent', this.context.newId); }); return prev; } undo(prev: ApplicationComponent[]): ApplicationComponent[] { setTimeout(() => { - eventBus.send(SelectComponentEvent, this.prevId); + eventBus.send('selectComponent', this.prevId); }); return prev; } diff --git a/yarn.lock b/yarn.lock index 8ae2cf16..32adfcf9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7264,6 +7264,16 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mobx-react-lite@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.2.2.tgz#cee5f09e6b0e4d2705d87276baf1de74d997fa33" + integrity sha512-FxJJMqmHcnQYOVVs2DdjNHioGlFsXF5/9VHztS9NAfIT3DYrxNZzVi119Zr/OmlWKkWNkAsssSNzPkqautfL4A== + +mobx@^6.3.8: + version "6.3.8" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.3.8.tgz#a4654b1b69c683237f2444cf0af39a621d4611af" + integrity sha512-RfG2y766P1o9u9xrQht/HBXEoUPIr4B3Gjri3reLW/TuHm3I/3TfBBS0OaeMbw19RIF0AymqjDNlJgakN4ZK7g== + modify-values@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" From 772ca1d5190f906e92835664cff8bcfa91c1665b Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Tue, 30 Nov 2021 14:09:33 +0800 Subject: [PATCH 2/6] remove useAppModel --- packages/editor/src/EditorStore.ts | 8 ++++++ .../ComponentForm/ComponentForm.tsx | 6 +---- .../EventTraitForm/EventHandlerForm.tsx | 23 ++++++++++------- .../EventTraitForm/EventTraitForm.tsx | 5 +--- .../FetchTraitForm/FetchTraitForm.tsx | 5 +--- packages/editor/src/components/Editor.tsx | 14 ++++------- packages/editor/src/operations/useAppModel.ts | 25 ------------------- packages/editor/src/playground.tsx | 6 +---- 8 files changed, 31 insertions(+), 61 deletions(-) delete mode 100644 packages/editor/src/operations/useAppModel.ts diff --git a/packages/editor/src/EditorStore.ts b/packages/editor/src/EditorStore.ts index f9a3db0c..671b4283 100644 --- a/packages/editor/src/EditorStore.ts +++ b/packages/editor/src/EditorStore.ts @@ -1,19 +1,27 @@ import { makeAutoObservable } from 'mobx'; +import { ApplicationComponent } from '../../core/lib'; import { eventBus } from './eventBus'; class EditorStore { selectedComponentId = ''; + components: ApplicationComponent[] = []; constructor() { eventBus.on('selectComponent', id => { this.setSelectedComponentId(id); }); + eventBus.on('componentsChange', (components: ApplicationComponent[]) => { + this.setComponents(components); + }); makeAutoObservable(this); } setSelectedComponentId(val: string) { this.selectedComponentId = val; } + setComponents(val: ApplicationComponent[]) { + this.components = val; + } } export const editorStore = new EditorStore() diff --git a/packages/editor/src/components/ComponentForm/ComponentForm.tsx b/packages/editor/src/components/ComponentForm/ComponentForm.tsx index ee6b1e1a..7d522c8c 100644 --- a/packages/editor/src/components/ComponentForm/ComponentForm.tsx +++ b/packages/editor/src/components/ComponentForm/ComponentForm.tsx @@ -11,7 +11,6 @@ import { GeneralTraitFormList } from './GeneralTraitFormList'; import { FetchTraitForm } from './FetchTraitForm'; import { Registry } from '@sunmao-ui/runtime/lib/services/registry'; import SchemaField from './JsonSchemaForm/SchemaField'; -import { AppModelManager } from '../../operations/AppModelManager'; import { ModifyComponentPropertiesLeafOperation, ModifyTraitPropertiesLeafOperation, @@ -22,7 +21,6 @@ type Props = { registry: Registry; selectedId: string; app: Application; - appModelManager: AppModelManager; }; export const renderField = (properties: { @@ -78,7 +76,7 @@ export const renderField = (properties: { }; export const ComponentForm: React.FC = props => { - const { selectedId, app, registry, appModelManager } = props; + const { selectedId, app, registry } = props; const selectedComponent = useMemo( () => app.spec.components.find(c => c.id === selectedId), @@ -146,12 +144,10 @@ export const ComponentForm: React.FC = props => { diff --git a/packages/editor/src/components/ComponentForm/EventTraitForm/EventHandlerForm.tsx b/packages/editor/src/components/ComponentForm/EventTraitForm/EventHandlerForm.tsx index ffb2406c..0250b63a 100644 --- a/packages/editor/src/components/ComponentForm/EventTraitForm/EventHandlerForm.tsx +++ b/packages/editor/src/components/ComponentForm/EventTraitForm/EventHandlerForm.tsx @@ -11,13 +11,12 @@ import { } from '@chakra-ui/react'; import { Static } from '@sinclair/typebox'; import { CloseIcon } from '@chakra-ui/icons'; +import { observer } from 'mobx-react-lite'; import { useFormik } from 'formik'; -import { EventHandlerSchema } from '@sunmao-ui/runtime'; -import { useAppModel } from '../../../operations/useAppModel'; +import { EventHandlerSchema, Registry } from '@sunmao-ui/runtime'; import { formWrapperCSS } from '../style'; import { KeyValueEditor } from '../../KeyValueEditor'; -import { Registry } from '@sunmao-ui/runtime/lib/services/registry'; -import { AppModelManager } from '../../../operations/AppModelManager'; +import { editorStore } from '../../../EditorStore'; type Props = { registry: Registry; @@ -26,12 +25,18 @@ type Props = { onChange: (hanlder: Static) => void; onRemove: () => void; hideEventType?: boolean; - appModelManager: AppModelManager }; -export const EventHandlerForm: React.FC = props => { - const { handler, eventTypes, onChange, onRemove, hideEventType, registry, appModelManager } = props; - const { components } = useAppModel(appModelManager); +export const EventHandlerForm: React.FC = observer(props => { + const { + handler, + eventTypes, + onChange, + onRemove, + hideEventType, + registry, + } = props; + const { components } = editorStore; const [methods, setMethods] = useState([]); function updateMethods(componentId: string) { @@ -193,4 +198,4 @@ export const EventHandlerForm: React.FC = props => { /> ); -}; +}); diff --git a/packages/editor/src/components/ComponentForm/EventTraitForm/EventTraitForm.tsx b/packages/editor/src/components/ComponentForm/EventTraitForm/EventTraitForm.tsx index 46ae3a93..e194a5be 100644 --- a/packages/editor/src/components/ComponentForm/EventTraitForm/EventTraitForm.tsx +++ b/packages/editor/src/components/ComponentForm/EventTraitForm/EventTraitForm.tsx @@ -8,7 +8,6 @@ import { EventHandlerSchema } from '@sunmao-ui/runtime'; import { eventBus } from '../../../eventBus'; import { EventHandlerForm } from './EventHandlerForm'; import { Registry } from '@sunmao-ui/runtime/lib/services/registry'; -import { AppModelManager } from '../../../operations/AppModelManager'; import { CreateTraitLeafOperation, ModifyTraitPropertiesLeafOperation, @@ -19,11 +18,10 @@ type EventHandler = Static; type Props = { registry: Registry; component: ApplicationComponent; - appModelManager: AppModelManager }; export const EventTraitForm: React.FC = props => { - const { component, registry, appModelManager } = props; + const { component, registry } = props; const handlers: EventHandler[] = useMemo(() => { return component.traits.find(t => t.type === 'core/v1/event')?.properties @@ -116,7 +114,6 @@ export const EventTraitForm: React.FC = props => { onChange={onChange} onRemove={onRemove} registry={registry} - appModelManager={appModelManager} /> ); }); diff --git a/packages/editor/src/components/ComponentForm/FetchTraitForm/FetchTraitForm.tsx b/packages/editor/src/components/ComponentForm/FetchTraitForm/FetchTraitForm.tsx index 673341d4..954892c6 100644 --- a/packages/editor/src/components/ComponentForm/FetchTraitForm/FetchTraitForm.tsx +++ b/packages/editor/src/components/ComponentForm/FetchTraitForm/FetchTraitForm.tsx @@ -19,7 +19,6 @@ import { KeyValueEditor } from '../../KeyValueEditor'; import { EventHandlerForm } from '../EventTraitForm/EventHandlerForm'; import { eventBus } from '../../../eventBus'; import { Registry } from '@sunmao-ui/runtime/lib/services/registry'; -import { AppModelManager } from '../../../operations/AppModelManager'; import { ModifyTraitPropertiesLeafOperation, RemoveTraitLeafOperation, @@ -30,13 +29,12 @@ type EventHandler = Static; type Props = { component: ApplicationComponent; registry: Registry; - appModelManager: AppModelManager; }; const httpMethods = ['get', 'post', 'put', 'delete', 'patch']; export const FetchTraitForm: React.FC = props => { - const { component, registry, appModelManager } = props; + const { component, registry } = props; const fetchTrait = component.traits.find(t => t.type === 'core/v1/fetch') ?.properties as Static; @@ -172,7 +170,6 @@ export const FetchTraitForm: React.FC = props => { onChange={onChange} onRemove={onRemove} registry={registry} - appModelManager={appModelManager} /> ); })} diff --git a/packages/editor/src/components/Editor.tsx b/packages/editor/src/components/Editor.tsx index 6360b066..0bd40656 100644 --- a/packages/editor/src/components/Editor.tsx +++ b/packages/editor/src/components/Editor.tsx @@ -7,13 +7,11 @@ import { StructureTree } from './StructureTree'; import { eventBus } from '../eventBus'; import { ComponentForm } from './ComponentForm'; import { ComponentList } from './ComponentsList'; -import { useAppModel } from '../operations/useAppModel'; import { EditorHeader } from './EditorHeader'; import { PreviewModal } from './PreviewModal'; import { KeyboardEventWrapper } from './KeyboardEventWrapper'; import { ComponentWrapper } from './ComponentWrapper'; import { StateEditor, SchemaEditor } from './CodeEditor'; -import { AppModelManager } from '../operations/AppModelManager'; import { Explorer } from './Explorer'; import { AppStorage } from '../AppStorage'; import { @@ -30,13 +28,12 @@ type Props = { registry: ReturnOfInit['registry']; stateStore: ReturnOfInit['stateManager']['store']; apiService: ReturnOfInit['apiService']; - appModelManager: AppModelManager; appStorage: AppStorage; }; export const Editor: React.FC = observer( - ({ App, registry, stateStore, appModelManager, appStorage }) => { - const { components } = useAppModel(appModelManager); + ({ App, registry, stateStore, appStorage }) => { + const { components, selectedComponentId } = editorStore; const [scale, setScale] = useState(100); const [preview, setPreview] = useState(false); @@ -152,7 +149,7 @@ export const Editor: React.FC = observer( editorStore.setSelectedComponentId(id)} registry={registry} /> @@ -180,9 +177,8 @@ export const Editor: React.FC = observer( @@ -196,7 +192,7 @@ export const Editor: React.FC = observer( }; return ( - + ( - appModalManager.components - ); - - useEffect(() => { - const onComponents = (components: ApplicationComponent[]) => { - setComponents(() => components); - }; - eventBus.on('componentsChange', onComponents); - - return () => { - eventBus.off('componentsChange', onComponents); - }; - }, []); - - return { - components, - }; -} diff --git a/packages/editor/src/playground.tsx b/packages/editor/src/playground.tsx index 3a8b9d85..a64e6e0e 100644 --- a/packages/editor/src/playground.tsx +++ b/packages/editor/src/playground.tsx @@ -8,7 +8,6 @@ import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; import { Editor } from './components/Editor'; -import { AppModelManager } from './operations/AppModelManager'; import { appStorage } from './setup'; type Example = { @@ -22,7 +21,7 @@ type Example = { const Playground: React.FC<{ examples: Example[] }> = ({ examples }) => { const [example, setExample] = useState(examples[0]); - const { App, registry, stateStore, appModelManager, apiService } = useMemo(() => { + const { App, registry, stateStore, apiService } = useMemo(() => { if (!example) { return {}; } @@ -37,13 +36,11 @@ const Playground: React.FC<{ examples: Example[] }> = ({ examples }) => { registry.registerModule(m); }); localStorage.removeItem('schema'); - const appModelManager = new AppModelManager(appStorage.components); return { App, registry, stateStore, - appModelManager, apiService, }; }, [example]); @@ -89,7 +86,6 @@ const Playground: React.FC<{ examples: Example[] }> = ({ examples }) => { registry={registry!} stateStore={stateStore!} apiService={apiService!} - appModelManager={appModelManager} appStorage={appStorage} /> )} From a1e998702f583847c65afa9b330a4299bcfee1ae Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Tue, 30 Nov 2021 14:40:40 +0800 Subject: [PATCH 3/6] move appStorage in editorStore --- packages/editor/src/AppStorage.ts | 20 ++++++---- packages/editor/src/EditorStore.ts | 39 +++++++++++++++++-- packages/editor/src/components/Editor.tsx | 6 +-- .../src/components/Explorer/Explorer.tsx | 38 +++++------------- packages/editor/src/main.tsx | 7 ++-- packages/editor/src/playground.tsx | 18 ++++----- packages/editor/src/setup.ts | 6 +-- 7 files changed, 72 insertions(+), 62 deletions(-) diff --git a/packages/editor/src/AppStorage.ts b/packages/editor/src/AppStorage.ts index 2142e1b4..18fd4eaf 100644 --- a/packages/editor/src/AppStorage.ts +++ b/packages/editor/src/AppStorage.ts @@ -14,12 +14,12 @@ export class AppStorage { static AppLSKey = 'schema'; static ModulesLSKey = 'modules'; - constructor(private registry: Registry) { + constructor() { this.app = this.getDefaultAppFromLS(); - this.setApp(this.app) + this.setApp(this.app); this.modules = this.getModulesFromLS(); - this.setModules(this.modules) - + this.setModules(this.modules); + this.updateCurrentId('app', this.app.metadata.name); this.refreshComponents(); @@ -64,8 +64,14 @@ export class AppStorage { this.saveModulesInLS(); } - removeModule(module: ImplementedRuntimeModule) { - this.setModules(this.modules.filter(m => m !== module)); + removeModule(v: string, n: string) { + console.log(v, n) + console.log(this.modules) + this.setModules( + this.modules.filter( + ({ version, metadata: { name } }) => version !== v && name !== n + ) + ); this.saveModulesInLS(); } @@ -107,8 +113,6 @@ export class AppStorage { private saveModulesInLS() { localStorage.setItem(AppStorage.ModulesLSKey, JSON.stringify(this.modules)); - // reregister modules to activate immediately - this.modules.forEach(m => this.registry.registerModule(m, true)); } // update components by currentEditingType & cache diff --git a/packages/editor/src/EditorStore.ts b/packages/editor/src/EditorStore.ts index 671b4283..ee478f81 100644 --- a/packages/editor/src/EditorStore.ts +++ b/packages/editor/src/EditorStore.ts @@ -1,27 +1,60 @@ import { makeAutoObservable } from 'mobx'; -import { ApplicationComponent } from '../../core/lib'; +import { Application, ApplicationComponent } from '@sunmao-ui/core'; +import { ImplementedRuntimeModule } from '@sunmao-ui/runtime'; import { eventBus } from './eventBus'; +import { AppStorage } from './AppStorage'; +import { registry } from './setup'; class EditorStore { selectedComponentId = ''; + // currentEditingComponents, it could be app's or module's components components: ApplicationComponent[] = []; + modules: ImplementedRuntimeModule[]; + // it could be app or module's name + currentEditingName: string | undefined; + currentEditingType: 'app' | 'module' = 'app'; + app: Application; + + appStorage = new AppStorage(); constructor() { + this.app = this.appStorage.app; + this.modules = this.appStorage.modules; eventBus.on('selectComponent', id => { this.setSelectedComponentId(id); }); - eventBus.on('componentsChange', (components: ApplicationComponent[]) => { + eventBus.on('componentsChange', components => { this.setComponents(components); }); + eventBus.on('modulesChange', modules => { + this.setModules(modules); + // reregister modules to activate immediately + this.modules.forEach(m => registry.registerModule(m, true)); + }); makeAutoObservable(this); } + updateCurrentEditingTarget = (type: 'app' | 'module', name: string) => { + this.appStorage.updateCurrentId(type, name); + // this.setCurrentEditingType(type); + // this.setCurrentEditingName(name); + } + setSelectedComponentId(val: string) { this.selectedComponentId = val; } + private setCurrentEditingName(val: string) { + this.currentEditingName = val; + } + private setCurrentEditingType(val: 'app' | 'module') { + this.currentEditingType = val; + } setComponents(val: ApplicationComponent[]) { this.components = val; } + setModules(val: ImplementedRuntimeModule[]) { + this.modules = val; + } } -export const editorStore = new EditorStore() +export const editorStore = new EditorStore(); diff --git a/packages/editor/src/components/Editor.tsx b/packages/editor/src/components/Editor.tsx index 0bd40656..e5fae325 100644 --- a/packages/editor/src/components/Editor.tsx +++ b/packages/editor/src/components/Editor.tsx @@ -13,7 +13,6 @@ import { KeyboardEventWrapper } from './KeyboardEventWrapper'; import { ComponentWrapper } from './ComponentWrapper'; import { StateEditor, SchemaEditor } from './CodeEditor'; import { Explorer } from './Explorer'; -import { AppStorage } from '../AppStorage'; import { ModifyComponentPropertiesLeafOperation, ReplaceAppLeafOperation, @@ -28,11 +27,10 @@ type Props = { registry: ReturnOfInit['registry']; stateStore: ReturnOfInit['stateManager']['store']; apiService: ReturnOfInit['apiService']; - appStorage: AppStorage; }; export const Editor: React.FC = observer( - ({ App, registry, stateStore, appStorage }) => { + ({ App, registry, stateStore }) => { const { components, selectedComponentId } = editorStore; const [scale, setScale] = useState(100); @@ -144,7 +142,7 @@ export const Editor: React.FC = observer( - + { - const [modules, setModules] = React.useState( - appStorage.modules - ); - - eventBus.on('modulesChange', newModules => { - setModules(newModules); - }); - - return { - modules, - }; -}; - -export const Explorer: React.FC = ({ appStorage }) => { - const app = appStorage.app; +export const Explorer: React.FC = observer(() => { + const { app, modules, updateCurrentEditingTarget } = editorStore; const appItemId = `app_${app.metadata.name}`; const [selectedItem, setSelectedItem] = React.useState(appItemId); const onClickApp = (id: string) => { setSelectedItem(id); - appStorage.updateCurrentId('app', app.metadata.name); + updateCurrentEditingTarget('app', app.metadata.name); }; const appItem = ( @@ -43,15 +25,15 @@ export const Explorer: React.FC = ({ appStorage }) => { /> ); - const { modules } = useAppStorage(appStorage); + console.log('modules', modules); const moduleItems = modules.map((module: ImplementedRuntimeModule) => { const moduleItemId = `module_${module.metadata.name}`; const onClickModule = (id: string) => { setSelectedItem(id); - appStorage.updateCurrentId('module', module.metadata.name); + updateCurrentEditingTarget('module', module.metadata.name); }; const onRemove = () => { - appStorage.removeModule(module); + editorStore.appStorage.removeModule(module.version, module.metadata.name); }; return ( = ({ appStorage }) => { aria-label="create module" size="xs" icon={} - onClick={() => appStorage.createModule()} + onClick={() => editorStore.appStorage.createModule()} /> {moduleItems} ); -}; +}); type ExplorerItemProps = { id: string; diff --git a/packages/editor/src/main.tsx b/packages/editor/src/main.tsx index 20b36fd8..25c057da 100644 --- a/packages/editor/src/main.tsx +++ b/packages/editor/src/main.tsx @@ -6,7 +6,8 @@ import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; import { Editor } from './components/Editor'; -import { apiService, App, appModelManager, appStorage, registry, stateStore } from './setup'; +import { editorStore } from './EditorStore'; +import { apiService, App, registry, stateStore } from './setup'; type Options = Partial<{ components: Parameters[0][]; @@ -19,7 +20,7 @@ export default function renderApp(options: Options = {}) { components.forEach(c => registry.registerComponent(c)); traits.forEach(t => registry.registerTrait(t)); modules.forEach(m => registry.registerModule(m)); - appStorage.modules.forEach(m => registry.registerModule(m)); + editorStore.appStorage.modules.forEach(m => registry.registerModule(m)); ReactDOM.render( @@ -29,8 +30,6 @@ export default function renderApp(options: Options = {}) { registry={registry} stateStore={stateStore} apiService={apiService} - appStorage={appStorage} - appModelManager={appModelManager} /> , diff --git a/packages/editor/src/playground.tsx b/packages/editor/src/playground.tsx index a64e6e0e..9eb5c475 100644 --- a/packages/editor/src/playground.tsx +++ b/packages/editor/src/playground.tsx @@ -8,7 +8,6 @@ import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; import { Editor } from './components/Editor'; -import { appStorage } from './setup'; type Example = { name: string; @@ -79,16 +78,13 @@ const Playground: React.FC<{ examples: Example[] }> = ({ examples }) => { - {appModelManager && ( - - )} + ); diff --git a/packages/editor/src/setup.ts b/packages/editor/src/setup.ts index 23c790c1..4912c092 100644 --- a/packages/editor/src/setup.ts +++ b/packages/editor/src/setup.ts @@ -1,5 +1,5 @@ import { initSunmaoUI } from '@sunmao-ui/runtime'; -import { AppStorage } from './AppStorage'; +import { editorStore } from './EditorStore'; import { AppModelManager } from './operations/AppModelManager'; const ui = initSunmaoUI(); @@ -8,8 +8,7 @@ const App = ui.App; const registry = ui.registry; const apiService = ui.apiService; const stateStore = ui.stateManager.store; -const appStorage = new AppStorage(registry); -const appModelManager = new AppModelManager(appStorage.components); +const appModelManager = new AppModelManager(editorStore.appStorage.components); export { ui, @@ -17,6 +16,5 @@ export { registry, apiService, stateStore, - appStorage, appModelManager, }; From dcd448965c328826ff118cd8ff5a3efe3d3d48f4 Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Tue, 30 Nov 2021 15:44:04 +0800 Subject: [PATCH 4/6] refactor AppStorage --- packages/editor/src/AppStorage.ts | 68 ++++--------------- packages/editor/src/EditorStore.ts | 61 ++++++++++++++--- .../editor/src/operations/AppModelManager.ts | 7 +- packages/editor/src/setup.ts | 3 +- 4 files changed, 67 insertions(+), 72 deletions(-) diff --git a/packages/editor/src/AppStorage.ts b/packages/editor/src/AppStorage.ts index 18fd4eaf..6bd222c5 100644 --- a/packages/editor/src/AppStorage.ts +++ b/packages/editor/src/AppStorage.ts @@ -1,32 +1,18 @@ import { Application, ApplicationComponent } from '@sunmao-ui/core'; -import { ImplementedRuntimeModule, Registry } from '@sunmao-ui/runtime'; +import { ImplementedRuntimeModule } from '@sunmao-ui/runtime'; import { produce } from 'immer'; -import { eventBus } from './eventBus'; import { DefaultNewModule, EmptyAppSchema } from './constants'; export class AppStorage { - components: ApplicationComponent[] = []; app: Application; modules: ImplementedRuntimeModule[]; // this is current editing Model - private currentEditingName: string | undefined; - private currentEditingType: 'app' | 'module' = 'app'; static AppLSKey = 'schema'; static ModulesLSKey = 'modules'; constructor() { this.app = this.getDefaultAppFromLS(); - this.setApp(this.app); this.modules = this.getModulesFromLS(); - this.setModules(this.modules); - - this.updateCurrentId('app', this.app.metadata.name); - this.refreshComponents(); - - eventBus.on('componentsChange', (components: ApplicationComponent[]) => { - this.components = components; - this.saveComponentsInLS(); - }); } getDefaultAppFromLS(): Application { @@ -53,20 +39,14 @@ export class AppStorage { } } - updateCurrentId(type: 'app' | 'module', name: string) { - this.currentEditingType = type; - this.currentEditingName = name; - this.refreshComponents(); - } - createModule() { this.setModules([...this.modules, DefaultNewModule]); this.saveModulesInLS(); } removeModule(v: string, n: string) { - console.log(v, n) - console.log(this.modules) + console.log(v, n); + console.log(this.modules); this.setModules( this.modules.filter( ({ version, metadata: { name } }) => version !== v && name !== n @@ -75,21 +55,24 @@ export class AppStorage { this.saveModulesInLS(); } - saveComponentsInLS() { - switch (this.currentEditingType) { + // name is `${module.version}/${module.metadata.name}` + saveComponentsInLS( + type: 'app' | 'module', + name: string, + components: ApplicationComponent[] + ) { + switch (type) { case 'app': const newApp = produce(this.app, draft => { - draft.spec.components = this.components; + draft.spec.components = components; }); this.setApp(newApp); this.saveAppInLS(); break; case 'module': - const i = this.modules.findIndex( - m => m.metadata.name === this.currentEditingName - ); + const i = this.modules.findIndex(m => m.metadata.name === name); const newModules = produce(this.modules, draft => { - draft[i].components = this.components; + draft[i].components = components; }); this.setModules(newModules); this.saveModulesInLS(); @@ -99,12 +82,10 @@ export class AppStorage { private setApp(app: Application) { this.app = app; - eventBus.send('appChange', app); } private setModules(modules: ImplementedRuntimeModule[]) { this.modules = modules; - eventBus.send('modulesChange', modules); } private saveAppInLS() { @@ -114,27 +95,4 @@ export class AppStorage { private saveModulesInLS() { localStorage.setItem(AppStorage.ModulesLSKey, JSON.stringify(this.modules)); } - - // update components by currentEditingType & cache - private refreshComponents() { - switch (this.currentEditingType) { - case 'module': - const module = this.modules.find( - m => m.metadata.name === this.currentEditingName - ); - const componentsOfModule = module?.components || []; - this.components = componentsOfModule; - - break; - case 'app': - const componentsOfApp = this.app.spec.components; - this.components = componentsOfApp; - break; - } - this.emitComponentsChange(); - } - - private emitComponentsChange() { - eventBus.send('componentsReload', this.components); - } } diff --git a/packages/editor/src/EditorStore.ts b/packages/editor/src/EditorStore.ts index ee478f81..ab213e19 100644 --- a/packages/editor/src/EditorStore.ts +++ b/packages/editor/src/EditorStore.ts @@ -1,4 +1,4 @@ -import { makeAutoObservable } from 'mobx'; +import { makeAutoObservable, autorun, observable } from 'mobx'; import { Application, ApplicationComponent } from '@sunmao-ui/core'; import { ImplementedRuntimeModule } from '@sunmao-ui/runtime'; import { eventBus } from './eventBus'; @@ -11,34 +11,70 @@ class EditorStore { components: ApplicationComponent[] = []; modules: ImplementedRuntimeModule[]; // it could be app or module's name - currentEditingName: string | undefined; + // name is `${module.version}/${module.metadata.name}` + currentEditingName: string = ''; currentEditingType: 'app' | 'module' = 'app'; app: Application; appStorage = new AppStorage(); constructor() { + makeAutoObservable(this, { + components: observable.shallow, + app: observable.shallow, + modules: observable.shallow, + }); this.app = this.appStorage.app; this.modules = this.appStorage.modules; + this.setApp(this.appStorage.app); + this.setModules(this.appStorage.modules); + eventBus.on('selectComponent', id => { this.setSelectedComponentId(id); }); - eventBus.on('componentsChange', components => { - this.setComponents(components); + eventBus.on('appChange', app => { + this.setApp(app); }); eventBus.on('modulesChange', modules => { this.setModules(modules); // reregister modules to activate immediately this.modules.forEach(m => registry.registerModule(m, true)); }); - makeAutoObservable(this); + // listen the change by operations, and save newComponents + eventBus.on('componentsChange', components => { + this.setComponents(components); + this.appStorage.saveComponentsInLS( + this.currentEditingType, + this.currentEditingName, + components + ); + }); + + autorun(() => { + console.log('componentsReload', this.originComponents) + eventBus.send('componentsReload', this.originComponents) + this.setComponents(this.originComponents); + }) + } + + // init components of app of module + get originComponents(): ApplicationComponent[] { + switch (this.currentEditingType) { + case 'module': + const module = this.modules.find( + m => m.metadata.name === this.currentEditingName + ); + return module?.components || []; + case 'app': + console.log('this.app', this.app) + return this.app.spec.components; + } } updateCurrentEditingTarget = (type: 'app' | 'module', name: string) => { - this.appStorage.updateCurrentId(type, name); - // this.setCurrentEditingType(type); - // this.setCurrentEditingName(name); - } + this.setCurrentEditingType(type); + this.setCurrentEditingName(name); + }; setSelectedComponentId(val: string) { this.selectedComponentId = val; @@ -49,12 +85,15 @@ class EditorStore { private setCurrentEditingType(val: 'app' | 'module') { this.currentEditingType = val; } - setComponents(val: ApplicationComponent[]) { + private setComponents(val: ApplicationComponent[]) { this.components = val; } - setModules(val: ImplementedRuntimeModule[]) { + private setModules(val: ImplementedRuntimeModule[]) { this.modules = val; } + private setApp(val: Application) { + this.app = val; + } } export const editorStore = new EditorStore(); diff --git a/packages/editor/src/operations/AppModelManager.ts b/packages/editor/src/operations/AppModelManager.ts index 1fe75529..e8a0f8da 100644 --- a/packages/editor/src/operations/AppModelManager.ts +++ b/packages/editor/src/operations/AppModelManager.ts @@ -6,14 +6,13 @@ export class AppModelManager implements IUndoRedoManager { components: ApplicationComponent[] = []; operationStack: OperationList = new OperationList(); - constructor(components: ApplicationComponent[]) { - this.components = components; - this.updateComponents(components); + constructor() { eventBus.on('undo', () => this.undo()); eventBus.on('redo', () => this.redo()); eventBus.on('operation', o => this.do(o)); eventBus.on('componentsReload', components => { - this.updateComponents(components); + this.components = components; + this.operationStack = new OperationList(); }); } diff --git a/packages/editor/src/setup.ts b/packages/editor/src/setup.ts index 4912c092..8ccf888b 100644 --- a/packages/editor/src/setup.ts +++ b/packages/editor/src/setup.ts @@ -1,5 +1,4 @@ import { initSunmaoUI } from '@sunmao-ui/runtime'; -import { editorStore } from './EditorStore'; import { AppModelManager } from './operations/AppModelManager'; const ui = initSunmaoUI(); @@ -8,7 +7,7 @@ const App = ui.App; const registry = ui.registry; const apiService = ui.apiService; const stateStore = ui.stateManager.store; -const appModelManager = new AppModelManager(editorStore.appStorage.components); +const appModelManager = new AppModelManager(); export { ui, From 69504f008be38ab1a119656804ef9a28afe69503 Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Tue, 30 Nov 2021 15:52:08 +0800 Subject: [PATCH 5/6] appStorage mobx --- packages/editor/src/AppStorage.ts | 29 ++++---- packages/editor/src/EditorStore.ts | 67 +++++++------------ .../src/components/Explorer/Explorer.tsx | 1 - packages/editor/src/eventBus.ts | 11 ++- .../editor/src/operations/AppModelManager.ts | 2 +- 5 files changed, 45 insertions(+), 65 deletions(-) diff --git a/packages/editor/src/AppStorage.ts b/packages/editor/src/AppStorage.ts index 6bd222c5..abaf9071 100644 --- a/packages/editor/src/AppStorage.ts +++ b/packages/editor/src/AppStorage.ts @@ -1,18 +1,22 @@ +import { observable, makeObservable, action } from 'mobx'; import { Application, ApplicationComponent } from '@sunmao-ui/core'; import { ImplementedRuntimeModule } from '@sunmao-ui/runtime'; import { produce } from 'immer'; import { DefaultNewModule, EmptyAppSchema } from './constants'; export class AppStorage { - app: Application; - modules: ImplementedRuntimeModule[]; - // this is current editing Model + app: Application = this.getDefaultAppFromLS(); + modules: ImplementedRuntimeModule[] = this.getModulesFromLS(); static AppLSKey = 'schema'; static ModulesLSKey = 'modules'; constructor() { - this.app = this.getDefaultAppFromLS(); - this.modules = this.getModulesFromLS(); + makeObservable(this, { + app: observable.shallow, + modules: observable.shallow, + setApp: action, + setModules: action + }); } getDefaultAppFromLS(): Application { @@ -45,8 +49,6 @@ export class AppStorage { } removeModule(v: string, n: string) { - console.log(v, n); - console.log(this.modules); this.setModules( this.modules.filter( ({ version, metadata: { name } }) => version !== v && name !== n @@ -80,13 +82,7 @@ export class AppStorage { } } - private setApp(app: Application) { - this.app = app; - } - private setModules(modules: ImplementedRuntimeModule[]) { - this.modules = modules; - } private saveAppInLS() { localStorage.setItem(AppStorage.AppLSKey, JSON.stringify(this.app)); @@ -95,4 +91,11 @@ export class AppStorage { private saveModulesInLS() { localStorage.setItem(AppStorage.ModulesLSKey, JSON.stringify(this.modules)); } + + setApp(app: Application) { + this.app = app; + } + setModules(modules: ImplementedRuntimeModule[]) { + this.modules = modules; + } } diff --git a/packages/editor/src/EditorStore.ts b/packages/editor/src/EditorStore.ts index ab213e19..229e8e8a 100644 --- a/packages/editor/src/EditorStore.ts +++ b/packages/editor/src/EditorStore.ts @@ -1,45 +1,36 @@ import { makeAutoObservable, autorun, observable } from 'mobx'; -import { Application, ApplicationComponent } from '@sunmao-ui/core'; -import { ImplementedRuntimeModule } from '@sunmao-ui/runtime'; +import { ApplicationComponent } from '@sunmao-ui/core'; import { eventBus } from './eventBus'; import { AppStorage } from './AppStorage'; import { registry } from './setup'; class EditorStore { - selectedComponentId = ''; - // currentEditingComponents, it could be app's or module's components components: ApplicationComponent[] = []; - modules: ImplementedRuntimeModule[]; + // currentEditingComponents, it could be app's or module's components + selectedComponentId = ''; // it could be app or module's name // name is `${module.version}/${module.metadata.name}` - currentEditingName: string = ''; + currentEditingName = ''; currentEditingType: 'app' | 'module' = 'app'; - app: Application; appStorage = new AppStorage(); + get app () { + return this.appStorage.app + } + + get modules () { + return this.appStorage.modules + } + constructor() { makeAutoObservable(this, { components: observable.shallow, - app: observable.shallow, - modules: observable.shallow, }); - this.app = this.appStorage.app; - this.modules = this.appStorage.modules; - this.setApp(this.appStorage.app); - this.setModules(this.appStorage.modules); eventBus.on('selectComponent', id => { this.setSelectedComponentId(id); }); - eventBus.on('appChange', app => { - this.setApp(app); - }); - eventBus.on('modulesChange', modules => { - this.setModules(modules); - // reregister modules to activate immediately - this.modules.forEach(m => registry.registerModule(m, true)); - }); // listen the change by operations, and save newComponents eventBus.on('componentsChange', components => { this.setComponents(components); @@ -48,16 +39,20 @@ class EditorStore { this.currentEditingName, components ); + if (this.currentEditingType === 'module') { + // reregister modules to activate immediately + this.modules.forEach(m => registry.registerModule(m, true)); + } }); - + autorun(() => { - console.log('componentsReload', this.originComponents) - eventBus.send('componentsReload', this.originComponents) + eventBus.send('componentsRefresh', this.originComponents); this.setComponents(this.originComponents); - }) + }); } - // init components of app of module + // origin components of app of module + // when switch app or module, components should refresh get originComponents(): ApplicationComponent[] { switch (this.currentEditingType) { case 'module': @@ -66,34 +61,20 @@ class EditorStore { ); return module?.components || []; case 'app': - console.log('this.app', this.app) return this.app.spec.components; } } updateCurrentEditingTarget = (type: 'app' | 'module', name: string) => { - this.setCurrentEditingType(type); - this.setCurrentEditingName(name); + this.currentEditingType = type; + this.currentEditingName = name }; - setSelectedComponentId(val: string) { this.selectedComponentId = val; } - private setCurrentEditingName(val: string) { - this.currentEditingName = val; - } - private setCurrentEditingType(val: 'app' | 'module') { - this.currentEditingType = val; - } - private setComponents(val: ApplicationComponent[]) { + setComponents(val: ApplicationComponent[]) { this.components = val; } - private setModules(val: ImplementedRuntimeModule[]) { - this.modules = val; - } - private setApp(val: Application) { - this.app = val; - } } export const editorStore = new EditorStore(); diff --git a/packages/editor/src/components/Explorer/Explorer.tsx b/packages/editor/src/components/Explorer/Explorer.tsx index 9487d845..41dd3eae 100644 --- a/packages/editor/src/components/Explorer/Explorer.tsx +++ b/packages/editor/src/components/Explorer/Explorer.tsx @@ -25,7 +25,6 @@ export const Explorer: React.FC = observer(() => { /> ); - console.log('modules', modules); const moduleItems = modules.map((module: ImplementedRuntimeModule) => { const moduleItemId = `module_${module.metadata.name}`; const onClickModule = (id: string) => { diff --git a/packages/editor/src/eventBus.ts b/packages/editor/src/eventBus.ts index 80ec9d76..e6a66bc1 100644 --- a/packages/editor/src/eventBus.ts +++ b/packages/editor/src/eventBus.ts @@ -1,20 +1,17 @@ import mitt from 'mitt'; -import { Application, ApplicationComponent } from '@sunmao-ui/core'; +import { ApplicationComponent } from '@sunmao-ui/core'; import { IOperation } from './operations/type'; -import { ImplementedRuntimeModule } from '../../runtime/lib'; export type EventNames = { operation: IOperation; redo: undefined; undo: undefined; - componentsReload: ApplicationComponent[]; + // when switch app or module, current components refresh + componentsRefresh: ApplicationComponent[]; + // components change by operation componentsChange: ApplicationComponent[]; selectComponent: string; hoverComponent: string; - - // for state decorators - appChange: Application; - modulesChange: ImplementedRuntimeModule[]; } const emitter = mitt(); diff --git a/packages/editor/src/operations/AppModelManager.ts b/packages/editor/src/operations/AppModelManager.ts index e8a0f8da..bf36555e 100644 --- a/packages/editor/src/operations/AppModelManager.ts +++ b/packages/editor/src/operations/AppModelManager.ts @@ -10,7 +10,7 @@ export class AppModelManager implements IUndoRedoManager { eventBus.on('undo', () => this.undo()); eventBus.on('redo', () => this.redo()); eventBus.on('operation', o => this.do(o)); - eventBus.on('componentsReload', components => { + eventBus.on('componentsRefresh', components => { this.components = components; this.operationStack = new OperationList(); }); From c1d821143503944bd9b9c35d0e1c07e4eac53c3f Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Wed, 1 Dec 2021 11:12:55 +0800 Subject: [PATCH 6/6] use mobx in ComponentWrapper --- packages/editor/src/EditorStore.ts | 22 ++++++----- .../src/components/ComponentWrapper.tsx | 39 +++++++------------ packages/editor/src/eventBus.ts | 2 +- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/packages/editor/src/EditorStore.ts b/packages/editor/src/EditorStore.ts index 229e8e8a..2d9d90d2 100644 --- a/packages/editor/src/EditorStore.ts +++ b/packages/editor/src/EditorStore.ts @@ -8,6 +8,7 @@ class EditorStore { components: ApplicationComponent[] = []; // currentEditingComponents, it could be app's or module's components selectedComponentId = ''; + hoverComponentId = ''; // it could be app or module's name // name is `${module.version}/${module.metadata.name}` currentEditingName = ''; @@ -15,12 +16,12 @@ class EditorStore { appStorage = new AppStorage(); - get app () { - return this.appStorage.app + get app() { + return this.appStorage.app; } - get modules () { - return this.appStorage.modules + get modules() { + return this.appStorage.modules; } constructor() { @@ -67,14 +68,17 @@ class EditorStore { updateCurrentEditingTarget = (type: 'app' | 'module', name: string) => { this.currentEditingType = type; - this.currentEditingName = name + this.currentEditingName = name; }; - setSelectedComponentId(val: string) { + setSelectedComponentId = (val: string) => { this.selectedComponentId = val; - } - setComponents(val: ApplicationComponent[]) { + }; + setHoverComponentId = (val: string) => { + this.hoverComponentId = val; + }; + setComponents = (val: ApplicationComponent[]) => { this.components = val; - } + }; } export const editorStore = new EditorStore(); diff --git a/packages/editor/src/components/ComponentWrapper.tsx b/packages/editor/src/components/ComponentWrapper.tsx index 35f7b0e3..4f526d20 100644 --- a/packages/editor/src/components/ComponentWrapper.tsx +++ b/packages/editor/src/components/ComponentWrapper.tsx @@ -1,34 +1,25 @@ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import { css } from '@emotion/react'; import { ComponentWrapperType } from '@sunmao-ui/runtime'; -import { eventBus } from '../eventBus'; +import { observer } from 'mobx-react-lite'; +import { editorStore } from '../EditorStore'; // children of components in this list should render height as 100% const fullHeightList = ['core/v1/grid_layout']; const inlineList = ['chakra_ui/v1/checkbox', 'chakra_ui/v1/radio']; -export const ComponentWrapper: ComponentWrapperType = props => { +export const ComponentWrapper: ComponentWrapperType = observer(props => { const { component, parentType } = props; - const [selectedComponentId, setSelectedComponentId] = useState(''); - const [hoverComponentId, setHoverComponentId] = useState(''); - - useEffect(() => { - const handler = (event: string, payload: any) => { - switch (event) { - case 'selectComponent': - setSelectedComponentId(payload); - break; - case 'hoverComponentEvent': - setHoverComponentId(payload); - break; - } - }; - eventBus.on('*', handler); - return () => eventBus.off('*', handler); - }, [setSelectedComponentId, setHoverComponentId]); + const { + selectedComponentId, + setSelectedComponentId, + hoverComponentId, + setHoverComponentId, + } = editorStore; const isHover = hoverComponentId === component.id; const isSelected = selectedComponentId === component.id; + let borderColor = 'transparent'; if (isSelected) { borderColor = 'red'; @@ -52,15 +43,15 @@ export const ComponentWrapper: ComponentWrapperType = props => { `; const onClickWrapper = (e: React.MouseEvent) => { e.stopPropagation(); - eventBus.send('selectComponent' as any, component.id); + setSelectedComponentId(component.id); }; const onMouseEnterWrapper = (e: React.MouseEvent) => { e.stopPropagation(); - eventBus.send('hoverComponentEvent' as any, component.id); + setHoverComponentId(component.id); }; const onMouseLeaveWrapper = (e: React.MouseEvent) => { e.stopPropagation(); - eventBus.send('hoverComponentEvent' as any, ''); + setHoverComponentId(''); }; return (
{ {props.children}
); -}; +}); diff --git a/packages/editor/src/eventBus.ts b/packages/editor/src/eventBus.ts index e6a66bc1..cf090ec1 100644 --- a/packages/editor/src/eventBus.ts +++ b/packages/editor/src/eventBus.ts @@ -10,8 +10,8 @@ export type EventNames = { componentsRefresh: ApplicationComponent[]; // components change by operation componentsChange: ApplicationComponent[]; + // it is only used for some operations' side effect selectComponent: string; - hoverComponent: string; } const emitter = mitt();