tldraw
Version:
A tiny little drawing editor.
226 lines (225 loc) • 8.3 kB
JavaScript
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import {
DEFAULT_SUPPORTED_IMAGE_TYPES,
DEFAULT_SUPPORT_VIDEO_TYPES,
TldrawEditor,
defaultUserPreferences,
mergeArraysAndReplaceDefaults,
useEditor,
useEditorComponents,
useOnMount,
useShallowArrayIdentity,
useShallowObjectIdentity
} from "@tldraw/editor";
import { useMemo } from "react";
import { TldrawHandles } from "./canvas/TldrawHandles.mjs";
import { TldrawOverlays } from "./canvas/TldrawOverlays.mjs";
import { TldrawScribble } from "./canvas/TldrawScribble.mjs";
import { TldrawSelectionForeground } from "./canvas/TldrawSelectionForeground.mjs";
import { TldrawShapeIndicators } from "./canvas/TldrawShapeIndicators.mjs";
import { defaultBindingUtils } from "./defaultBindingUtils.mjs";
import {
registerDefaultExternalContentHandlers
} from "./defaultExternalContentHandlers.mjs";
import { defaultShapeTools } from "./defaultShapeTools.mjs";
import { defaultShapeUtils } from "./defaultShapeUtils.mjs";
import { registerDefaultSideEffects } from "./defaultSideEffects.mjs";
import { defaultTools } from "./defaultTools.mjs";
import { EmbedShapeUtil } from "./shapes/embed/EmbedShapeUtil.mjs";
import { allDefaultFontFaces } from "./shapes/shared/defaultFonts.mjs";
import { TldrawUi, TldrawUiInFrontOfTheCanvas } from "./ui/TldrawUi.mjs";
import { useDefaultUiAssetUrlsWithOverrides } from "./ui/assetUrls.mjs";
import { LoadingScreen } from "./ui/components/LoadingScreen.mjs";
import { Spinner } from "./ui/components/Spinner.mjs";
import { AssetUrlsProvider } from "./ui/context/asset-urls.mjs";
import { useTldrawUiComponents } from "./ui/context/components.mjs";
import { useUiEvents } from "./ui/context/events.mjs";
import { useToasts } from "./ui/context/toasts.mjs";
import {
TldrawUiTranslationProvider,
useTranslation
} from "./ui/hooks/useTranslation/useTranslation.mjs";
import { useMergedTranslationOverrides } from "./ui/overrides.mjs";
import { useDefaultEditorAssetsWithOverrides } from "./utils/static-assets/assetUrls.mjs";
import { defaultAddFontsFromNode, tipTapDefaultExtensions } from "./utils/text/richText.mjs";
const allDefaultTools = [...defaultTools, ...defaultShapeTools];
function Tldraw(props) {
const {
children,
maxImageDimension,
maxAssetSize,
acceptedImageMimeTypes,
acceptedVideoMimeTypes,
onMount,
components = {},
shapeUtils = [],
bindingUtils = [],
tools = [],
// needs to be here for backwards compatibility
// eslint-disable-next-line @typescript-eslint/no-deprecated
embeds,
options,
// needs to be here for backwards compatibility with TldrawEditor
// eslint-disable-next-line @typescript-eslint/no-deprecated
textOptions: _textOptions,
...rest
} = props;
const _components = useShallowObjectIdentity(components);
const CustomInFrontOfTheCanvas = components?.InFrontOfTheCanvas;
const InFrontOfTheCanvas = useMemo(() => {
if (rest.hideUi) return CustomInFrontOfTheCanvas ?? null;
if (!CustomInFrontOfTheCanvas) return TldrawUiInFrontOfTheCanvas;
return () => /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(TldrawUiInFrontOfTheCanvas, {}),
/* @__PURE__ */ jsx(CustomInFrontOfTheCanvas, {})
] });
}, [rest.hideUi, CustomInFrontOfTheCanvas]);
const componentsWithDefault = useMemo(
() => ({
Scribble: TldrawScribble,
ShapeIndicators: TldrawShapeIndicators,
CollaboratorScribble: TldrawScribble,
SelectionForeground: TldrawSelectionForeground,
Handles: TldrawHandles,
Overlays: TldrawOverlays,
Spinner,
LoadingScreen,
..._components,
InFrontOfTheCanvas
}),
[_components, InFrontOfTheCanvas]
);
const _shapeUtils = useShallowArrayIdentity(shapeUtils);
const shapeUtilsWithDefaults = useMemo(
() => mergeArraysAndReplaceDefaults("type", _shapeUtils, defaultShapeUtils),
[_shapeUtils]
);
const _bindingUtils = useShallowArrayIdentity(bindingUtils);
const bindingUtilsWithDefaults = useMemo(
() => mergeArraysAndReplaceDefaults("type", _bindingUtils, defaultBindingUtils),
[_bindingUtils]
);
const _tools = useShallowArrayIdentity(tools);
const toolsWithDefaults = useMemo(
() => mergeArraysAndReplaceDefaults("id", _tools, allDefaultTools),
[_tools]
);
const _imageMimeTypes = useShallowArrayIdentity(
acceptedImageMimeTypes ?? DEFAULT_SUPPORTED_IMAGE_TYPES
);
const _videoMimeTypes = useShallowArrayIdentity(
acceptedVideoMimeTypes ?? DEFAULT_SUPPORT_VIDEO_TYPES
);
const _mergedTextOptions = options?.text ?? _textOptions;
const textOptionsWithDefaults = useMemo(() => {
return {
addFontsFromNode: defaultAddFontsFromNode,
..._mergedTextOptions,
tipTapConfig: {
extensions: tipTapDefaultExtensions,
..._mergedTextOptions?.tipTapConfig
}
};
}, [_mergedTextOptions]);
const optionsWithDefaults = useMemo(
() => ({
...options,
text: textOptionsWithDefaults
}),
[options, textOptionsWithDefaults]
);
const mediaMimeTypes = useMemo(
() => [..._imageMimeTypes, ..._videoMimeTypes],
[_imageMimeTypes, _videoMimeTypes]
);
const assets = useDefaultEditorAssetsWithOverrides(rest.assetUrls);
const embedShapeUtil = shapeUtilsWithDefaults.find((util) => util.type === "embed");
if (embedShapeUtil && embeds) {
EmbedShapeUtil.setEmbedDefinitions(embeds);
}
return (
// We provide an extra higher layer of asset+translations providers here so that
// loading UI (which is rendered outside of TldrawUi) may be translated.
// Ideally we would refactor to hoist all the UI context providers we can up here. Maybe later.
/* @__PURE__ */ (jsx(
AssetUrlsProvider,
{ assetUrls: useDefaultUiAssetUrlsWithOverrides(rest.assetUrls), children: /* @__PURE__ */ jsx(
TldrawUiTranslationProvider,
{
overrides: useMergedTranslationOverrides(rest.overrides),
locale: rest.user?.userPreferences.get().locale ?? defaultUserPreferences.locale,
children: /* @__PURE__ */ jsx(
TldrawEditor,
{
initialState: "select",
...rest,
components: componentsWithDefault,
shapeUtils: shapeUtilsWithDefaults,
bindingUtils: bindingUtilsWithDefaults,
tools: toolsWithDefaults,
options: optionsWithDefaults,
assetUrls: assets,
children: /* @__PURE__ */ jsxs(TldrawUi, { ...rest, components: componentsWithDefault, mediaMimeTypes, children: [
/* @__PURE__ */ jsx(
InsideOfEditorAndUiContext,
{
maxImageDimension,
maxAssetSize,
acceptedImageMimeTypes: _imageMimeTypes,
acceptedVideoMimeTypes: _videoMimeTypes,
onMount
}
),
children
] })
}
)
}
) }
))
);
}
function InsideOfEditorAndUiContext({
maxImageDimension,
maxAssetSize,
acceptedImageMimeTypes,
acceptedVideoMimeTypes,
onMount
}) {
const editor = useEditor();
const toasts = useToasts();
const msg = useTranslation();
const trackEvent = useUiEvents();
useOnMount(() => {
const unsubs = [];
unsubs.push(registerDefaultSideEffects(editor));
editor.fonts.requestFonts(allDefaultFontFaces);
editor.once("edit", () => trackEvent("edit", { source: "unknown" }));
registerDefaultExternalContentHandlers(editor, {
maxImageDimension,
maxAssetSize,
acceptedImageMimeTypes,
acceptedVideoMimeTypes,
toasts,
msg
});
unsubs.push(editor.store.props.onMount(editor));
unsubs.push(onMount?.(editor));
return () => {
unsubs.forEach((fn) => fn?.());
};
});
const { Canvas } = useEditorComponents();
const { ContextMenu } = useTldrawUiComponents();
if (ContextMenu) {
return /* @__PURE__ */ jsx(ContextMenu, {});
}
if (Canvas) {
return /* @__PURE__ */ jsx(Canvas, {});
}
return null;
}
export {
Tldraw
};
//# sourceMappingURL=Tldraw.mjs.map