import { Data } from 'types' import { setToArray } from 'utils' import tld from 'utils/tld' /* ------------------ Command Class ----------------- */ export type CommandFn = (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 { timestamp = Date.now() name: string category: string private undoFn: CommandFn private doFn: CommandFn protected restoreBeforeSelectionState: (data: T) => void protected restoreAfterSelectionState: (data: T) => void protected saveSelectionState: (data: T) => (data: T) => void protected manualSelection: boolean constructor(options: { do: CommandFn undo: CommandFn name: string category: string manualSelection?: boolean }) { this.name = options.name this.category = options.category this.doFn = options.do this.undoFn = options.undo this.manualSelection = options.manualSelection || false this.restoreBeforeSelectionState = () => () => { null } this.restoreAfterSelectionState = () => () => { null } } undo = (data: T): void => { 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) } redo = (data: T, initial = false): void => { if (this.manualSelection) { this.doFn(data, initial) return } 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. */ export default class Command extends BaseCommand { saveSelectionState = (data: Data): ((next: Data) => void) => { const { currentPageId } = data const selectedIds = setToArray(tld.getSelectedIds(data)) return (next: Data) => { next.currentPageId = currentPageId next.hoveredId = undefined next.pointedId = undefined tld.setSelectedIds(next, selectedIds) } } }