@infinite-canvas-tutorial/webcomponents
Version:
WebComponents UI implementation
112 lines • 4.38 kB
JavaScript
/**
* Borrow from https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/store.ts
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Store = exports.CaptureUpdateAction = exports.StoreIncrementEvent = void 0;
const eventemitter3_1 = require("eventemitter3");
const AppStateChange_1 = require("./AppStateChange");
const ElementsChange_1 = require("./ElementsChange");
const Snapshot_1 = require("./Snapshot");
exports.StoreIncrementEvent = 'storeIncrement';
exports.CaptureUpdateAction = {
/**
* Immediately undoable.
*
* Use for updates which should be captured.
* Should be used for most of the local updates.
*
* These updates will _immediately_ make it to the local undo / redo stacks.
*/
IMMEDIATELY: 'IMMEDIATELY',
/**
* Never undoable.
*
* Use for updates which should never be recorded, such as remote updates
* or scene initialization.
*
* These updates will _never_ make it to the local undo / redo stacks.
*/
NEVER: 'NEVER',
/**
* Eventually undoable.
*
* Use for updates which should not be captured immediately - likely
* exceptions which are part of some async multi-step process. Otherwise, all
* such updates would end up being captured with the next
* `CaptureUpdateAction.IMMEDIATELY` - triggered either by the next `updateScene`
* or internally by the editor.
*
* These updates will _eventually_ make it to the local undo / redo stacks.
*/
EVENTUALLY: 'EVENTUALLY',
};
class Store {
constructor() {
this._snapshot = Snapshot_1.Snapshot.empty();
this.scheduledActions = new Set();
this.onStoreIncrementEmitter = new eventemitter3_1.EventEmitter();
}
get snapshot() {
return this._snapshot;
}
set snapshot(snapshot) {
this._snapshot = snapshot;
}
scheduleAction(action) {
this.scheduledActions.add(action);
}
shouldCaptureIncrement() {
this.scheduleAction(exports.CaptureUpdateAction.IMMEDIATELY);
}
shouldUpdateSnapshot() {
this.scheduleAction(exports.CaptureUpdateAction.NEVER);
}
commit(elements, appState) {
try {
// Capture has precedence since it also performs update
if (this.scheduledActions.has(exports.CaptureUpdateAction.IMMEDIATELY)) {
this.captureIncrement(elements, appState);
}
else if (this.scheduledActions.has(exports.CaptureUpdateAction.NEVER)) {
this.updateSnapshot(elements, appState);
}
}
finally {
// Defensively reset all scheduled actions, potentially cleans up other runtime garbage
this.scheduledActions = new Set();
}
}
captureIncrement(elements, appState) {
const prevSnapshot = this.snapshot;
const nextSnapshot = this.snapshot.maybeClone(elements, appState);
// Optimisation, don't continue if nothing has changed
if (prevSnapshot !== nextSnapshot) {
// Calculate and record the changes based on the previous and next snapshot
const elementsChange = nextSnapshot.meta.didElementsChange
? ElementsChange_1.ElementsChange.calculate(prevSnapshot.elements, nextSnapshot.elements)
: ElementsChange_1.ElementsChange.empty();
const appStateChange = nextSnapshot.meta.didAppStateChange
? AppStateChange_1.AppStateChange.calculate(prevSnapshot.appState, nextSnapshot.appState)
: AppStateChange_1.AppStateChange.empty();
if (!elementsChange.isEmpty() || !appStateChange.isEmpty()) {
// Notify listeners with the increment
this.onStoreIncrementEmitter.emit(exports.StoreIncrementEvent, {
elementsChange,
appStateChange,
});
}
// Update snapshot
this.snapshot = nextSnapshot;
}
}
updateSnapshot(elements, appState) {
const nextSnapshot = this.snapshot.maybeClone(elements, appState);
if (this.snapshot !== nextSnapshot) {
// Update snapshot
this.snapshot = nextSnapshot;
}
}
}
exports.Store = Store;
//# sourceMappingURL=Store.js.map
;