You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

command.ts 2.4KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { Data } from "types"
  2. /* ------------------ Command Class ----------------- */
  3. export type CommandFn<T> = (data: T, initial?: boolean) => void
  4. /**
  5. * A command makes changes to some applicate state. Every command has an "undo"
  6. * method to reverse its changes. The apps history is a series of commands.
  7. */
  8. export class BaseCommand<T extends any> {
  9. timestamp = Date.now()
  10. name: string
  11. category: string
  12. private undoFn: CommandFn<T>
  13. private doFn: CommandFn<T>
  14. protected restoreBeforeSelectionState: (data: T) => void
  15. protected restoreAfterSelectionState: (data: T) => void
  16. protected saveSelectionState: (data: T) => (data: T) => void
  17. protected manualSelection: boolean
  18. constructor(options: {
  19. do: CommandFn<T>
  20. undo: CommandFn<T>
  21. name: string
  22. category: string
  23. manualSelection?: boolean
  24. }) {
  25. this.name = options.name
  26. this.category = options.category
  27. this.doFn = options.do
  28. this.undoFn = options.undo
  29. this.manualSelection = options.manualSelection || false
  30. this.restoreBeforeSelectionState = () => () => {
  31. null
  32. }
  33. this.restoreAfterSelectionState = () => () => {
  34. null
  35. }
  36. }
  37. undo = (data: T) => {
  38. if (this.manualSelection) {
  39. this.undoFn(data)
  40. return
  41. }
  42. // We need to set the selection state to what it was before we after we did the command
  43. this.restoreAfterSelectionState(data)
  44. this.undoFn(data)
  45. this.restoreBeforeSelectionState(data)
  46. }
  47. redo = (data: T, initial = false) => {
  48. if (initial) {
  49. this.restoreBeforeSelectionState = this.saveSelectionState(data)
  50. } else {
  51. this.restoreBeforeSelectionState(data)
  52. }
  53. // We need to set the selection state to what it was before we did the command
  54. this.doFn(data, initial)
  55. if (initial) {
  56. this.restoreAfterSelectionState = this.saveSelectionState(data)
  57. }
  58. }
  59. }
  60. /* ---------------- Project Specific ---------------- */
  61. /**
  62. * A subclass of BaseCommand that sends events to our state. In our case, we want our actions
  63. * to mutate the state's data. Actions do not effect the "active states" in
  64. * the app.
  65. */
  66. export default class Command extends BaseCommand<Data> {
  67. saveSelectionState = (data: Data) => {
  68. const selectedIds = new Set(data.selectedIds)
  69. return (data: Data) => {
  70. data.hoveredId = undefined
  71. data.pointedId = undefined
  72. data.selectedIds = selectedIds
  73. }
  74. }
  75. }