appState.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import oc from "open-color";
  2. import {
  3. DEFAULT_FONT_FAMILY,
  4. DEFAULT_FONT_SIZE,
  5. DEFAULT_TEXT_ALIGN,
  6. } from "./constants";
  7. import { t } from "./i18n";
  8. import { AppState, NormalizedZoomValue } from "./types";
  9. import { getDateTime } from "./utils";
  10. export const getDefaultAppState = (): Omit<
  11. AppState,
  12. "offsetTop" | "offsetLeft"
  13. > => {
  14. return {
  15. appearance: "light",
  16. collaborators: new Map(),
  17. currentChartType: "bar",
  18. currentItemBackgroundColor: "transparent",
  19. currentItemEndArrowhead: "arrow",
  20. currentItemFillStyle: "hachure",
  21. currentItemFontFamily: DEFAULT_FONT_FAMILY,
  22. currentItemFontSize: DEFAULT_FONT_SIZE,
  23. currentItemLinearStrokeSharpness: "round",
  24. currentItemOpacity: 100,
  25. currentItemRoughness: 1,
  26. currentItemStartArrowhead: null,
  27. currentItemStrokeColor: oc.black,
  28. currentItemStrokeSharpness: "sharp",
  29. currentItemStrokeStyle: "solid",
  30. currentItemStrokeWidth: 1,
  31. currentItemTextAlign: DEFAULT_TEXT_ALIGN,
  32. cursorButton: "up",
  33. draggingElement: null,
  34. editingElement: null,
  35. editingGroupId: null,
  36. editingLinearElement: null,
  37. elementLocked: false,
  38. elementType: "selection",
  39. errorMessage: null,
  40. exportBackground: true,
  41. exportEmbedScene: false,
  42. fileHandle: null,
  43. gridSize: null,
  44. height: window.innerHeight,
  45. isBindingEnabled: true,
  46. isLibraryOpen: false,
  47. isLoading: false,
  48. isResizing: false,
  49. isRotating: false,
  50. lastPointerDownWith: "mouse",
  51. multiElement: null,
  52. name: `${t("labels.untitled")}-${getDateTime()}`,
  53. openMenu: null,
  54. pasteDialog: { shown: false, data: null },
  55. previousSelectedElementIds: {},
  56. resizingElement: null,
  57. scrolledOutside: false,
  58. scrollX: 0,
  59. scrollY: 0,
  60. selectedElementIds: {},
  61. selectedGroupIds: {},
  62. selectionElement: null,
  63. shouldAddWatermark: false,
  64. shouldCacheIgnoreZoom: false,
  65. showHelpDialog: false,
  66. showStats: false,
  67. startBoundElement: null,
  68. suggestedBindings: [],
  69. toastMessage: null,
  70. viewBackgroundColor: oc.white,
  71. width: window.innerWidth,
  72. zenModeEnabled: false,
  73. zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } },
  74. viewModeEnabled: false,
  75. };
  76. };
  77. /**
  78. * Config containing all AppState keys. Used to determine whether given state
  79. * prop should be stripped when exporting to given storage type.
  80. */
  81. const APP_STATE_STORAGE_CONF = (<
  82. Values extends {
  83. /** whether to keep when storing to browser storage (localStorage/IDB) */
  84. browser: boolean;
  85. /** whether to keep when exporting to file/database */
  86. export: boolean;
  87. },
  88. T extends Record<keyof AppState, Values>
  89. >(
  90. config: { [K in keyof T]: K extends keyof AppState ? T[K] : never },
  91. ) => config)({
  92. appearance: { browser: true, export: false },
  93. collaborators: { browser: false, export: false },
  94. currentChartType: { browser: true, export: false },
  95. currentItemBackgroundColor: { browser: true, export: false },
  96. currentItemEndArrowhead: { browser: true, export: false },
  97. currentItemFillStyle: { browser: true, export: false },
  98. currentItemFontFamily: { browser: true, export: false },
  99. currentItemFontSize: { browser: true, export: false },
  100. currentItemLinearStrokeSharpness: { browser: true, export: false },
  101. currentItemOpacity: { browser: true, export: false },
  102. currentItemRoughness: { browser: true, export: false },
  103. currentItemStartArrowhead: { browser: true, export: false },
  104. currentItemStrokeColor: { browser: true, export: false },
  105. currentItemStrokeSharpness: { browser: true, export: false },
  106. currentItemStrokeStyle: { browser: true, export: false },
  107. currentItemStrokeWidth: { browser: true, export: false },
  108. currentItemTextAlign: { browser: true, export: false },
  109. cursorButton: { browser: true, export: false },
  110. draggingElement: { browser: false, export: false },
  111. editingElement: { browser: false, export: false },
  112. editingGroupId: { browser: true, export: false },
  113. editingLinearElement: { browser: false, export: false },
  114. elementLocked: { browser: true, export: false },
  115. elementType: { browser: true, export: false },
  116. errorMessage: { browser: false, export: false },
  117. exportBackground: { browser: true, export: false },
  118. exportEmbedScene: { browser: true, export: false },
  119. fileHandle: { browser: false, export: false },
  120. gridSize: { browser: true, export: true },
  121. height: { browser: false, export: false },
  122. isBindingEnabled: { browser: false, export: false },
  123. isLibraryOpen: { browser: false, export: false },
  124. isLoading: { browser: false, export: false },
  125. isResizing: { browser: false, export: false },
  126. isRotating: { browser: false, export: false },
  127. lastPointerDownWith: { browser: true, export: false },
  128. multiElement: { browser: false, export: false },
  129. name: { browser: true, export: false },
  130. offsetLeft: { browser: false, export: false },
  131. offsetTop: { browser: false, export: false },
  132. openMenu: { browser: true, export: false },
  133. pasteDialog: { browser: false, export: false },
  134. previousSelectedElementIds: { browser: true, export: false },
  135. resizingElement: { browser: false, export: false },
  136. scrolledOutside: { browser: true, export: false },
  137. scrollX: { browser: true, export: false },
  138. scrollY: { browser: true, export: false },
  139. selectedElementIds: { browser: true, export: false },
  140. selectedGroupIds: { browser: true, export: false },
  141. selectionElement: { browser: false, export: false },
  142. shouldAddWatermark: { browser: true, export: false },
  143. shouldCacheIgnoreZoom: { browser: true, export: false },
  144. showHelpDialog: { browser: false, export: false },
  145. showStats: { browser: true, export: false },
  146. startBoundElement: { browser: false, export: false },
  147. suggestedBindings: { browser: false, export: false },
  148. toastMessage: { browser: false, export: false },
  149. viewBackgroundColor: { browser: true, export: true },
  150. width: { browser: false, export: false },
  151. zenModeEnabled: { browser: true, export: false },
  152. zoom: { browser: true, export: false },
  153. viewModeEnabled: { browser: false, export: false },
  154. });
  155. const _clearAppStateForStorage = <ExportType extends "export" | "browser">(
  156. appState: Partial<AppState>,
  157. exportType: ExportType,
  158. ) => {
  159. type ExportableKeys = {
  160. [K in keyof typeof APP_STATE_STORAGE_CONF]: typeof APP_STATE_STORAGE_CONF[K][ExportType] extends true
  161. ? K
  162. : never;
  163. }[keyof typeof APP_STATE_STORAGE_CONF];
  164. const stateForExport = {} as { [K in ExportableKeys]?: typeof appState[K] };
  165. for (const key of Object.keys(appState) as (keyof typeof appState)[]) {
  166. const propConfig = APP_STATE_STORAGE_CONF[key];
  167. if (propConfig?.[exportType]) {
  168. // @ts-ignore see https://github.com/microsoft/TypeScript/issues/31445
  169. stateForExport[key] = appState[key];
  170. }
  171. }
  172. return stateForExport;
  173. };
  174. export const clearAppStateForLocalStorage = (appState: Partial<AppState>) => {
  175. return _clearAppStateForStorage(appState, "browser");
  176. };
  177. export const cleanAppStateForExport = (appState: Partial<AppState>) => {
  178. return _clearAppStateForStorage(appState, "export");
  179. };