tldraw
Version:
A tiny little drawing editor.
95 lines (94 loc) • 3.3 kB
JavaScript
import {
react,
useDelaySvgExport,
useEditor,
useSvgExportContext
} from "@tldraw/editor";
import { useEffect, useRef, useState } from "react";
function useImageOrVideoAsset({ shapeId, assetId, width }) {
const editor = useEditor();
const exportInfo = useSvgExportContext();
const exportIsReady = useDelaySvgExport();
const [result, setResult] = useState(() => ({
asset: assetId ? editor.getAsset(assetId) ?? null : null,
url: null
}));
const didAlreadyResolve = useRef(false);
const previousAssetId = useRef(null);
const shouldRunImmediately = useRef(false);
const previousUrl = useRef(null);
useEffect(() => {
const assetIdChanged = previousAssetId.current !== assetId;
previousAssetId.current = assetId;
if (assetIdChanged) {
shouldRunImmediately.current = true;
}
if (!assetId) return;
let isCancelled = false;
let cancelDebounceFn;
const cleanupEffectScheduler = react("update state", () => {
if (!exportInfo && shapeId && editor.getCulledShapes().has(shapeId)) return;
const asset = editor.getAsset(assetId);
if (!asset) {
setResult((prev) => ({ ...prev, asset: null, url: null }));
return;
}
if (!asset.props.src) {
const preview = editor.getTemporaryAssetPreview(asset.id);
if (preview) {
if (previousUrl.current !== preview) {
previousUrl.current = preview;
setResult((prev) => ({ ...prev, isPlaceholder: true, url: preview }));
exportIsReady();
}
return;
}
}
const screenScale = exportInfo ? exportInfo.scale * (width / asset.props.w) : editor.getEfficientZoomLevel() * (width / asset.props.w);
function resolve(asset2, url) {
if (isCancelled) return;
if (previousUrl.current === url) return;
didAlreadyResolve.current = true;
previousUrl.current = url;
setResult({ asset: asset2, url });
exportIsReady();
}
if (didAlreadyResolve.current && !shouldRunImmediately.current) {
let tick = 0;
const resolveAssetAfterAWhile = () => {
tick++;
if (tick > 500 / 16) {
resolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url));
cancelDebounceFn?.();
}
};
cancelDebounceFn?.();
editor.on("tick", resolveAssetAfterAWhile);
cancelDebounceFn = () => editor.off("tick", resolveAssetAfterAWhile);
} else {
cancelDebounceFn?.();
resolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url));
shouldRunImmediately.current = false;
}
});
return () => {
cleanupEffectScheduler();
cancelDebounceFn?.();
isCancelled = true;
};
}, [editor, assetId, exportInfo, exportIsReady, shapeId, width]);
return result;
}
function resolveAssetUrl(editor, assetId, screenScale, exportInfo, callback) {
editor.resolveAssetUrl(assetId, {
screenScale,
shouldResolveToOriginal: exportInfo ? exportInfo.pixelRatio === null : false,
dpr: exportInfo?.pixelRatio ?? void 0
}).then((url) => {
callback(url);
});
}
export {
useImageOrVideoAsset
};
//# sourceMappingURL=useImageOrVideoAsset.mjs.map