tldraw
Version:
A tiny little drawing editor.
120 lines (119 loc) • 3.35 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import {
Editor,
mergeArraysAndReplaceDefaults,
useShallowArrayIdentity,
useTLStore
} from "@tldraw/editor";
import { memo, useEffect, useLayoutEffect, useMemo, useState } from "react";
import { defaultBindingUtils } from "./defaultBindingUtils.mjs";
import { defaultShapeUtils } from "./defaultShapeUtils.mjs";
import { defaultAddFontsFromNode, tipTapDefaultExtensions } from "./utils/text/richText.mjs";
const defaultTextOptions = {
tipTapConfig: {
extensions: tipTapDefaultExtensions
},
addFontsFromNode: defaultAddFontsFromNode
};
const TldrawImage = memo(function TldrawImage2(props) {
const [url, setUrl] = useState(null);
const [container, setContainer] = useState(null);
const _shapeUtils = useShallowArrayIdentity(props.shapeUtils ?? []);
const shapeUtilsWithDefaults = useMemo(
() => mergeArraysAndReplaceDefaults("type", _shapeUtils, defaultShapeUtils),
[_shapeUtils]
);
const _bindingUtils = useShallowArrayIdentity(props.bindingUtils ?? []);
const bindingUtilsWithDefaults = useMemo(
() => mergeArraysAndReplaceDefaults("type", _bindingUtils, defaultBindingUtils),
[_bindingUtils]
);
const store = useTLStore({ snapshot: props.snapshot, shapeUtils: shapeUtilsWithDefaults });
const {
pageId,
bounds,
scale,
pixelRatio,
background,
padding,
darkMode,
preserveAspectRatio,
format = "svg",
licenseKey,
assetUrls,
textOptions = defaultTextOptions
} = props;
useLayoutEffect(() => {
if (!container) return;
if (!store) 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,
fontAssetUrls: assetUrls?.fonts,
textOptions
});
if (pageId) editor.setCurrentPage(pageId);
const shapeIds = editor.getCurrentPageShapeIds();
async function setSvg() {
const imageResult = await editor.toImage([...shapeIds], {
bounds,
scale,
background,
padding,
darkMode,
preserveAspectRatio,
format
});
if (!imageResult || isCancelled) return;
const url2 = URL.createObjectURL(imageResult.blob);
setUrl(url2);
editor.dispose();
}
setSvg();
return () => {
isCancelled = true;
};
}, [
format,
container,
store,
shapeUtilsWithDefaults,
bindingUtilsWithDefaults,
pageId,
bounds,
scale,
background,
padding,
darkMode,
preserveAspectRatio,
licenseKey,
pixelRatio,
assetUrls,
textOptions
]);
useEffect(() => {
return () => {
if (url) URL.revokeObjectURL(url);
};
}, [url]);
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