tldraw/state/commands/command.ts

96 lines
2.6 KiB
TypeScript
Raw Normal View History

import { Data } from 'types'
2021-06-24 08:18:14 +00:00
import { getSelectedIds, setSelectedIds, setToArray } from 'utils'
2021-05-10 12:16:57 +00:00
/* ------------------ Command Class ----------------- */
export type CommandFn<T> = (data: T, initial?: boolean) => void
/**
* A command makes changes to some applicate state. Every command has an "undo"
* method to reverse its changes. The apps history is a series of commands.
*/
export class BaseCommand<T extends any> {
timestamp = Date.now()
2021-05-13 06:44:52 +00:00
name: string
category: string
2021-05-10 12:16:57 +00:00
private undoFn: CommandFn<T>
private doFn: CommandFn<T>
protected restoreBeforeSelectionState: (data: T) => void
protected restoreAfterSelectionState: (data: T) => void
protected saveSelectionState: (data: T) => (data: T) => void
protected manualSelection: boolean
constructor(options: {
do: CommandFn<T>
undo: CommandFn<T>
2021-05-13 06:44:52 +00:00
name: string
category: string
2021-05-10 12:16:57 +00:00
manualSelection?: boolean
}) {
2021-05-13 06:44:52 +00:00
this.name = options.name
this.category = options.category
2021-05-10 12:16:57 +00:00
this.doFn = options.do
this.undoFn = options.undo
this.manualSelection = options.manualSelection || false
this.restoreBeforeSelectionState = () => () => {
null
}
this.restoreAfterSelectionState = () => () => {
null
}
}
2021-06-21 21:35:28 +00:00
undo = (data: T): void => {
2021-05-10 12:16:57 +00:00
if (this.manualSelection) {
this.undoFn(data)
return
}
// We need to set the selection state to what it was before we after we did the command
this.restoreAfterSelectionState(data)
this.undoFn(data)
this.restoreBeforeSelectionState(data)
}
2021-06-21 21:35:28 +00:00
redo = (data: T, initial = false): void => {
if (this.manualSelection) {
this.doFn(data, initial)
return
}
2021-05-10 12:16:57 +00:00
if (initial) {
this.restoreBeforeSelectionState = this.saveSelectionState(data)
} else {
this.restoreBeforeSelectionState(data)
}
// We need to set the selection state to what it was before we did the command
this.doFn(data, initial)
if (initial) {
this.restoreAfterSelectionState = this.saveSelectionState(data)
}
}
}
/* ---------------- Project Specific ---------------- */
/**
* A subclass of BaseCommand that sends events to our state. In our case, we want our actions
* to mutate the state's data. Actions do not effect the "active states" in
* the app.
*/
2021-05-13 06:44:52 +00:00
export default class Command extends BaseCommand<Data> {
2021-06-21 21:35:28 +00:00
saveSelectionState = (data: Data): ((next: Data) => void) => {
const { currentPageId } = data
const selectedIds = setToArray(getSelectedIds(data))
return (next: Data) => {
next.currentPageId = currentPageId
next.hoveredId = undefined
next.pointedId = undefined
setSelectedIds(next, selectedIds)
2021-05-13 06:44:52 +00:00
}
2021-05-10 12:16:57 +00:00
}
}