tldraw
Version:
A tiny little drawing editor.
138 lines (137 loc) • 3.96 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 { useDefaultEditorAssetsWithOverrides } from "./utils/static-assets/assetUrls.mjs";
import { defaultAddFontsFromNode, tipTapDefaultExtensions } from "./utils/text/richText.mjs";
const defaultOptions = {
text: {
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,
options: _options,
// eslint-disable-next-line @typescript-eslint/no-deprecated
textOptions: _textOptions
} = props;
const options = useMemo(
() => ({
...defaultOptions,
..._options,
text: {
...defaultOptions.text,
...(_options?.text ?? _textOptions)
}
}),
[_options, _textOptions]
);
const assetUrlsWithOverrides = useDefaultEditorAssetsWithOverrides(assetUrls);
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: assetUrlsWithOverrides.fonts,
options
});
if (pageId) editor.setCurrentPage(pageId);
const shapeIds = editor.getCurrentPageShapeIds();
async function setSvg() {
await editor.fonts.loadRequiredFontsForCurrentPage(editor.options.maxFontsToLoadBeforeRender);
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,
assetUrlsWithOverrides,
options
]);
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