JSONExportDialog.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import React, { useState } from "react";
  2. import { ActionsManagerInterface } from "../actions/types";
  3. import { NonDeletedExcalidrawElement } from "../element/types";
  4. import { t } from "../i18n";
  5. import { useIsMobile } from "./App";
  6. import { AppState, ExportOpts } from "../types";
  7. import { Dialog } from "./Dialog";
  8. import { exportFile, exportToFileIcon, link } from "./icons";
  9. import { ToolButton } from "./ToolButton";
  10. import { actionSaveFileToDisk } from "../actions/actionExport";
  11. import { Card } from "./Card";
  12. import "./ExportDialog.scss";
  13. import { nativeFileSystemSupported } from "../data/filesystem";
  14. export type ExportCB = (
  15. elements: readonly NonDeletedExcalidrawElement[],
  16. scale?: number,
  17. ) => void;
  18. const JSONExportModal = ({
  19. elements,
  20. appState,
  21. actionManager,
  22. exportOpts,
  23. canvas,
  24. }: {
  25. appState: AppState;
  26. elements: readonly NonDeletedExcalidrawElement[];
  27. actionManager: ActionsManagerInterface;
  28. onCloseRequest: () => void;
  29. exportOpts: ExportOpts;
  30. canvas: HTMLCanvasElement | null;
  31. }) => {
  32. const { onExportToBackend } = exportOpts;
  33. return (
  34. <div className="ExportDialog ExportDialog--json">
  35. <div className="ExportDialog-cards">
  36. {exportOpts.saveFileToDisk && (
  37. <Card color="lime">
  38. <div className="Card-icon">{exportToFileIcon}</div>
  39. <h2>{t("exportDialog.disk_title")}</h2>
  40. <div className="Card-details">
  41. {t("exportDialog.disk_details")}
  42. {!nativeFileSystemSupported &&
  43. actionManager.renderAction("changeProjectName")}
  44. </div>
  45. <ToolButton
  46. className="Card-button"
  47. type="button"
  48. title={t("exportDialog.disk_button")}
  49. aria-label={t("exportDialog.disk_button")}
  50. showAriaLabel={true}
  51. onClick={() => {
  52. actionManager.executeAction(actionSaveFileToDisk);
  53. }}
  54. />
  55. </Card>
  56. )}
  57. {onExportToBackend && (
  58. <Card color="pink">
  59. <div className="Card-icon">{link}</div>
  60. <h2>{t("exportDialog.link_title")}</h2>
  61. <div className="Card-details">{t("exportDialog.link_details")}</div>
  62. <ToolButton
  63. className="Card-button"
  64. type="button"
  65. title={t("exportDialog.link_button")}
  66. aria-label={t("exportDialog.link_button")}
  67. showAriaLabel={true}
  68. onClick={() => onExportToBackend(elements, appState, canvas)}
  69. />
  70. </Card>
  71. )}
  72. {exportOpts.renderCustomUI &&
  73. exportOpts.renderCustomUI(elements, appState, canvas)}
  74. </div>
  75. </div>
  76. );
  77. };
  78. export const JSONExportDialog = ({
  79. elements,
  80. appState,
  81. actionManager,
  82. exportOpts,
  83. canvas,
  84. }: {
  85. appState: AppState;
  86. elements: readonly NonDeletedExcalidrawElement[];
  87. actionManager: ActionsManagerInterface;
  88. exportOpts: ExportOpts;
  89. canvas: HTMLCanvasElement | null;
  90. }) => {
  91. const [modalIsShown, setModalIsShown] = useState(false);
  92. const handleClose = React.useCallback(() => {
  93. setModalIsShown(false);
  94. }, []);
  95. return (
  96. <>
  97. <ToolButton
  98. onClick={() => {
  99. setModalIsShown(true);
  100. }}
  101. data-testid="json-export-button"
  102. icon={exportFile}
  103. type="button"
  104. aria-label={t("buttons.export")}
  105. showAriaLabel={useIsMobile()}
  106. title={t("buttons.export")}
  107. />
  108. {modalIsShown && (
  109. <Dialog onCloseRequest={handleClose} title={t("buttons.export")}>
  110. <JSONExportModal
  111. elements={elements}
  112. appState={appState}
  113. actionManager={actionManager}
  114. onCloseRequest={handleClose}
  115. exportOpts={exportOpts}
  116. canvas={canvas}
  117. />
  118. </Dialog>
  119. )}
  120. </>
  121. );
  122. };