tldraw
Version:
A tiny little drawing editor.
191 lines (190 loc) • 5.72 kB
JavaScript
import { objectMapEntries, useMaybeEditor, useShallowArrayIdentity } from "@tldraw/editor";
import { createContext, useCallback, useContext, useMemo } from "react";
import { PORTRAIT_BREAKPOINT } from "./constants.mjs";
import { useBreakpoint } from "./context/breakpoints.mjs";
import { useDialogs } from "./context/dialogs.mjs";
import { useToasts } from "./context/toasts.mjs";
import { getLocalFiles } from "./getLocalFiles.mjs";
import { useMenuClipboardEvents } from "./hooks/useClipboardEvents.mjs";
import { useCopyAs } from "./hooks/useCopyAs.mjs";
import { useExportAs } from "./hooks/useExportAs.mjs";
import { useGetEmbedDefinition } from "./hooks/useGetEmbedDefinition.mjs";
import { usePrint } from "./hooks/usePrint.mjs";
import { useTranslation } from "./hooks/useTranslation/useTranslation.mjs";
const MimeTypeContext = createContext([]);
function useDefaultHelpers() {
const editor = useMaybeEditor();
const { addToast, removeToast, clearToasts } = useToasts();
const { addDialog, clearDialogs, removeDialog } = useDialogs();
const msg = useTranslation();
const printSelectionOrPages = usePrint();
const { cut, copy, paste } = useMenuClipboardEvents();
const copyAs = useCopyAs();
const exportAs = useExportAs();
const getEmbedDefinition = useGetEmbedDefinition();
const breakpoint = useBreakpoint();
const isMobile = breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM;
const mimeTypes = useShallowArrayIdentity(useContext(MimeTypeContext));
const insertMedia = useCallback(async () => {
if (!editor) return;
const files = await getLocalFiles({
allowMultiple: true,
mimeTypes
});
if (!files.length) return;
editor.markHistoryStoppingPoint("insert media");
editor.putExternalContent({
type: "files",
files,
point: editor.getViewportPageBounds().center
});
}, [editor, mimeTypes]);
const replaceMedia = useCallback(
async (isImage) => {
if (!editor) return;
const files = await getLocalFiles({
allowMultiple: false,
mimeTypes: mimeTypes?.filter(
(m) => isImage ? m.startsWith("image/") : m.startsWith("video/")
)
});
if (!files.length) return;
const shape = editor.getOnlySelectedShape();
if (!shape || isImage && shape.type !== "image" || !isImage && shape.type !== "video")
return;
editor.markHistoryStoppingPoint("replace media");
const file = files[0];
editor.replaceExternalContent({
type: "file-replace",
file,
shapeId: shape.id,
isImage
});
},
[editor, mimeTypes]
);
const replaceImage = useCallback(() => replaceMedia(
true
/* isImage */
), [replaceMedia]);
const replaceVideo = useCallback(() => replaceMedia(
false
/* isImage */
), [replaceMedia]);
return useMemo(
() => ({
addToast,
removeToast,
clearToasts,
addDialog,
removeDialog,
clearDialogs,
msg,
isMobile,
insertMedia,
replaceImage,
replaceVideo,
printSelectionOrPages,
cut,
copy,
paste,
copyAs,
exportAs,
getEmbedDefinition
}),
[
addToast,
removeToast,
clearToasts,
addDialog,
removeDialog,
clearDialogs,
msg,
isMobile,
insertMedia,
replaceImage,
replaceVideo,
printSelectionOrPages,
cut,
copy,
paste,
copyAs,
exportAs,
getEmbedDefinition
]
);
}
function mergeOverrides(overrides, defaultHelpers) {
const mergedTranslations = {};
for (const override of overrides) {
if (override.translations) {
for (const [key, value] of objectMapEntries(override.translations)) {
let strings = mergedTranslations[key];
if (!strings) {
strings = mergedTranslations[key] = {};
}
Object.assign(strings, value);
}
}
}
return {
actions: (editor, schema, helpers) => {
for (const override of overrides) {
if (override.actions) {
schema = override.actions(editor, schema, helpers);
}
}
return schema;
},
tools: (editor, schema, helpers) => {
for (const override of overrides) {
if (override.tools) {
schema = override.tools(editor, schema, { ...defaultHelpers, ...helpers });
}
}
return schema;
},
translations: mergedTranslations
};
}
function useShallowArrayEquality(array) {
return useMemo(() => array, array);
}
function useMergedTranslationOverrides(overrides) {
const overridesArray = useShallowArrayEquality(
overrides == null ? [] : Array.isArray(overrides) ? overrides : [overrides]
);
return useMemo(() => {
const mergedTranslations = {};
for (const override of overridesArray) {
if (override.translations) {
for (const [key, value] of objectMapEntries(override.translations)) {
let strings = mergedTranslations[key];
if (!strings) {
strings = mergedTranslations[key] = {};
}
Object.assign(strings, value);
}
}
}
return mergedTranslations;
}, [overridesArray]);
}
function useMergedOverrides(overrides) {
const defaultHelpers = useDefaultHelpers();
const overridesArray = useShallowArrayEquality(
overrides == null ? [] : Array.isArray(overrides) ? overrides : [overrides]
);
return useMemo(
() => mergeOverrides(overridesArray, defaultHelpers),
[overridesArray, defaultHelpers]
);
}
export {
MimeTypeContext,
mergeOverrides,
useDefaultHelpers,
useMergedOverrides,
useMergedTranslationOverrides
};
//# sourceMappingURL=overrides.mjs.map