json.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { fileOpen, fileSave } from "./filesystem";
  2. import { cleanAppStateForExport } from "../appState";
  3. import { EXPORT_DATA_TYPES, EXPORT_SOURCE, MIME_TYPES } from "../constants";
  4. import { clearElementsForExport } from "../element";
  5. import { ExcalidrawElement } from "../element/types";
  6. import { AppState } from "../types";
  7. import { isImageFileHandle, loadFromBlob } from "./blob";
  8. import {
  9. ExportedDataState,
  10. ImportedDataState,
  11. ExportedLibraryData,
  12. } from "./types";
  13. import Library from "./library";
  14. export const serializeAsJSON = (
  15. elements: readonly ExcalidrawElement[],
  16. appState: Partial<AppState>,
  17. ): string => {
  18. const data: ExportedDataState = {
  19. type: EXPORT_DATA_TYPES.excalidraw,
  20. version: 2,
  21. source: EXPORT_SOURCE,
  22. elements: clearElementsForExport(elements),
  23. appState: cleanAppStateForExport(appState),
  24. };
  25. return JSON.stringify(data, null, 2);
  26. };
  27. export const saveAsJSON = async (
  28. elements: readonly ExcalidrawElement[],
  29. appState: AppState,
  30. ) => {
  31. const serialized = serializeAsJSON(elements, appState);
  32. const blob = new Blob([serialized], {
  33. type: MIME_TYPES.excalidraw,
  34. });
  35. const fileHandle = await fileSave(blob, {
  36. name: appState.name,
  37. extension: "excalidraw",
  38. description: "Excalidraw file",
  39. fileHandle: isImageFileHandle(appState.fileHandle)
  40. ? null
  41. : appState.fileHandle,
  42. });
  43. return { fileHandle };
  44. };
  45. export const loadFromJSON = async (
  46. localAppState: AppState,
  47. localElements: readonly ExcalidrawElement[] | null,
  48. ) => {
  49. const blob = await fileOpen({
  50. description: "Excalidraw files",
  51. // ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
  52. // gets resolved. Else, iOS users cannot open `.excalidraw` files.
  53. /*
  54. extensions: [".json", ".excalidraw", ".png", ".svg"],
  55. mimeTypes: [
  56. MIME_TYPES.excalidraw,
  57. "application/json",
  58. "image/png",
  59. "image/svg+xml",
  60. ],
  61. */
  62. });
  63. return loadFromBlob(blob, localAppState, localElements);
  64. };
  65. export const isValidExcalidrawData = (data?: {
  66. type?: any;
  67. elements?: any;
  68. appState?: any;
  69. }): data is ImportedDataState => {
  70. return (
  71. data?.type === EXPORT_DATA_TYPES.excalidraw &&
  72. (!data.elements ||
  73. (Array.isArray(data.elements) &&
  74. (!data.appState || typeof data.appState === "object")))
  75. );
  76. };
  77. export const isValidLibrary = (json: any) => {
  78. return (
  79. typeof json === "object" &&
  80. json &&
  81. json.type === EXPORT_DATA_TYPES.excalidrawLibrary &&
  82. json.version === 1
  83. );
  84. };
  85. export const saveLibraryAsJSON = async (library: Library) => {
  86. const libraryItems = await library.loadLibrary();
  87. const data: ExportedLibraryData = {
  88. type: EXPORT_DATA_TYPES.excalidrawLibrary,
  89. version: 1,
  90. source: EXPORT_SOURCE,
  91. library: libraryItems,
  92. };
  93. const serialized = JSON.stringify(data, null, 2);
  94. await fileSave(
  95. new Blob([serialized], {
  96. type: MIME_TYPES.excalidrawlib,
  97. }),
  98. {
  99. name: "library",
  100. extension: "excalidrawlib",
  101. description: "Excalidraw library file",
  102. },
  103. );
  104. };
  105. export const importLibraryFromJSON = async (library: Library) => {
  106. const blob = await fileOpen({
  107. description: "Excalidraw library files",
  108. // ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
  109. // gets resolved. Else, iOS users cannot open `.excalidraw` files.
  110. /*
  111. extensions: [".json", ".excalidrawlib"],
  112. */
  113. });
  114. await library.importLibrary(blob);
  115. };