mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Make all operations on elements array immutable (#283)
* Make scene functions return array instead of mutate array - Not all functions were changes; so the given argument was a new array to some * Make data restoration functions immutable - Make mutations in App component * Make history actions immutable * Fix an issue in change property that was causing elements to be removed * mark elements params as readonly & remove unnecessary copying * Make `clearSelection` return a new array * Perform Id comparisons instead of reference comparisons in onDoubleClick * Allow deselecting items with SHIFT key - Refactor hit detection code * Fix a bug in element selection and revert drag functionality Co-authored-by: David Luzar <luzar.david@gmail.com>
This commit is contained in:
parent
1ea72e9134
commit
862231da4f
11 changed files with 239 additions and 157 deletions
|
@ -5,7 +5,7 @@ class SceneHistory {
|
|||
private stateHistory: string[] = [];
|
||||
private redoStack: string[] = [];
|
||||
|
||||
generateCurrentEntry(elements: ExcalidrawElement[]) {
|
||||
generateCurrentEntry(elements: readonly ExcalidrawElement[]) {
|
||||
return JSON.stringify(
|
||||
elements.map(element => ({ ...element, isSelected: false }))
|
||||
);
|
||||
|
@ -22,30 +22,33 @@ class SceneHistory {
|
|||
this.stateHistory.push(newEntry);
|
||||
}
|
||||
|
||||
restoreEntry(elements: ExcalidrawElement[], entry: string) {
|
||||
const newElements = JSON.parse(entry);
|
||||
elements.splice(0, elements.length);
|
||||
newElements.forEach((newElement: ExcalidrawElement) => {
|
||||
elements.push(newElement);
|
||||
});
|
||||
restoreEntry(entry: string) {
|
||||
// When restoring, we shouldn't add an history entry otherwise we'll be stuck with it and can't go back
|
||||
this.skipRecording();
|
||||
|
||||
try {
|
||||
return JSON.parse(entry);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
clearRedoStack() {
|
||||
this.redoStack.splice(0, this.redoStack.length);
|
||||
}
|
||||
|
||||
redoOnce(elements: ExcalidrawElement[]) {
|
||||
redoOnce(elements: readonly ExcalidrawElement[]) {
|
||||
const currentEntry = this.generateCurrentEntry(elements);
|
||||
const entryToRestore = this.redoStack.pop();
|
||||
if (entryToRestore !== undefined) {
|
||||
this.restoreEntry(elements, entryToRestore);
|
||||
this.stateHistory.push(currentEntry);
|
||||
return this.restoreEntry(entryToRestore);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
undoOnce(elements: ExcalidrawElement[]) {
|
||||
undoOnce(elements: readonly ExcalidrawElement[]) {
|
||||
const currentEntry = this.generateCurrentEntry(elements);
|
||||
let entryToRestore = this.stateHistory.pop();
|
||||
|
||||
|
@ -54,9 +57,11 @@ class SceneHistory {
|
|||
entryToRestore = this.stateHistory.pop();
|
||||
}
|
||||
if (entryToRestore !== undefined) {
|
||||
this.restoreEntry(elements, entryToRestore);
|
||||
this.redoStack.push(currentEntry);
|
||||
return this.restoreEntry(entryToRestore);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
isRecording() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue