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.

session.ts 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import { BaseSession } from './sessions'
  2. /**
  3. * # Session Manager
  4. *
  5. * Sessions are instances that manage data mutations for activities such as
  6. * dragging, transforming, drawing, etc. The session manager singleton provides
  7. * an API with which the state's actions can begin a session and interact it.
  8. *
  9. * A session has a lifecycle:
  10. *
  11. * - it `begin`s when the session instance is created
  12. * - it receives `update`s during the session
  13. * - it ends either when it is `complete`d or `cancel`led
  14. *
  15. * Each session may produce different effects during these life cycles, according
  16. * to its implementation. Most sessions call a command when completed.
  17. *
  18. * It's intended that only a single session occurs at once. This pattern helps
  19. * ensure that we don't accidentally begin a new session before the current one
  20. * is cancelled or completes.
  21. */
  22. class SessionManager {
  23. #current?: BaseSession
  24. /**
  25. * Begin a new session.
  26. * @param session A Session instance.
  27. * @example
  28. * ```ts
  29. * session.begin(new Sessions.EditSession(data))
  30. * ```
  31. */
  32. begin(session: BaseSession) {
  33. if (this.#current) {
  34. throw Error(
  35. 'Cannot begin a session until the current session is complete. This error indicates a problem with the state chart.'
  36. )
  37. }
  38. this.#current = session
  39. return this
  40. }
  41. /**
  42. * Update the current session. Include the session type as a generic in order to properly type the arguments.
  43. * @param args The arguments of the current session's `update` method.
  44. * @example
  45. * ```ts
  46. * session.update<Sessions.EditSession>(data, payload.change)
  47. * ```
  48. */
  49. update<T extends BaseSession>(...args: Parameters<T['update']>) {
  50. const session = this.#current
  51. if (session === undefined) {
  52. throw Error('No current session.')
  53. }
  54. session.update.call(this.#current, ...args)
  55. return this
  56. }
  57. /**
  58. * Complete the current session. Include the session type as a generic in order to properly type the arguments.
  59. * @param args The arguments of the current session's `complete` method.
  60. * @example
  61. * ```ts
  62. * session.update<Sessions.EditSession>(data, payload.change)
  63. * ```
  64. */
  65. complete<T extends BaseSession>(...args: Parameters<T['complete']>) {
  66. const session = this.#current
  67. if (session === undefined) return this
  68. session.complete.call(this.#current, ...args)
  69. this.#current = undefined
  70. return this
  71. }
  72. /**
  73. * Cancel the current session.
  74. * @param args The arguments of the current session's `cancel` method.
  75. * @example
  76. * ```ts
  77. * session.cancel(data)
  78. * ```
  79. */
  80. cancel<T extends BaseSession>(...args: Parameters<T['cancel']>) {
  81. this.#current.cancel.call(this.#current, ...args)
  82. this.#current = undefined
  83. return this
  84. }
  85. }
  86. const session = new SessionManager()
  87. export default session