import "./ExportDialog.scss"; import React, { useState, useEffect, useRef } from "react"; import { ToolButton } from "./ToolButton"; import { clipboard, exportFile, link } from "./icons"; import { NonDeletedExcalidrawElement } from "../element/types"; import { AppState } from "../types"; import { exportToCanvas } from "../scene/export"; import { ActionsManagerInterface } from "../actions/types"; import Stack from "./Stack"; import { t } from "../i18n"; import { probablySupportsClipboardBlob } from "../clipboard"; import { getSelectedElements, isSomeElementSelected } from "../scene"; import useIsMobile from "../is-mobile"; import { Dialog } from "./Dialog"; const scales = [1, 2, 3]; const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1; export type ExportCB = ( elements: readonly NonDeletedExcalidrawElement[], scale?: number, ) => void; function ExportModal({ elements, appState, exportPadding = 10, actionManager, onExportToPng, onExportToSvg, onExportToClipboard, onExportToBackend, }: { appState: AppState; elements: readonly NonDeletedExcalidrawElement[]; exportPadding?: number; actionManager: ActionsManagerInterface; onExportToPng: ExportCB; onExportToSvg: ExportCB; onExportToClipboard: ExportCB; onExportToBackend: ExportCB; onCloseRequest: () => void; }) { const someElementIsSelected = isSomeElementSelected(elements, appState); const [scale, setScale] = useState(defaultScale); const [exportSelected, setExportSelected] = useState(someElementIsSelected); const previewRef = useRef(null); const { exportBackground, viewBackgroundColor } = appState; const exportedElements = exportSelected ? getSelectedElements(elements, appState) : elements; useEffect(() => { setExportSelected(someElementIsSelected); }, [someElementIsSelected]); useEffect(() => { const previewNode = previewRef.current; const canvas = exportToCanvas(exportedElements, appState, { exportBackground, viewBackgroundColor, exportPadding, scale, }); previewNode?.appendChild(canvas); return () => { previewNode?.removeChild(canvas); }; }, [ appState, exportedElements, exportBackground, exportPadding, viewBackgroundColor, scale, ]); return (
onExportToPng(exportedElements, scale)} /> onExportToSvg(exportedElements, scale)} /> {probablySupportsClipboardBlob && ( onExportToClipboard(exportedElements, scale)} /> )} onExportToBackend(exportedElements)} />
{actionManager.renderAction("changeProjectName")}
{scales.map((s) => ( setScale(s)} /> ))}
{actionManager.renderAction("changeExportBackground")} {someElementIsSelected && (
)}
); } export function ExportDialog({ elements, appState, exportPadding = 10, actionManager, onExportToPng, onExportToSvg, onExportToClipboard, onExportToBackend, }: { appState: AppState; elements: readonly NonDeletedExcalidrawElement[]; exportPadding?: number; actionManager: ActionsManagerInterface; onExportToPng: ExportCB; onExportToSvg: ExportCB; onExportToClipboard: ExportCB; onExportToBackend: ExportCB; }) { const [modalIsShown, setModalIsShown] = useState(false); const triggerButton = useRef(null); const handleClose = React.useCallback(() => { setModalIsShown(false); triggerButton.current?.focus(); }, []); return ( <> setModalIsShown(true)} icon={exportFile} type="button" aria-label={t("buttons.export")} showAriaLabel={useIsMobile()} title={t("buttons.export")} ref={triggerButton} /> {modalIsShown && ( )} ); }