tldraw
Version:
A tiny little drawing editor.
131 lines (130 loc) • 4.03 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import {
DefaultSpinner,
Editor,
ErrorScreen,
LoadingScreen,
useShallowArrayIdentity,
useTLStore
} from "@tldraw/editor";
import { memo, useLayoutEffect, useMemo, useState } from "react";
import { defaultBindingUtils } from "./defaultBindingUtils.mjs";
import { defaultShapeUtils } from "./defaultShapeUtils.mjs";
import { usePreloadAssets } from "./ui/hooks/usePreloadAssets.mjs";
import { getSvgAsImage } from "./utils/export/export.mjs";
import { useDefaultEditorAssetsWithOverrides } from "./utils/static-assets/assetUrls.mjs";
const TldrawImage = memo(function TldrawImage2(props) {
const [url, setUrl] = useState(null);
const [container, setContainer] = useState(null);
const shapeUtils = useShallowArrayIdentity(props.shapeUtils ?? []);
const shapeUtilsWithDefaults = useMemo(() => [...defaultShapeUtils, ...shapeUtils], [shapeUtils]);
const bindingUtils = useShallowArrayIdentity(props.bindingUtils ?? []);
const bindingUtilsWithDefaults = useMemo(
() => [...defaultBindingUtils, ...bindingUtils],
[bindingUtils]
);
const store = useTLStore({ snapshot: props.snapshot, shapeUtils: shapeUtilsWithDefaults });
const assets = useDefaultEditorAssetsWithOverrides(props.assetUrls);
const { done: preloadingComplete, error: preloadingError } = usePreloadAssets(assets);
const {
pageId,
bounds,
scale,
pixelRatio,
background,
padding,
darkMode,
preserveAspectRatio,
format = "svg",
licenseKey
} = props;
useLayoutEffect(() => {
if (!container) return;
if (!store) return;
if (!preloadingComplete) return;
let isCancelled = false;
const tempElm = document.createElement("div");
container.appendChild(tempElm);
container.classList.add("tl-container", "tl-theme__light");
const editor = new Editor({
store,
shapeUtils: shapeUtilsWithDefaults,
bindingUtils: bindingUtilsWithDefaults,
tools: [],
getContainer: () => tempElm,
licenseKey
});
if (pageId) editor.setCurrentPage(pageId);
const shapeIds = editor.getCurrentPageShapeIds();
async function setSvg() {
const svgResult = await editor.getSvgString([...shapeIds], {
bounds,
scale,
background,
padding,
darkMode,
preserveAspectRatio
});
if (svgResult && !isCancelled) {
if (format === "svg") {
if (!isCancelled) {
const blob = new Blob([svgResult.svg], { type: "image/svg+xml" });
const url2 = URL.createObjectURL(blob);
setUrl(url2);
}
} else if (format === "png") {
const blob = await getSvgAsImage(editor, svgResult.svg, {
type: format,
width: svgResult.width,
height: svgResult.height,
pixelRatio
});
if (blob && !isCancelled) {
const url2 = URL.createObjectURL(blob);
setUrl(url2);
}
}
}
editor.dispose();
}
setSvg();
return () => {
isCancelled = true;
};
}, [
format,
container,
store,
shapeUtilsWithDefaults,
bindingUtilsWithDefaults,
pageId,
bounds,
scale,
background,
padding,
darkMode,
preserveAspectRatio,
preloadingComplete,
preloadingError,
licenseKey,
pixelRatio
]);
if (preloadingError) {
return /* @__PURE__ */ jsx(ErrorScreen, { children: "Could not load assets." });
}
if (!preloadingComplete) {
return /* @__PURE__ */ jsx(LoadingScreen, { children: /* @__PURE__ */ jsx(DefaultSpinner, {}) });
}
return /* @__PURE__ */ jsx("div", { ref: setContainer, style: { position: "relative", width: "100%", height: "100%" }, children: url && /* @__PURE__ */ jsx(
"img",
{
src: url,
referrerPolicy: "strict-origin-when-cross-origin",
style: { width: "100%", height: "100%" }
}
) });
});
export {
TldrawImage
};
//# sourceMappingURL=TldrawImage.mjs.map