Skip to content
This repository was archived by the owner on Jul 8, 2025. It is now read-only.

Commit 669e6a5

Browse files
committed
feat(editor): supporting undo & redo
1 parent 9f45cd4 commit 669e6a5

File tree

8 files changed

+82
-61
lines changed

8 files changed

+82
-61
lines changed

packages/editor/src/libs/history/decorators.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,16 @@ export const withSnapshot = (payload?: Record<string, any>) => (
4747
};
4848
};
4949

50-
export function actionWithSnapshot(target: object, propertyKey: string, descriptor?: PropertyDescriptor): void;
51-
export function actionWithSnapshot(
52-
payload: Record<string, any>,
53-
): (target: object, propertyKey: string, descriptor?: PropertyDescriptor) => void;
54-
export function actionWithSnapshot(
50+
interface ActionWithSnapshot {
51+
(target: object, propertyKey: string, descriptor?: PropertyDescriptor): void;
52+
(payload: Record<string, any>): (target: object, propertyKey: string, descriptor?: PropertyDescriptor) => void;
53+
}
54+
55+
export const actionWithSnapshot: ActionWithSnapshot = (
5556
payloadOrTarget: Record<string, any> | object,
5657
propertyKey?: string,
5758
descriptor?: PropertyDescriptor,
58-
) {
59+
) => {
5960
if (!propertyKey) {
6061
const payload = payloadOrTarget as Record<string, any>;
6162
return (target: object, propertyKey: string, descriptor?: PropertyDescriptor) => {
@@ -66,5 +67,5 @@ export function actionWithSnapshot(
6667

6768
const target = payloadOrTarget as object;
6869
withSnapshot(undefined)(target, propertyKey, descriptor);
69-
return action(target, propertyKey, descriptor);
70-
}
70+
return action(target, propertyKey, descriptor) as any;
71+
};
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
import { isArray, isMap, isObject, isFunction } from './utils';
22

3-
export function dehydrate(model: any) {
4-
if (isArray(model)) {
5-
return model.length ? model.map(dehydrate) : [];
3+
export function dehydrate(state: any) {
4+
if (isArray(state)) {
5+
return state.length ? state.map(dehydrate) : [];
66
}
77

8-
if (isMap(model)) {
9-
if (model.size) {
8+
if (isMap(state)) {
9+
if (state.size) {
1010
const map: { [key: string]: any } = {};
11-
model.forEach((value: any, key: string) => {
11+
state.forEach((value: any, key: string) => {
1212
map[key] = dehydrate(value);
1313
});
1414
return map;
1515
}
1616
return {};
1717
}
1818

19-
if (isObject(model)) {
20-
return Object.keys(model).reduce<Record<string, any>>((acc, stateName) => {
21-
const value = dehydrate(model[stateName]);
19+
if (isObject(state)) {
20+
return Object.keys(state).reduce<Record<string, any>>((acc, stateName) => {
21+
const value = dehydrate(state[stateName]);
2222
if (value !== undefined) {
2323
acc[stateName] = value;
2424
}
2525
return acc;
2626
}, {});
2727
}
2828

29-
if (isFunction(model)) {
29+
if (isFunction(state)) {
3030
return undefined;
3131
}
3232

33-
return model;
33+
return state;
3434
}

packages/editor/src/states/components.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class ComponentsStore extends StoreWithUtils<ComponentsStore> {
2727
constructor() {
2828
super();
2929
timeTraveler.onRestore((type, nextSnapshots, currentSnapshots) => {
30-
if (nextSnapshots?.payload?.needReloadIndex || currentSnapshots?.payload?.needReloadIndex) {
30+
if (nextSnapshots?.payload?.needReloadComponentsIndex || currentSnapshots?.payload?.needReloadComponentsIndex) {
3131
regenerateAllPagesComponentsIndex();
3232
}
3333
});
@@ -52,7 +52,7 @@ export class ComponentsStore extends StoreWithUtils<ComponentsStore> {
5252
return newInstances;
5353
};
5454

55-
@actionWithSnapshot({ needReloadIndex: true })
55+
@actionWithSnapshot({ needReloadComponentsIndex: true })
5656
public addComponentInstance = (componentID: string) => {
5757
return this.setCurrentPageComponentInstances(instances => {
5858
const component = getMaterialsComponentMeta(componentID)!;
@@ -73,7 +73,7 @@ export class ComponentsStore extends StoreWithUtils<ComponentsStore> {
7373
});
7474
};
7575

76-
@actionWithSnapshot({ needReloadIndex: true })
76+
@actionWithSnapshot({ needReloadComponentsIndex: true })
7777
private addComponentInstanceAsChildren = (instance: ComponentInstance) => {
7878
return this.setCurrentPageComponentInstances(instances => {
7979
const { index: parentIndex } = getCurrentPageComponentIndex(selectStore.containerComponentKey)!;
@@ -92,7 +92,7 @@ export class ComponentsStore extends StoreWithUtils<ComponentsStore> {
9292
});
9393
};
9494

95-
@actionWithSnapshot({ needReloadIndex: true, needReloadDeps: true })
95+
@actionWithSnapshot({ needReloadComponentsIndex: true, needReloadDeps: true })
9696
public deleteComponentInstance = (key: number) => {
9797
if (!getCurrentPageComponentIndex(key)) {
9898
return sharedStore.deleteSharedComponentInstance(key);
@@ -115,7 +115,7 @@ export class ComponentsStore extends StoreWithUtils<ComponentsStore> {
115115
return deletedInstance!;
116116
};
117117

118-
@actionWithSnapshot({ needReloadIndex: true })
118+
@actionWithSnapshot({ needReloadComponentsIndex: true })
119119
public resortComponentInstance = (key: number, oldIndex: number, newIndex: number) => {
120120
if (oldIndex === newIndex) {
121121
return;
@@ -136,7 +136,7 @@ export class ComponentsStore extends StoreWithUtils<ComponentsStore> {
136136
});
137137
};
138138

139-
@actionWithSnapshot({ needReloadIndex: true })
139+
@actionWithSnapshot({ needReloadComponentsIndex: true })
140140
public moveComponentInstance = (oldIndex: ComponentIndex, newIndex: ComponentIndex) => {
141141
if (compareComponentIndex(oldIndex, newIndex)) {
142142
return;

packages/editor/src/states/events.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
createEventInstance,
2929
regenerateAllEventDeps,
3030
} from 'libs';
31-
import { timeTraveler } from 'libs/history';
31+
import { timeTraveler, actionWithSnapshot } from 'libs/history';
3232
import { getMaterialsActionMeta } from 'runtime';
3333
import { selectStore, SelectType } from './select';
3434
import { componentsStore } from './components';
@@ -40,13 +40,13 @@ import { pagesStore } from './pages';
4040
export class EventStore {
4141
constructor() {
4242
timeTraveler.onRestore((type, nextSnapshots, currentSnapshots) => {
43-
if (nextSnapshots.payload.needReloadDeps || currentSnapshots.payload.needReloadDeps) {
43+
if (nextSnapshots?.payload?.needReloadDeps || currentSnapshots?.payload?.needReloadDeps) {
4444
regenerateAllEventDeps();
4545
}
4646
});
4747
}
4848

49-
@action
49+
@actionWithSnapshot({ needReloadDeps: true })
5050
public addEventInstance = (triggerName: EventTriggerName, target: EventTarget) => {
5151
const action = target.type === EventTargetType.Action ? getMaterialsActionMeta(target.id)! : undefined;
5252

@@ -183,7 +183,7 @@ export class EventStore {
183183
}
184184
};
185185

186-
@action
186+
@actionWithSnapshot({ needReloadDeps: true })
187187
public deleteEventInstance = (index: number) => {
188188
let eventInstance: EventInstance;
189189
switch (selectStore.selectType) {
@@ -276,7 +276,7 @@ export class EventStore {
276276
}
277277
};
278278

279-
@action
279+
@actionWithSnapshot({ needReloadDeps: true })
280280
public deleteDepsEventInstances = (type: DepsTargetType, key: number) => {
281281
let deps: Maybe<DepFrom[]>;
282282
switch (type) {
@@ -323,42 +323,42 @@ export class EventStore {
323323
});
324324
};
325325

326-
@action
326+
@actionWithSnapshot
327327
public setEventInstanceDataOfCurrentComponentInstance = (data: object, index: number) => {
328328
return componentsStore.setCurrentComponentInstanceEvents(events => {
329329
events[index]!.data = data;
330330
});
331331
};
332332

333-
@action
333+
@actionWithSnapshot
334334
public setEventInstanceDataOfCurrentPluginInstance = (data: object, index: number) => {
335335
return pluginsStore.setCurrentPluginInstanceEvents(events => {
336336
events[index]!.data = data;
337337
});
338338
};
339339

340-
@action
340+
@actionWithSnapshot
341341
public setEventInstanceDataOfCurrentHotArea = (data: object, index: number) => {
342342
return hotAreaStore.setCurrentHotAreaEvents(events => {
343343
events[index]!.data = data;
344344
});
345345
};
346346

347-
@action
347+
@actionWithSnapshot
348348
public setEventInstanceDataOfGlobal = (data: object, index: number) => {
349349
return globalStore.setGlobalEvents(events => {
350350
events[index]!.data = data;
351351
});
352352
};
353353

354-
@action
354+
@actionWithSnapshot
355355
public setEventInstanceDataOfCurrentPage = (data: object, index: number) => {
356356
return pagesStore.setCurrentPage(page => {
357357
page.events[index]!.data = data;
358358
});
359359
};
360360

361-
@action
361+
@actionWithSnapshot
362362
public resortEventInstanceFromCurrentComponentInstance = (oldIndex: number, newIndex: number) => {
363363
if (oldIndex === newIndex) {
364364
return;
@@ -370,7 +370,7 @@ export class EventStore {
370370
});
371371
};
372372

373-
@action
373+
@actionWithSnapshot
374374
public resortEventInstanceFromCurrentPluginInstance = (oldIndex: number, newIndex: number) => {
375375
if (oldIndex === newIndex) {
376376
return;
@@ -382,7 +382,7 @@ export class EventStore {
382382
});
383383
};
384384

385-
@action
385+
@actionWithSnapshot
386386
public resortEventInstanceFromCurrentHotArea = (oldIndex: number, newIndex: number) => {
387387
if (oldIndex === newIndex) {
388388
return;
@@ -394,7 +394,7 @@ export class EventStore {
394394
});
395395
};
396396

397-
@action
397+
@actionWithSnapshot
398398
public resortEventInstanceFromGlobal = (oldIndex: number, newIndex: number) => {
399399
if (oldIndex === newIndex) {
400400
return;

packages/editor/src/states/global.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { action, observable } from 'mobx';
22
import { getFormDefaultValue, getQueryParams } from 'utils';
33
import { getMaterialsContainerMeta } from 'libs';
4+
import { actionWithSnapshot } from 'libs/history';
45
import { EventInstance, GlobalMeta } from 'types';
56
import { StoreWithUtils } from './utils';
67

@@ -26,13 +27,13 @@ export class GlobalStore extends StoreWithUtils<GlobalStore> {
2627
@observable
2728
public globalData: object = {};
2829

29-
@action
30+
@actionWithSnapshot
3031
public setGlobalData = (data: object) => (this.globalData = data);
3132

3233
@observable
3334
public globalStyle: object = {};
3435

35-
@action
36+
@actionWithSnapshot
3637
public setGlobalStyle = (data: object) => (this.globalStyle = data);
3738

3839
/**
@@ -41,7 +42,7 @@ export class GlobalStore extends StoreWithUtils<GlobalStore> {
4142
@observable
4243
public globalEvents: EventInstance[] = [];
4344

44-
@action
45+
@actionWithSnapshot({ needReloadDeps: true })
4546
public setGlobalEvents = (setter: (events: EventInstance[]) => EventInstance[] | void) => {
4647
const newEvents = setter(this.globalEvents);
4748
if (newEvents) {
@@ -63,7 +64,7 @@ export class GlobalStore extends StoreWithUtils<GlobalStore> {
6364
isEditor: true,
6465
};
6566

66-
@action
67+
@actionWithSnapshot
6768
public setMetaInfo = (data: Partial<GlobalMeta>) => (this.metaInfo = { ...this.metaInfo, ...data });
6869
}
6970

packages/editor/src/states/hotAreas.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { action } from 'mobx';
21
import { EventInstance, HotArea, Maybe } from 'types';
2+
import { actionWithSnapshot } from 'libs/history';
33
import { componentsStore } from './components';
44
import { selectStore } from './select';
55

@@ -17,12 +17,12 @@ export class HotAreasStore {
1717
return component.hotAreas?.[hotAreaIndex];
1818
};
1919

20-
@action
20+
@actionWithSnapshot
2121
public setCurrentComponentHotAreas = (hotAreas: HotArea[]) => {
2222
return componentsStore.setCurrentComponentInstanceHotAreas(() => hotAreas);
2323
};
2424

25-
@action
25+
@actionWithSnapshot
2626
public setCurrentComponentHotArea = (setter: (hotArea: HotArea) => HotArea) => {
2727
const { hotAreaIndex } = selectStore;
2828
return componentsStore.setCurrentComponentInstanceHotAreas(hotAreas => {
@@ -32,7 +32,7 @@ export class HotAreasStore {
3232
});
3333
};
3434

35-
@action
35+
@actionWithSnapshot({ needReloadDeps: true })
3636
public setCurrentHotAreaEvents = (setter: (eventInstances: EventInstance[]) => EventInstance[] | void) => {
3737
return this.setCurrentComponentHotArea(hotarea => {
3838
const events = setter(hotarea.events);
@@ -43,7 +43,7 @@ export class HotAreasStore {
4343
});
4444
};
4545

46-
@action
46+
@actionWithSnapshot
4747
public setHotAreaProps = (
4848
componentKey: number,
4949
hotAreaIndex: number,
@@ -58,7 +58,7 @@ export class HotAreasStore {
5858
});
5959
};
6060

61-
@action
61+
@actionWithSnapshot({ needReloadDeps: true })
6262
public deleteHotArea = (componentKey: number, hotAreaIndex: number) => {
6363
return componentsStore.setComponentInstancePropsByKey(componentKey, ({ hotAreas }) => {
6464
hotAreas!.splice(hotAreaIndex, 1);

0 commit comments

Comments
 (0)