mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-12-27 23:17:13 +01:00
Compare commits
1 Commits
persist_fi
...
cycle_sele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e3a5b2042 |
@@ -2,8 +2,5 @@
|
||||
"firestore": {
|
||||
"rules": "firestore.rules",
|
||||
"indexes": "firestore.indexes.json"
|
||||
},
|
||||
"storage": {
|
||||
"rules": "storage.rules"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
rules_version = '2';
|
||||
service firebase.storage {
|
||||
match /b/{bucket}/o {
|
||||
match /{migrations} {
|
||||
match /{scenes}/{scene} {
|
||||
allow get, write: if true;
|
||||
// redundant, but let's be explicit'
|
||||
allow list: if false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@
|
||||
"clsx": "1.1.1",
|
||||
"firebase": "8.3.3",
|
||||
"i18next-browser-languagedetector": "6.1.0",
|
||||
"idb-keyval": "5.0.6",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"nanoid": "3.1.22",
|
||||
"open-color": "1.8.0",
|
||||
|
||||
Binary file not shown.
@@ -34,9 +34,9 @@ export const actionChangeViewBackgroundColor = register({
|
||||
type="canvasBackground"
|
||||
color={appState.viewBackgroundColor}
|
||||
onChange={(color) => updateData({ viewBackgroundColor: color })}
|
||||
isActive={appState.openPopup === "canvasColorPicker"}
|
||||
isActive={appState.openMenu === "canvasColorPicker"}
|
||||
setActive={(active) =>
|
||||
updateData({ openPopup: active ? "canvasColorPicker" : null })
|
||||
updateData({ openMenu: active ? "canvasColorPicker" : null })
|
||||
}
|
||||
data-testid="canvas-background-picker"
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { trackEvent } from "../analytics";
|
||||
import { load, questionCircle, saveAs } from "../components/icons";
|
||||
import { load, questionCircle, save, saveAs } from "../components/icons";
|
||||
import { ProjectName } from "../components/ProjectName";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
import "../components/ToolIcon.scss";
|
||||
@@ -13,12 +13,6 @@ import { KEYS } from "../keys";
|
||||
import { register } from "./register";
|
||||
import { supported as fsSupported } from "browser-fs-access";
|
||||
import { CheckboxItem } from "../components/CheckboxItem";
|
||||
import { getExportSize } from "../scene/export";
|
||||
import { DEFAULT_EXPORT_PADDING, EXPORT_SCALES, IDB_KEYS } from "../constants";
|
||||
import { getSelectedElements, isSomeElementSelected } from "../scene";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { ActiveFile } from "../components/ActiveFile";
|
||||
import * as idb from "idb-keyval";
|
||||
|
||||
export const actionChangeProjectName = register({
|
||||
name: "changeProjectName",
|
||||
@@ -38,54 +32,6 @@ export const actionChangeProjectName = register({
|
||||
),
|
||||
});
|
||||
|
||||
export const actionChangeExportScale = register({
|
||||
name: "changeExportScale",
|
||||
perform: (_elements, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, exportScale: value },
|
||||
commitToHistory: false,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements: allElements, appState, updateData }) => {
|
||||
const elements = getNonDeletedElements(allElements);
|
||||
const exportSelected = isSomeElementSelected(elements, appState);
|
||||
const exportedElements = exportSelected
|
||||
? getSelectedElements(elements, appState)
|
||||
: elements;
|
||||
|
||||
return (
|
||||
<>
|
||||
{EXPORT_SCALES.map((s) => {
|
||||
const [width, height] = getExportSize(
|
||||
exportedElements,
|
||||
DEFAULT_EXPORT_PADDING,
|
||||
s,
|
||||
);
|
||||
|
||||
const scaleButtonTitle = `${t(
|
||||
"buttons.scale",
|
||||
)} ${s}x (${width}x${height})`;
|
||||
|
||||
return (
|
||||
<ToolButton
|
||||
key={s}
|
||||
size="s"
|
||||
type="radio"
|
||||
icon={`${s}x`}
|
||||
name="export-canvas-scale"
|
||||
title={scaleButtonTitle}
|
||||
aria-label={scaleButtonTitle}
|
||||
id="export-canvas-scale"
|
||||
checked={s === appState.exportScale}
|
||||
onChange={() => updateData(s)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export const actionChangeExportBackground = register({
|
||||
name: "changeExportBackground",
|
||||
perform: (_elements, appState, value) => {
|
||||
@@ -150,30 +96,19 @@ export const actionSaveToActiveFile = register({
|
||||
if (error?.name !== "AbortError") {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
if (fileHandleExists && error.name === "AbortError") {
|
||||
try {
|
||||
await idb.del(IDB_KEYS.fileHandle);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return {
|
||||
commitToHistory: false,
|
||||
appState: { ...appState, fileHandle: null },
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
commitToHistory: false,
|
||||
};
|
||||
return { commitToHistory: false };
|
||||
}
|
||||
},
|
||||
keyTest: (event) =>
|
||||
event.key === KEYS.S && event[KEYS.CTRL_OR_CMD] && !event.shiftKey,
|
||||
PanelComponent: ({ updateData, appState }) => (
|
||||
<ActiveFile
|
||||
onSave={() => updateData(null)}
|
||||
fileName={appState.fileHandle?.name}
|
||||
PanelComponent: ({ updateData }) => (
|
||||
<ToolButton
|
||||
type="icon"
|
||||
icon={save}
|
||||
title={t("buttons.save")}
|
||||
aria-label={t("buttons.save")}
|
||||
onClick={() => updateData(null)}
|
||||
data-testid="save-button"
|
||||
/>
|
||||
),
|
||||
});
|
||||
@@ -186,13 +121,6 @@ export const actionSaveFileToDisk = register({
|
||||
...appState,
|
||||
fileHandle: null,
|
||||
});
|
||||
try {
|
||||
if (fileHandle) {
|
||||
await idb.set(IDB_KEYS.fileHandle, fileHandle);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return { commitToHistory: false, appState: { ...appState, fileHandle } };
|
||||
} catch (error) {
|
||||
if (error?.name !== "AbortError") {
|
||||
|
||||
@@ -13,13 +13,6 @@ import {
|
||||
FillCrossHatchIcon,
|
||||
FillHachureIcon,
|
||||
FillSolidIcon,
|
||||
FontFamilyCodeIcon,
|
||||
FontFamilyHandDrawnIcon,
|
||||
FontFamilyNormalIcon,
|
||||
FontSizeExtraLargeIcon,
|
||||
FontSizeLargeIcon,
|
||||
FontSizeMediumIcon,
|
||||
FontSizeSmallIcon,
|
||||
SloppinessArchitectIcon,
|
||||
SloppinessArtistIcon,
|
||||
SloppinessCartoonistIcon,
|
||||
@@ -27,15 +20,18 @@ import {
|
||||
StrokeStyleDottedIcon,
|
||||
StrokeStyleSolidIcon,
|
||||
StrokeWidthIcon,
|
||||
TextAlignCenterIcon,
|
||||
FontSizeSmallIcon,
|
||||
FontSizeMediumIcon,
|
||||
FontSizeLargeIcon,
|
||||
FontSizeExtraLargeIcon,
|
||||
FontFamilyHandDrawnIcon,
|
||||
FontFamilyNormalIcon,
|
||||
FontFamilyCodeIcon,
|
||||
TextAlignLeftIcon,
|
||||
TextAlignCenterIcon,
|
||||
TextAlignRightIcon,
|
||||
} from "../components/icons";
|
||||
import {
|
||||
DEFAULT_FONT_FAMILY,
|
||||
DEFAULT_FONT_SIZE,
|
||||
FONT_FAMILY,
|
||||
} from "../constants";
|
||||
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants";
|
||||
import {
|
||||
getNonDeletedElements,
|
||||
isTextElement,
|
||||
@@ -48,7 +44,7 @@ import {
|
||||
ExcalidrawElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawTextElement,
|
||||
FontFamilyValues,
|
||||
FontFamily,
|
||||
TextAlign,
|
||||
} from "../element/types";
|
||||
import { getLanguage, t } from "../i18n";
|
||||
@@ -130,9 +126,9 @@ export const actionChangeStrokeColor = register({
|
||||
appState.currentItemStrokeColor,
|
||||
)}
|
||||
onChange={(color) => updateData({ currentItemStrokeColor: color })}
|
||||
isActive={appState.openPopup === "strokeColorPicker"}
|
||||
isActive={appState.openMenu === "strokeColorPicker"}
|
||||
setActive={(active) =>
|
||||
updateData({ openPopup: active ? "strokeColorPicker" : null })
|
||||
updateData({ openMenu: active ? "strokeColorPicker" : null })
|
||||
}
|
||||
/>
|
||||
</>
|
||||
@@ -170,9 +166,9 @@ export const actionChangeBackgroundColor = register({
|
||||
appState.currentItemBackgroundColor,
|
||||
)}
|
||||
onChange={(color) => updateData({ currentItemBackgroundColor: color })}
|
||||
isActive={appState.openPopup === "backgroundColorPicker"}
|
||||
isActive={appState.openMenu === "backgroundColorPicker"}
|
||||
setActive={(active) =>
|
||||
updateData({ openPopup: active ? "backgroundColorPicker" : null })
|
||||
updateData({ openMenu: active ? "backgroundColorPicker" : null })
|
||||
}
|
||||
/>
|
||||
</>
|
||||
@@ -503,23 +499,19 @@ export const actionChangeFontFamily = register({
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData }) => {
|
||||
const options: {
|
||||
value: FontFamilyValues;
|
||||
text: string;
|
||||
icon: JSX.Element;
|
||||
}[] = [
|
||||
const options: { value: FontFamily; text: string; icon: JSX.Element }[] = [
|
||||
{
|
||||
value: FONT_FAMILY.Virgil,
|
||||
value: 1,
|
||||
text: t("labels.handDrawn"),
|
||||
icon: <FontFamilyHandDrawnIcon theme={appState.theme} />,
|
||||
},
|
||||
{
|
||||
value: FONT_FAMILY.Helvetica,
|
||||
value: 2,
|
||||
text: t("labels.normal"),
|
||||
icon: <FontFamilyNormalIcon theme={appState.theme} />,
|
||||
},
|
||||
{
|
||||
value: FONT_FAMILY.Cascadia,
|
||||
value: 3,
|
||||
text: t("labels.code"),
|
||||
icon: <FontFamilyCodeIcon theme={appState.theme} />,
|
||||
},
|
||||
@@ -528,7 +520,7 @@ export const actionChangeFontFamily = register({
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{t("labels.fontFamily")}</legend>
|
||||
<ButtonIconSelect<FontFamilyValues | false>
|
||||
<ButtonIconSelect<FontFamily | false>
|
||||
group="font-family"
|
||||
options={options}
|
||||
value={getFormValue(
|
||||
|
||||
@@ -66,7 +66,6 @@ export type ActionName =
|
||||
| "changeProjectName"
|
||||
| "changeExportBackground"
|
||||
| "changeExportEmbedScene"
|
||||
| "changeExportScale"
|
||||
| "saveToActiveFile"
|
||||
| "saveFileToDisk"
|
||||
| "loadScene"
|
||||
|
||||
@@ -3,16 +3,11 @@ import {
|
||||
DEFAULT_FONT_FAMILY,
|
||||
DEFAULT_FONT_SIZE,
|
||||
DEFAULT_TEXT_ALIGN,
|
||||
EXPORT_SCALES,
|
||||
} from "./constants";
|
||||
import { t } from "./i18n";
|
||||
import { AppState, NormalizedZoomValue } from "./types";
|
||||
import { getDateTime } from "./utils";
|
||||
|
||||
const defaultExportScale = EXPORT_SCALES.includes(devicePixelRatio)
|
||||
? devicePixelRatio
|
||||
: 1;
|
||||
|
||||
export const getDefaultAppState = (): Omit<
|
||||
AppState,
|
||||
"offsetTop" | "offsetLeft" | "width" | "height"
|
||||
@@ -44,7 +39,6 @@ export const getDefaultAppState = (): Omit<
|
||||
elementType: "selection",
|
||||
errorMessage: null,
|
||||
exportBackground: true,
|
||||
exportScale: defaultExportScale,
|
||||
exportEmbedScene: false,
|
||||
exportWithDarkMode: false,
|
||||
fileHandle: null,
|
||||
@@ -58,7 +52,6 @@ export const getDefaultAppState = (): Omit<
|
||||
multiElement: null,
|
||||
name: `${t("labels.untitled")}-${getDateTime()}`,
|
||||
openMenu: null,
|
||||
openPopup: null,
|
||||
pasteDialog: { shown: false, data: null },
|
||||
previousSelectedElementIds: {},
|
||||
resizingElement: null,
|
||||
@@ -123,7 +116,6 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
errorMessage: { browser: false, export: false },
|
||||
exportBackground: { browser: true, export: false },
|
||||
exportEmbedScene: { browser: true, export: false },
|
||||
exportScale: { browser: true, export: false },
|
||||
exportWithDarkMode: { browser: true, export: false },
|
||||
fileHandle: { browser: false, export: false },
|
||||
gridSize: { browser: true, export: true },
|
||||
@@ -139,7 +131,6 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
offsetLeft: { browser: false, export: false },
|
||||
offsetTop: { browser: false, export: false },
|
||||
openMenu: { browser: true, export: false },
|
||||
openPopup: { browser: false, export: false },
|
||||
pasteDialog: { browser: false, export: false },
|
||||
previousSelectedElementIds: { browser: true, export: false },
|
||||
resizingElement: { browser: false, export: false },
|
||||
|
||||
@@ -151,14 +151,23 @@ export const SelectedShapeActions = ({
|
||||
);
|
||||
};
|
||||
|
||||
const LIBRARY_ICON = (
|
||||
// fa-th-large
|
||||
<svg viewBox="0 0 512 512">
|
||||
<path d="M296 32h192c13.255 0 24 10.745 24 24v160c0 13.255-10.745 24-24 24H296c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24zm-80 0H24C10.745 32 0 42.745 0 56v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zM0 296v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zm296 184h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H296c-13.255 0-24 10.745-24 24v160c0 13.255 10.745 24 24 24z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ShapesSwitcher = ({
|
||||
canvas,
|
||||
elementType,
|
||||
setAppState,
|
||||
isLibraryOpen,
|
||||
}: {
|
||||
canvas: HTMLCanvasElement | null;
|
||||
elementType: ExcalidrawElement["type"];
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
isLibraryOpen: boolean;
|
||||
}) => (
|
||||
<>
|
||||
{SHAPES.map(({ value, icon, key }, index) => {
|
||||
@@ -192,6 +201,19 @@ export const ShapesSwitcher = ({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<ToolButton
|
||||
className="Shape ToolIcon_type_button__library"
|
||||
type="button"
|
||||
icon={LIBRARY_ICON}
|
||||
name="editor-library"
|
||||
keyBindingLabel="9"
|
||||
aria-keyshortcuts="9"
|
||||
title={`${capitalizeString(t("toolBar.library"))} — 9`}
|
||||
aria-label={capitalizeString(t("toolBar.library"))}
|
||||
onClick={() => {
|
||||
setAppState({ isLibraryOpen: !isLibraryOpen });
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.excalidraw {
|
||||
.ActiveFile {
|
||||
.ActiveFile__fileName {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 9.3em;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 1.15em;
|
||||
margin-inline-end: 0.3em;
|
||||
transform: scaleY(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from "react";
|
||||
import Stack from "../components/Stack";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
import { save, file } from "../components/icons";
|
||||
import { t } from "../i18n";
|
||||
|
||||
import "./ActiveFile.scss";
|
||||
|
||||
type ActiveFileProps = {
|
||||
fileName?: string;
|
||||
onSave: () => void;
|
||||
};
|
||||
|
||||
export const ActiveFile = ({ fileName, onSave }: ActiveFileProps) => (
|
||||
<Stack.Row className="ActiveFile" gap={1} align="center">
|
||||
<span className="ActiveFile__fileName">
|
||||
{file}
|
||||
<span>{fileName}</span>
|
||||
</span>
|
||||
<ToolButton
|
||||
type="icon"
|
||||
icon={save}
|
||||
title={t("buttons.save")}
|
||||
aria-label={t("buttons.save")}
|
||||
onClick={onSave}
|
||||
data-testid="save-button"
|
||||
/>
|
||||
</Stack.Row>
|
||||
);
|
||||
@@ -52,7 +52,6 @@ import {
|
||||
ENV,
|
||||
EVENT,
|
||||
GRID_SIZE,
|
||||
IDB_KEYS,
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
MIME_TYPES,
|
||||
MQ_MAX_HEIGHT_LANDSCAPE,
|
||||
@@ -112,6 +111,7 @@ import {
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
import { mutateElement } from "../element/mutateElement";
|
||||
import { deepCopyElement, newFreeDrawElement } from "../element/newElement";
|
||||
import { MaybeTransformHandleType } from "../element/transformHandles";
|
||||
import {
|
||||
isBindingElement,
|
||||
isBindingElementType,
|
||||
@@ -167,11 +167,9 @@ import { findShapeByKey } from "../shapes";
|
||||
import {
|
||||
AppProps,
|
||||
AppState,
|
||||
ExcalidrawImperativeAPI,
|
||||
Gesture,
|
||||
GestureEvent,
|
||||
LibraryItems,
|
||||
PointerDownState,
|
||||
SceneData,
|
||||
} from "../types";
|
||||
import {
|
||||
@@ -182,6 +180,7 @@ import {
|
||||
isToolIcon,
|
||||
isWritableElement,
|
||||
resetCursor,
|
||||
ResolvablePromise,
|
||||
resolvablePromise,
|
||||
sceneCoordsToViewportCoords,
|
||||
setCursor,
|
||||
@@ -195,14 +194,12 @@ import LayerUI from "./LayerUI";
|
||||
import { Stats } from "./Stats";
|
||||
import { Toast } from "./Toast";
|
||||
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
|
||||
import * as idb from "idb-keyval";
|
||||
|
||||
const IsMobileContext = React.createContext(false);
|
||||
export const useIsMobile = () => useContext(IsMobileContext);
|
||||
const ExcalidrawContainerContext = React.createContext<{
|
||||
container: HTMLDivElement | null;
|
||||
id: string | null;
|
||||
}>({ container: null, id: null });
|
||||
const ExcalidrawContainerContext = React.createContext<HTMLDivElement | null>(
|
||||
null,
|
||||
);
|
||||
export const useExcalidrawContainer = () =>
|
||||
useContext(ExcalidrawContainerContext);
|
||||
|
||||
@@ -225,6 +222,83 @@ const gesture: Gesture = {
|
||||
initialScale: null,
|
||||
};
|
||||
|
||||
export type PointerDownState = Readonly<{
|
||||
// The first position at which pointerDown happened
|
||||
origin: Readonly<{ x: number; y: number }>;
|
||||
// Same as "origin" but snapped to the grid, if grid is on
|
||||
originInGrid: Readonly<{ x: number; y: number }>;
|
||||
// Scrollbar checks
|
||||
scrollbars: ReturnType<typeof isOverScrollBars>;
|
||||
// The previous pointer position
|
||||
lastCoords: { x: number; y: number };
|
||||
// map of original elements data
|
||||
originalElements: Map<string, NonDeleted<ExcalidrawElement>>;
|
||||
resize: {
|
||||
// Handle when resizing, might change during the pointer interaction
|
||||
handleType: MaybeTransformHandleType;
|
||||
// This is determined on the initial pointer down event
|
||||
isResizing: boolean;
|
||||
// This is determined on the initial pointer down event
|
||||
offset: { x: number; y: number };
|
||||
// This is determined on the initial pointer down event
|
||||
arrowDirection: "origin" | "end";
|
||||
// This is a center point of selected elements determined on the initial pointer down event (for rotation only)
|
||||
center: { x: number; y: number };
|
||||
};
|
||||
hit: {
|
||||
// The element the pointer is "hitting", is determined on the initial
|
||||
// pointer down event
|
||||
element: NonDeleted<ExcalidrawElement> | null;
|
||||
// The elements the pointer is "hitting", is determined on the initial
|
||||
// pointer down event
|
||||
allHitElements: NonDeleted<ExcalidrawElement>[];
|
||||
// This is determined on the initial pointer down event
|
||||
wasAddedToSelection: boolean;
|
||||
// Whether selected element(s) were duplicated, might change during the
|
||||
// pointer interaction
|
||||
hasBeenDuplicated: boolean;
|
||||
hasHitCommonBoundingBoxOfSelectedElements: boolean;
|
||||
};
|
||||
withCmdOrCtrl: boolean;
|
||||
drag: {
|
||||
// Might change during the pointer interation
|
||||
hasOccurred: boolean;
|
||||
// Might change during the pointer interation
|
||||
offset: { x: number; y: number } | null;
|
||||
};
|
||||
// We need to have these in the state so that we can unsubscribe them
|
||||
eventListeners: {
|
||||
// It's defined on the initial pointer down event
|
||||
onMove: null | ((event: PointerEvent) => void);
|
||||
// It's defined on the initial pointer down event
|
||||
onUp: null | ((event: PointerEvent) => void);
|
||||
// It's defined on the initial pointer down event
|
||||
onKeyDown: null | ((event: KeyboardEvent) => void);
|
||||
// It's defined on the initial pointer down event
|
||||
onKeyUp: null | ((event: KeyboardEvent) => void);
|
||||
};
|
||||
}>;
|
||||
|
||||
export type ExcalidrawImperativeAPI = {
|
||||
updateScene: InstanceType<typeof App>["updateScene"];
|
||||
resetScene: InstanceType<typeof App>["resetScene"];
|
||||
getSceneElementsIncludingDeleted: InstanceType<
|
||||
typeof App
|
||||
>["getSceneElementsIncludingDeleted"];
|
||||
history: {
|
||||
clear: InstanceType<typeof App>["resetHistory"];
|
||||
};
|
||||
scrollToContent: InstanceType<typeof App>["scrollToContent"];
|
||||
getSceneElements: InstanceType<typeof App>["getSceneElements"];
|
||||
getAppState: () => InstanceType<typeof App>["state"];
|
||||
refresh: InstanceType<typeof App>["refresh"];
|
||||
importLibrary: InstanceType<typeof App>["importLibraryFromUrl"];
|
||||
setToastMessage: InstanceType<typeof App>["setToastMessage"];
|
||||
readyPromise: ResolvablePromise<ExcalidrawImperativeAPI>;
|
||||
ready: true;
|
||||
id: string;
|
||||
};
|
||||
|
||||
class App extends React.Component<AppProps, AppState> {
|
||||
canvas: HTMLCanvasElement | null = null;
|
||||
rc: RoughCanvas | null = null;
|
||||
@@ -247,10 +321,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
public libraryItemsFromStorage: LibraryItems | undefined;
|
||||
private id: string;
|
||||
private history: History;
|
||||
private excalidrawContainerValue: {
|
||||
container: HTMLDivElement | null;
|
||||
id: string;
|
||||
};
|
||||
|
||||
constructor(props: AppProps) {
|
||||
super(props);
|
||||
@@ -307,12 +377,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
readyPromise.resolve(api);
|
||||
}
|
||||
|
||||
this.excalidrawContainerValue = {
|
||||
container: this.excalidrawContainerRef.current,
|
||||
id: this.id,
|
||||
};
|
||||
|
||||
this.scene = new Scene();
|
||||
this.library = new Library(this);
|
||||
this.history = new History();
|
||||
@@ -340,7 +404,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
if (viewModeEnabled) {
|
||||
return (
|
||||
<canvas
|
||||
className="excalidraw__canvas"
|
||||
id="canvas"
|
||||
style={{
|
||||
width: canvasDOMWidth,
|
||||
height: canvasDOMHeight,
|
||||
@@ -362,7 +426,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
return (
|
||||
<canvas
|
||||
className="excalidraw__canvas"
|
||||
id="canvas"
|
||||
style={{
|
||||
width: canvasDOMWidth,
|
||||
height: canvasDOMHeight,
|
||||
@@ -407,7 +471,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
>
|
||||
<ExcalidrawContainerContext.Provider
|
||||
value={this.excalidrawContainerValue}
|
||||
value={this.excalidrawContainerRef.current}
|
||||
>
|
||||
<IsMobileContext.Provider value={this.isMobile}>
|
||||
<LayerUI
|
||||
@@ -470,9 +534,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
|
||||
public focusContainer = () => {
|
||||
if (this.props.autoFocus) {
|
||||
this.excalidrawContainerRef.current?.focus();
|
||||
}
|
||||
this.excalidrawContainerRef.current?.focus();
|
||||
};
|
||||
|
||||
public getSceneElementsIncludingDeleted = () => {
|
||||
@@ -738,8 +800,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
};
|
||||
|
||||
public async componentDidMount() {
|
||||
this.excalidrawContainerValue.container = this.excalidrawContainerRef.current;
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV === ENV.TEST ||
|
||||
process.env.NODE_ENV === ENV.DEVELOPMENT
|
||||
@@ -809,15 +869,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
} else {
|
||||
this.updateDOMRect(this.initializeScene);
|
||||
}
|
||||
|
||||
try {
|
||||
const fileHandle = await idb.get(IDB_KEYS.fileHandle);
|
||||
if (fileHandle) {
|
||||
this.setState({ fileHandle });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
@@ -1600,10 +1651,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||
);
|
||||
if (selectedElements.length) {
|
||||
if (event.key === KEYS.G) {
|
||||
this.setState({ openPopup: "backgroundColorPicker" });
|
||||
this.setState({ openMenu: "backgroundColorPicker" });
|
||||
}
|
||||
if (event.key === KEYS.S) {
|
||||
this.setState({ openPopup: "strokeColorPicker" });
|
||||
this.setState({ openMenu: "strokeColorPicker" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1811,6 +1862,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
/** if true, returns the first selected element (with highest z-index)
|
||||
of all hit elements */
|
||||
preferSelected?: boolean;
|
||||
cycleElementsUnderCursor?: boolean;
|
||||
},
|
||||
): NonDeleted<ExcalidrawElement> | null {
|
||||
const allHitElements = this.getElementsAtPosition(x, y);
|
||||
@@ -1821,6 +1873,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
return allHitElements[index];
|
||||
}
|
||||
}
|
||||
} else if (opts?.cycleElementsUnderCursor) {
|
||||
const selectedIdx = allHitElements.findIndex(
|
||||
(element) => this.state.selectedElementIds[element.id],
|
||||
);
|
||||
return selectedIdx > 0
|
||||
? allHitElements[selectedIdx - 1]
|
||||
: allHitElements[allHitElements.length - 1];
|
||||
}
|
||||
const elementWithHighestZIndex =
|
||||
allHitElements[allHitElements.length - 1];
|
||||
@@ -2257,6 +2316,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
private handleCanvasPointerDown = (
|
||||
event: React.PointerEvent<HTMLCanvasElement>,
|
||||
) => {
|
||||
event.persist();
|
||||
|
||||
// remove any active selection when we start to interact with canvas
|
||||
// (mainly, we care about removing selection outside the component which
|
||||
// would prevent our copy handling otherwise)
|
||||
@@ -2693,10 +2754,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
// hitElement may already be set above, so check first
|
||||
pointerDownState.hit.element =
|
||||
pointerDownState.hit.element ??
|
||||
(!event[KEYS.CTRL_OR_CMD] ? pointerDownState.hit.element : null) ??
|
||||
this.getElementAtPosition(
|
||||
pointerDownState.origin.x,
|
||||
pointerDownState.origin.y,
|
||||
{
|
||||
cycleElementsUnderCursor: event[KEYS.CTRL_OR_CMD],
|
||||
},
|
||||
);
|
||||
|
||||
// For overlapped elements one position may hit
|
||||
|
||||
@@ -16,5 +16,10 @@ export const BackgroundPickerAndDarkModeToggle = ({
|
||||
<div style={{ display: "flex" }}>
|
||||
{actionManager.renderAction("changeViewBackgroundColor")}
|
||||
{showThemeBtn && actionManager.renderAction("toggleTheme")}
|
||||
{appState.fileHandle && (
|
||||
<div style={{ marginInlineStart: "0.25rem" }}>
|
||||
{actionManager.renderAction("saveToActiveFile")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import clsx from "clsx";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useCallbackRefState } from "../hooks/useCallbackRefState";
|
||||
import { t } from "../i18n";
|
||||
import { useExcalidrawContainer, useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { KEYS } from "../keys";
|
||||
import "./Dialog.scss";
|
||||
import { back, close } from "./icons";
|
||||
@@ -21,7 +21,6 @@ export const Dialog = (props: {
|
||||
}) => {
|
||||
const [islandNode, setIslandNode] = useCallbackRefState<HTMLDivElement>();
|
||||
const [lastActiveElement] = useState(document.activeElement);
|
||||
const { id } = useExcalidrawContainer();
|
||||
|
||||
useEffect(() => {
|
||||
if (!islandNode) {
|
||||
@@ -83,7 +82,7 @@ export const Dialog = (props: {
|
||||
theme={props.theme}
|
||||
>
|
||||
<Island ref={setIslandNode}>
|
||||
<h2 id={`${id}-dialog-title`} className="Dialog__title">
|
||||
<h2 id="dialog-title" className="Dialog__title">
|
||||
<span className="Dialog__titleContent">{props.title}</span>
|
||||
<button
|
||||
className="Modal__close"
|
||||
|
||||
@@ -12,7 +12,7 @@ export const ErrorDialog = ({
|
||||
onClose?: () => void;
|
||||
}) => {
|
||||
const [modalIsShown, setModalIsShown] = useState(!!message);
|
||||
const { container: excalidrawContainer } = useExcalidrawContainer();
|
||||
const excalidrawContainer = useExcalidrawContainer();
|
||||
|
||||
const handleClose = React.useCallback(() => {
|
||||
setModalIsShown(false);
|
||||
|
||||
@@ -97,8 +97,7 @@
|
||||
|
||||
border-radius: 1rem;
|
||||
background-color: var(--button-color);
|
||||
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.28),
|
||||
0 6px 10px 0 rgba(0, 0, 0, 0.14);
|
||||
box-shadow: 0 3px 5px -1px rgb(0 0 0 / 28%), 0 6px 10px 0 rgb(0 0 0 / 14%);
|
||||
|
||||
font-family: Cascadia;
|
||||
font-size: 1.8em;
|
||||
|
||||
@@ -157,13 +157,6 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
|
||||
shortcuts={["Shift+P", "7"]}
|
||||
/>
|
||||
<Shortcut label={t("toolBar.text")} shortcuts={["T", "8"]} />
|
||||
<Shortcut
|
||||
label={t("helpDialog.editSelectedShape")}
|
||||
shortcuts={[
|
||||
getShortcutKey("Enter"),
|
||||
t("helpDialog.doubleClick"),
|
||||
]}
|
||||
/>
|
||||
<Shortcut
|
||||
label={t("helpDialog.textNewLine")}
|
||||
shortcuts={[
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getSelectedElements } from "../scene";
|
||||
|
||||
import "./HintViewer.scss";
|
||||
import { AppState } from "../types";
|
||||
import { isLinearElement, isTextElement } from "../element/typeChecks";
|
||||
import { isLinearElement } from "../element/typeChecks";
|
||||
import { getShortcutKey } from "../utils";
|
||||
|
||||
interface Hint {
|
||||
@@ -57,14 +57,6 @@ const getHints = ({ appState, elements }: Hint) => {
|
||||
return t("hints.lineEditor_info");
|
||||
}
|
||||
|
||||
if (selectedElements.length === 1 && isTextElement(selectedElements[0])) {
|
||||
return t("hints.text_selected");
|
||||
}
|
||||
|
||||
if (appState.editingElement && isTextElement(appState.editingElement)) {
|
||||
return t("hints.text_editing");
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,17 +8,20 @@ import { CanvasError } from "../errors";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "./App";
|
||||
import { getSelectedElements, isSomeElementSelected } from "../scene";
|
||||
import { exportToCanvas } from "../scene/export";
|
||||
import { exportToCanvas, getExportSize } from "../scene/export";
|
||||
import { AppState } from "../types";
|
||||
import { Dialog } from "./Dialog";
|
||||
import { clipboard, exportImage } from "./icons";
|
||||
import Stack from "./Stack";
|
||||
import { ToolButton } from "./ToolButton";
|
||||
|
||||
import "./ExportDialog.scss";
|
||||
import { supported as fsSupported } from "browser-fs-access";
|
||||
import OpenColor from "open-color";
|
||||
import { CheckboxItem } from "./CheckboxItem";
|
||||
import { DEFAULT_EXPORT_PADDING } from "../constants";
|
||||
|
||||
const scales = [1, 2, 3];
|
||||
const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1;
|
||||
|
||||
const supportsContextFilters =
|
||||
"filter" in document.createElement("canvas").getContext("2d")!;
|
||||
@@ -79,7 +82,7 @@ const ExportButton: React.FC<{
|
||||
const ImageExportModal = ({
|
||||
elements,
|
||||
appState,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
exportPadding = 10,
|
||||
actionManager,
|
||||
onExportToPng,
|
||||
onExportToSvg,
|
||||
@@ -95,6 +98,7 @@ const ImageExportModal = ({
|
||||
onCloseRequest: () => void;
|
||||
}) => {
|
||||
const someElementIsSelected = isSomeElementSelected(elements, appState);
|
||||
const [scale, setScale] = useState(defaultScale);
|
||||
const [exportSelected, setExportSelected] = useState(someElementIsSelected);
|
||||
const previewRef = useRef<HTMLDivElement>(null);
|
||||
const { exportBackground, viewBackgroundColor } = appState;
|
||||
@@ -117,6 +121,7 @@ const ImageExportModal = ({
|
||||
exportBackground,
|
||||
viewBackgroundColor,
|
||||
exportPadding,
|
||||
scale,
|
||||
});
|
||||
|
||||
// if converting to blob fails, there's some problem that will
|
||||
@@ -139,6 +144,7 @@ const ImageExportModal = ({
|
||||
exportBackground,
|
||||
exportPadding,
|
||||
viewBackgroundColor,
|
||||
scale,
|
||||
]);
|
||||
|
||||
return (
|
||||
@@ -169,8 +175,33 @@ const ImageExportModal = ({
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", alignItems: "center", marginTop: ".6em" }}>
|
||||
<Stack.Row gap={2}>
|
||||
{actionManager.renderAction("changeExportScale")}
|
||||
<Stack.Row gap={2} justifyContent={"center"}>
|
||||
{scales.map((_scale) => {
|
||||
const [width, height] = getExportSize(
|
||||
exportedElements,
|
||||
exportPadding,
|
||||
_scale,
|
||||
);
|
||||
|
||||
const scaleButtonTitle = `${t(
|
||||
"buttons.scale",
|
||||
)} ${_scale}x (${width}x${height})`;
|
||||
|
||||
return (
|
||||
<ToolButton
|
||||
key={_scale}
|
||||
size="s"
|
||||
type="radio"
|
||||
icon={`${_scale}x`}
|
||||
name="export-canvas-scale"
|
||||
title={scaleButtonTitle}
|
||||
aria-label={scaleButtonTitle}
|
||||
id="export-canvas-scale"
|
||||
checked={_scale === scale}
|
||||
onChange={() => setScale(_scale)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack.Row>
|
||||
<p style={{ marginLeft: "1em", userSelect: "none" }}>Scale</p>
|
||||
</div>
|
||||
@@ -189,7 +220,7 @@ const ImageExportModal = ({
|
||||
color="indigo"
|
||||
title={t("buttons.exportToPng")}
|
||||
aria-label={t("buttons.exportToPng")}
|
||||
onClick={() => onExportToPng(exportedElements)}
|
||||
onClick={() => onExportToPng(exportedElements, scale)}
|
||||
>
|
||||
PNG
|
||||
</ExportButton>
|
||||
@@ -197,14 +228,14 @@ const ImageExportModal = ({
|
||||
color="red"
|
||||
title={t("buttons.exportToSvg")}
|
||||
aria-label={t("buttons.exportToSvg")}
|
||||
onClick={() => onExportToSvg(exportedElements)}
|
||||
onClick={() => onExportToSvg(exportedElements, scale)}
|
||||
>
|
||||
SVG
|
||||
</ExportButton>
|
||||
{probablySupportsClipboardBlob && (
|
||||
<ExportButton
|
||||
title={t("buttons.copyPngToClipboard")}
|
||||
onClick={() => onExportToClipboard(exportedElements)}
|
||||
onClick={() => onExportToClipboard(exportedElements, scale)}
|
||||
color="gray"
|
||||
shade={7}
|
||||
>
|
||||
@@ -219,7 +250,7 @@ const ImageExportModal = ({
|
||||
export const ImageExportDialog = ({
|
||||
elements,
|
||||
appState,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
exportPadding = 10,
|
||||
actionManager,
|
||||
onExportToPng,
|
||||
onExportToSvg,
|
||||
|
||||
@@ -36,7 +36,7 @@ import { Island } from "./Island";
|
||||
import "./LayerUI.scss";
|
||||
import { LibraryUnit } from "./LibraryUnit";
|
||||
import { LoadingMessage } from "./LoadingMessage";
|
||||
import { LockButton } from "./LockButton";
|
||||
import { LockIcon } from "./LockIcon";
|
||||
import { MobileMenu } from "./MobileMenu";
|
||||
import { PasteChartDialog } from "./PasteChartDialog";
|
||||
import { Section } from "./Section";
|
||||
@@ -47,7 +47,6 @@ import { Tooltip } from "./Tooltip";
|
||||
import { UserList } from "./UserList";
|
||||
import Library from "../data/library";
|
||||
import { JSONExportDialog } from "./JSONExportDialog";
|
||||
import { LibraryButton } from "./LibraryButton";
|
||||
|
||||
interface LayerUIProps {
|
||||
actionManager: ActionManager;
|
||||
@@ -108,7 +107,6 @@ const LibraryMenuItems = ({
|
||||
onAddToLibrary,
|
||||
onInsertShape,
|
||||
pendingElements,
|
||||
theme,
|
||||
setAppState,
|
||||
setLibraryItems,
|
||||
libraryReturnUrl,
|
||||
@@ -121,7 +119,6 @@ const LibraryMenuItems = ({
|
||||
onRemoveFromLibrary: (index: number) => void;
|
||||
onInsertShape: (elements: LibraryItem) => void;
|
||||
onAddToLibrary: (elements: LibraryItem) => void;
|
||||
theme: AppState["theme"];
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
setLibraryItems: (library: LibraryItems) => void;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
@@ -195,7 +192,7 @@ const LibraryMenuItems = ({
|
||||
<a
|
||||
href={`https://libraries.excalidraw.com?target=${
|
||||
window.name || "_blank"
|
||||
}&referrer=${referrer}&useHash=true&token=${id}&theme=${theme}`}
|
||||
}&referrer=${referrer}&useHash=true&token=${id}`}
|
||||
target="_excalidraw_libraries"
|
||||
>
|
||||
{t("labels.libraries")}
|
||||
@@ -249,7 +246,6 @@ const LibraryMenu = ({
|
||||
onInsertShape,
|
||||
pendingElements,
|
||||
onAddToLibrary,
|
||||
theme,
|
||||
setAppState,
|
||||
libraryReturnUrl,
|
||||
focusContainer,
|
||||
@@ -260,7 +256,6 @@ const LibraryMenu = ({
|
||||
onClickOutside: (event: MouseEvent) => void;
|
||||
onInsertShape: (elements: LibraryItem) => void;
|
||||
onAddToLibrary: () => void;
|
||||
theme: AppState["theme"];
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
focusContainer: () => void;
|
||||
@@ -350,7 +345,6 @@ const LibraryMenu = ({
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
focusContainer={focusContainer}
|
||||
library={library}
|
||||
theme={theme}
|
||||
id={id}
|
||||
/>
|
||||
)}
|
||||
@@ -406,11 +400,13 @@ const LayerUI = ({
|
||||
|
||||
const createExporter = (type: ExportType): ExportCB => async (
|
||||
exportedElements,
|
||||
scale,
|
||||
) => {
|
||||
await exportCanvas(type, exportedElements, appState, {
|
||||
exportBackground: appState.exportBackground,
|
||||
name: appState.name,
|
||||
viewBackgroundColor: appState.viewBackgroundColor,
|
||||
scale,
|
||||
})
|
||||
.catch(muteFSAbortError)
|
||||
.catch((error) => {
|
||||
@@ -488,9 +484,6 @@ const LayerUI = ({
|
||||
setAppState={setAppState}
|
||||
showThemeBtn={showThemeBtn}
|
||||
/>
|
||||
{appState.fileHandle && (
|
||||
<>{actionManager.renderAction("saveToActiveFile")}</>
|
||||
)}
|
||||
</Stack.Col>
|
||||
</Island>
|
||||
</Section>
|
||||
@@ -509,8 +502,7 @@ const LayerUI = ({
|
||||
style={{
|
||||
// we want to make sure this doesn't overflow so substracting 200
|
||||
// which is approximately height of zoom footer and top left menu items with some buffer
|
||||
// if active file name is displayed, subtracting 248 to account for its height
|
||||
maxHeight: `${appState.height - (appState.fileHandle ? 248 : 200)}px`,
|
||||
maxHeight: `${appState.height - 200}px`,
|
||||
}}
|
||||
>
|
||||
<SelectedShapeActions
|
||||
@@ -547,7 +539,6 @@ const LayerUI = ({
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
focusContainer={focusContainer}
|
||||
library={library}
|
||||
theme={appState.theme}
|
||||
id={id}
|
||||
/>
|
||||
) : null;
|
||||
@@ -575,12 +566,6 @@ const LayerUI = ({
|
||||
{(heading) => (
|
||||
<Stack.Col gap={4} align="start">
|
||||
<Stack.Row gap={1}>
|
||||
<LockButton
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
checked={appState.elementLocked}
|
||||
onChange={onLockToggle}
|
||||
title={t("toolBar.lock")}
|
||||
/>
|
||||
<Island
|
||||
padding={1}
|
||||
className={clsx({ "zen-mode": zenModeEnabled })}
|
||||
@@ -592,12 +577,15 @@ const LayerUI = ({
|
||||
canvas={canvas}
|
||||
elementType={appState.elementType}
|
||||
setAppState={setAppState}
|
||||
isLibraryOpen={appState.isLibraryOpen}
|
||||
/>
|
||||
</Stack.Row>
|
||||
</Island>
|
||||
<LibraryButton
|
||||
appState={appState}
|
||||
setAppState={setAppState}
|
||||
<LockIcon
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
checked={appState.elementLocked}
|
||||
onChange={onLockToggle}
|
||||
title={t("toolBar.lock")}
|
||||
/>
|
||||
</Stack.Row>
|
||||
{libraryMenu}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import clsx from "clsx";
|
||||
import { t } from "../i18n";
|
||||
import { AppState } from "../types";
|
||||
import { capitalizeString } from "../utils";
|
||||
|
||||
const LIBRARY_ICON = (
|
||||
<svg viewBox="0 0 576 512">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M542.22 32.05c-54.8 3.11-163.72 14.43-230.96 55.59-4.64 2.84-7.27 7.89-7.27 13.17v363.87c0 11.55 12.63 18.85 23.28 13.49 69.18-34.82 169.23-44.32 218.7-46.92 16.89-.89 30.02-14.43 30.02-30.66V62.75c.01-17.71-15.35-31.74-33.77-30.7zM264.73 87.64C197.5 46.48 88.58 35.17 33.78 32.05 15.36 31.01 0 45.04 0 62.75V400.6c0 16.24 13.13 29.78 30.02 30.66 49.49 2.6 149.59 12.11 218.77 46.95 10.62 5.35 23.21-1.94 23.21-13.46V100.63c0-5.29-2.62-10.14-7.27-12.99z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const LibraryButton: React.FC<{
|
||||
appState: AppState;
|
||||
setAppState: React.Component<any, AppState>["setState"];
|
||||
}> = ({ appState, setAppState }) => {
|
||||
return (
|
||||
<label
|
||||
className={clsx(
|
||||
"ToolIcon ToolIcon_type_floating ToolIcon__library zen-mode-visibility",
|
||||
`ToolIcon_size_m`,
|
||||
{
|
||||
"zen-mode-visibility--hidden": appState.zenModeEnabled,
|
||||
},
|
||||
)}
|
||||
title={`${capitalizeString(t("toolBar.library"))} — 9`}
|
||||
style={{ marginInlineStart: "var(--space-factor)" }}
|
||||
>
|
||||
<input
|
||||
className="ToolIcon_type_checkbox"
|
||||
type="checkbox"
|
||||
name="editor-library"
|
||||
onChange={(event) => {
|
||||
setAppState({ isLibraryOpen: event.target.checked });
|
||||
}}
|
||||
checked={appState.isLibraryOpen}
|
||||
aria-label={capitalizeString(t("toolBar.library"))}
|
||||
aria-keyshortcuts="9"
|
||||
/>
|
||||
<div className="ToolIcon__icon">{LIBRARY_ICON}</div>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
@@ -8,8 +8,10 @@ type LockIconSize = "s" | "m";
|
||||
type LockIconProps = {
|
||||
title?: string;
|
||||
name?: string;
|
||||
id?: string;
|
||||
checked: boolean;
|
||||
onChange?(): void;
|
||||
size?: LockIconSize;
|
||||
zenModeEnabled?: boolean;
|
||||
};
|
||||
|
||||
@@ -39,12 +41,12 @@ const ICONS = {
|
||||
),
|
||||
};
|
||||
|
||||
export const LockButton = (props: LockIconProps) => {
|
||||
export const LockIcon = (props: LockIconProps) => {
|
||||
return (
|
||||
<label
|
||||
className={clsx(
|
||||
"ToolIcon ToolIcon__lock ToolIcon_type_floating zen-mode-visibility",
|
||||
`ToolIcon_size_${DEFAULT_SIZE}`,
|
||||
`ToolIcon_size_${props.size || DEFAULT_SIZE}`,
|
||||
{
|
||||
"zen-mode-visibility--hidden": props.zenModeEnabled,
|
||||
},
|
||||
@@ -55,6 +57,7 @@ export const LockButton = (props: LockIconProps) => {
|
||||
className="ToolIcon_type_checkbox"
|
||||
type="checkbox"
|
||||
name={props.name}
|
||||
id={props.id}
|
||||
onChange={props.onChange}
|
||||
checked={props.checked}
|
||||
aria-label={props.title}
|
||||
@@ -13,10 +13,9 @@ import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
||||
import { Section } from "./Section";
|
||||
import CollabButton from "./CollabButton";
|
||||
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
|
||||
import { LockButton } from "./LockButton";
|
||||
import { LockIcon } from "./LockIcon";
|
||||
import { UserList } from "./UserList";
|
||||
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
|
||||
import { LibraryButton } from "./LibraryButton";
|
||||
|
||||
type MobileMenuProps = {
|
||||
appState: AppState;
|
||||
@@ -65,15 +64,15 @@ export const MobileMenu = ({
|
||||
canvas={canvas}
|
||||
elementType={appState.elementType}
|
||||
setAppState={setAppState}
|
||||
isLibraryOpen={appState.isLibraryOpen}
|
||||
/>
|
||||
</Stack.Row>
|
||||
</Island>
|
||||
<LockButton
|
||||
<LockIcon
|
||||
checked={appState.elementLocked}
|
||||
onChange={onLockToggle}
|
||||
title={t("toolBar.lock")}
|
||||
/>
|
||||
<LibraryButton appState={appState} setAppState={setAppState} />
|
||||
</Stack.Row>
|
||||
{libraryMenu}
|
||||
</Stack.Col>
|
||||
|
||||
@@ -58,7 +58,7 @@ const useBodyRoot = (theme: AppState["theme"]) => {
|
||||
const isMobileRef = useRef(isMobile);
|
||||
isMobileRef.current = isMobile;
|
||||
|
||||
const { container: excalidrawContainer } = useExcalidrawContainer();
|
||||
const excalidrawContainer = useExcalidrawContainer();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (div) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import "./TextInput.scss";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import React, { Component } from "react";
|
||||
import { focusNearestParent } from "../utils";
|
||||
|
||||
import "./ProjectName.scss";
|
||||
import { useExcalidrawContainer } from "./App";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
@@ -13,19 +12,22 @@ type Props = {
|
||||
isNameEditable: boolean;
|
||||
};
|
||||
|
||||
export const ProjectName = (props: Props) => {
|
||||
const { id } = useExcalidrawContainer();
|
||||
const [fileName, setFileName] = useState<string>(props.value);
|
||||
|
||||
const handleBlur = (event: any) => {
|
||||
type State = {
|
||||
fileName: string;
|
||||
};
|
||||
export class ProjectName extends Component<Props, State> {
|
||||
state = {
|
||||
fileName: this.props.value,
|
||||
};
|
||||
private handleBlur = (event: any) => {
|
||||
focusNearestParent(event.target);
|
||||
const value = event.target.value;
|
||||
if (value !== props.value) {
|
||||
props.onChange(value);
|
||||
if (value !== this.props.value) {
|
||||
this.props.onChange(value);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
private handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
if (event.nativeEvent.isComposing || event.keyCode === 229) {
|
||||
@@ -35,25 +37,29 @@ export const ProjectName = (props: Props) => {
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ProjectName">
|
||||
<label className="ProjectName-label" htmlFor="filename">
|
||||
{`${props.label}${props.isNameEditable ? "" : ":"}`}
|
||||
</label>
|
||||
{props.isNameEditable ? (
|
||||
<input
|
||||
className="TextInput"
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
id={`${id}-filename`}
|
||||
value={fileName}
|
||||
onChange={(event) => setFileName(event.target.value)}
|
||||
/>
|
||||
) : (
|
||||
<span className="TextInput TextInput--readonly" id={`${id}-filename`}>
|
||||
{props.value}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<div className="ProjectName">
|
||||
<label className="ProjectName-label" htmlFor="filename">
|
||||
{`${this.props.label}${this.props.isNameEditable ? "" : ":"}`}
|
||||
</label>
|
||||
{this.props.isNameEditable ? (
|
||||
<input
|
||||
className="TextInput"
|
||||
onBlur={this.handleBlur}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
id="filename"
|
||||
value={this.state.fileName}
|
||||
onChange={(event) =>
|
||||
this.setState({ fileName: event.target.value })
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<span className="TextInput TextInput--readonly" id="filename">
|
||||
{this.props.value}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { t } from "../i18n";
|
||||
import { useExcalidrawContainer } from "./App";
|
||||
|
||||
interface SectionProps extends React.HTMLProps<HTMLElement> {
|
||||
heading: string;
|
||||
@@ -8,14 +7,13 @@ interface SectionProps extends React.HTMLProps<HTMLElement> {
|
||||
}
|
||||
|
||||
export const Section = ({ heading, children, ...props }: SectionProps) => {
|
||||
const { id } = useExcalidrawContainer();
|
||||
const header = (
|
||||
<h2 className="visually-hidden" id={`${id}-${heading}-title`}>
|
||||
<h2 className="visually-hidden" id={`${heading}-title`}>
|
||||
{t(`headings.${heading}`)}
|
||||
</h2>
|
||||
);
|
||||
return (
|
||||
<section {...props} aria-labelledby={`${id}-${heading}-title`}>
|
||||
<section {...props} aria-labelledby={`${heading}-title`}>
|
||||
{typeof children === "function" ? (
|
||||
children(header)
|
||||
) : (
|
||||
|
||||
@@ -2,7 +2,6 @@ import "./ToolIcon.scss";
|
||||
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import { useExcalidrawContainer } from "./App";
|
||||
|
||||
type ToolIconSize = "s" | "m";
|
||||
|
||||
@@ -44,7 +43,6 @@ type ToolButtonProps =
|
||||
const DEFAULT_SIZE: ToolIconSize = "m";
|
||||
|
||||
export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
|
||||
const { id: excalId } = useExcalidrawContainer();
|
||||
const innerRef = React.useRef(null);
|
||||
React.useImperativeHandle(ref, () => innerRef.current);
|
||||
const sizeCn = `ToolIcon_size_${props.size || DEFAULT_SIZE}`;
|
||||
@@ -100,7 +98,7 @@ export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
|
||||
aria-label={props["aria-label"]}
|
||||
aria-keyshortcuts={props["aria-keyshortcuts"]}
|
||||
data-testid={props["data-testid"]}
|
||||
id={`${excalId}-${props.id}`}
|
||||
id={props.id}
|
||||
onChange={props.onChange}
|
||||
checked={props.checked}
|
||||
ref={innerRef}
|
||||
|
||||
@@ -8,18 +8,10 @@
|
||||
position: relative;
|
||||
font-family: Cascadia;
|
||||
cursor: pointer;
|
||||
background-color: var(--button-gray-1);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
border-radius: var(--space-factor);
|
||||
user-select: none;
|
||||
|
||||
background-color: var(--button-gray-1);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--button-gray-2);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--button-gray-3);
|
||||
}
|
||||
}
|
||||
|
||||
.ToolIcon--plain {
|
||||
@@ -74,6 +66,14 @@
|
||||
margin: 0;
|
||||
font-size: inherit;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--button-gray-1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--button-gray-2);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2px var(--focus-highlight-color);
|
||||
}
|
||||
@@ -86,14 +86,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--button-gray-2);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--button-gray-3);
|
||||
}
|
||||
|
||||
&--show {
|
||||
visibility: visible;
|
||||
}
|
||||
@@ -111,9 +103,6 @@
|
||||
|
||||
&:not(.ToolIcon_toggle_opaque):checked + .ToolIcon__icon {
|
||||
background-color: var(--button-gray-2);
|
||||
&:active {
|
||||
background-color: var(--button-gray-3);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus + .ToolIcon__icon {
|
||||
@@ -141,21 +130,12 @@
|
||||
}
|
||||
|
||||
.ToolIcon__icon {
|
||||
background-color: var(--button-gray-1);
|
||||
&:hover {
|
||||
background-color: var(--button-gray-2);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--button-gray-3);
|
||||
}
|
||||
|
||||
width: 2rem;
|
||||
height: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.ToolIcon.ToolIcon__lock {
|
||||
margin-inline-end: var(--space-factor);
|
||||
&.ToolIcon_type_floating {
|
||||
margin-left: 0.1rem;
|
||||
}
|
||||
@@ -186,9 +166,10 @@
|
||||
// move the lock button out of the way on small viewports
|
||||
// it begins to collide with the GitHub icon before we switch to mobile mode
|
||||
@media (max-width: 760px) {
|
||||
.ToolIcon.ToolIcon_type_floating {
|
||||
.ToolIcon.ToolIcon__lock {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: -8px;
|
||||
|
||||
margin-left: 0;
|
||||
@@ -213,14 +194,6 @@
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
.ToolIcon.ToolIcon__library {
|
||||
top: 100px;
|
||||
}
|
||||
|
||||
.ToolIcon.ToolIcon__lock {
|
||||
margin-inline-end: 0;
|
||||
top: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.unlocked-icon {
|
||||
|
||||
@@ -24,10 +24,7 @@ type Opts = {
|
||||
mirror?: true;
|
||||
} & React.SVGProps<SVGSVGElement>;
|
||||
|
||||
export const createIcon = (
|
||||
d: string | React.ReactNode,
|
||||
opts: number | Opts = 512,
|
||||
) => {
|
||||
const createIcon = (d: string | React.ReactNode, opts: number | Opts = 512) => {
|
||||
const { width = 512, height = width, mirror, style } =
|
||||
typeof opts === "number" ? ({ width: opts } as Opts) : opts;
|
||||
return (
|
||||
@@ -477,11 +474,6 @@ export const shield = createIcon(
|
||||
{ width: 24 },
|
||||
);
|
||||
|
||||
export const file = createIcon(
|
||||
"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm32-48h224V288l-23.5-23.5c-4.7-4.7-12.3-4.7-17 0L176 352l-39.5-39.5c-4.7-4.7-12.3-4.7-17 0L80 352v64zm48-240c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z",
|
||||
{ width: 384, height: 512 },
|
||||
);
|
||||
|
||||
export const GroupIcon = React.memo(({ theme }: { theme: "light" | "dark" }) =>
|
||||
createIcon(
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FontFamily } from "./element/types";
|
||||
import cssVariables from "./css/variables.module.scss";
|
||||
import { AppProps } from "./types";
|
||||
import { FontFamilyValues } from "./element/types";
|
||||
|
||||
export const APP_NAME = "Excalidraw";
|
||||
|
||||
@@ -63,15 +63,15 @@ export const CLASSES = {
|
||||
|
||||
// 1-based in case we ever do `if(element.fontFamily)`
|
||||
export const FONT_FAMILY = {
|
||||
Virgil: 1,
|
||||
Helvetica: 2,
|
||||
Cascadia: 3,
|
||||
};
|
||||
1: "Virgil",
|
||||
2: "Helvetica",
|
||||
3: "Cascadia",
|
||||
} as const;
|
||||
|
||||
export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
|
||||
|
||||
export const DEFAULT_FONT_SIZE = 20;
|
||||
export const DEFAULT_FONT_FAMILY: FontFamilyValues = FONT_FAMILY.Virgil;
|
||||
export const DEFAULT_FONT_FAMILY: FontFamily = 1;
|
||||
export const DEFAULT_TEXT_ALIGN = "left";
|
||||
export const DEFAULT_VERTICAL_ALIGN = "top";
|
||||
export const DEFAULT_VERSION = "{version}";
|
||||
@@ -97,10 +97,6 @@ export const STORAGE_KEYS = {
|
||||
LOCAL_STORAGE_LIBRARY: "excalidraw-library",
|
||||
} as const;
|
||||
|
||||
export const IDB_KEYS = {
|
||||
fileHandle: "fileHandle",
|
||||
} as const;
|
||||
|
||||
// time in milliseconds
|
||||
export const TAP_TWICE_TIMEOUT = 300;
|
||||
export const TOUCH_CTX_MENU_TIMEOUT = 500;
|
||||
@@ -148,6 +144,3 @@ export const MQ_MAX_WIDTH_LANDSCAPE = 1000;
|
||||
export const MQ_MAX_HEIGHT_LANDSCAPE = 500;
|
||||
|
||||
export const MAX_DECIMALS_FOR_SVG_EXPORT = 2;
|
||||
|
||||
export const EXPORT_SCALES = [1, 2, 3];
|
||||
export const DEFAULT_EXPORT_PADDING = 10; // px
|
||||
|
||||
@@ -51,12 +51,11 @@
|
||||
image-rendering: -moz-crisp-edges; // FF
|
||||
|
||||
z-index: var(--zIndex-canvas);
|
||||
|
||||
// Remove the main canvas from document flow to avoid resizeObserver
|
||||
// feedback loop (see https://github.com/excalidraw/excalidraw/pull/3379)
|
||||
}
|
||||
|
||||
&__canvas {
|
||||
#canvas {
|
||||
// Remove the main canvas from document flow to avoid resizeObserver
|
||||
// feedback loop (see https://github.com/excalidraw/excalidraw/pull/3379)
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
copyBlobToClipboardAsPng,
|
||||
copyTextToSystemClipboard,
|
||||
} from "../clipboard";
|
||||
import { DEFAULT_EXPORT_PADDING } from "../constants";
|
||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
import { exportToCanvas, exportToSvg } from "../scene/export";
|
||||
@@ -21,14 +20,16 @@ export const exportCanvas = async (
|
||||
appState: AppState,
|
||||
{
|
||||
exportBackground,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
exportPadding = 10,
|
||||
viewBackgroundColor,
|
||||
name,
|
||||
scale = 1,
|
||||
}: {
|
||||
exportBackground: boolean;
|
||||
exportPadding?: number;
|
||||
viewBackgroundColor: string;
|
||||
name: string;
|
||||
scale?: number;
|
||||
},
|
||||
) => {
|
||||
if (elements.length === 0) {
|
||||
@@ -40,7 +41,7 @@ export const exportCanvas = async (
|
||||
exportWithDarkMode: appState.exportWithDarkMode,
|
||||
viewBackgroundColor,
|
||||
exportPadding,
|
||||
exportScale: appState.exportScale,
|
||||
scale,
|
||||
metadata:
|
||||
appState.exportEmbedScene && type === "svg"
|
||||
? await (
|
||||
@@ -66,6 +67,7 @@ export const exportCanvas = async (
|
||||
exportBackground,
|
||||
viewBackgroundColor,
|
||||
exportPadding,
|
||||
scale,
|
||||
});
|
||||
tempCanvas.style.display = "none";
|
||||
document.body.appendChild(tempCanvas);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fileOpen, fileSave, FileSystemHandle } from "browser-fs-access";
|
||||
import { fileOpen, fileSave } from "browser-fs-access";
|
||||
import { cleanAppStateForExport } from "../appState";
|
||||
import { EXPORT_DATA_TYPES, EXPORT_SOURCE, MIME_TYPES } from "../constants";
|
||||
import { clearElementsForExport } from "../element";
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
ExportedLibraryData,
|
||||
} from "./types";
|
||||
import Library from "./library";
|
||||
import { AbortError } from "../errors";
|
||||
|
||||
export const serializeAsJSON = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
@@ -29,26 +28,6 @@ export const serializeAsJSON = (
|
||||
return JSON.stringify(data, null, 2);
|
||||
};
|
||||
|
||||
// adapted from https://web.dev/file-system-access
|
||||
const verifyPermission = async (fileHandle: FileSystemHandle) => {
|
||||
try {
|
||||
const options = { mode: "readwrite" } as any;
|
||||
// Check if permission was already granted. If so, return true.
|
||||
if ((await fileHandle.queryPermission(options)) === "granted") {
|
||||
return true;
|
||||
}
|
||||
// Request permission. If the user grants permission, return true.
|
||||
if ((await fileHandle.requestPermission(options)) === "granted") {
|
||||
return true;
|
||||
}
|
||||
// The user didn't grant permission, so return false.
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveAsJSON = async (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
@@ -58,12 +37,6 @@ export const saveAsJSON = async (
|
||||
type: MIME_TYPES.excalidraw,
|
||||
});
|
||||
|
||||
if (appState.fileHandle) {
|
||||
if (!(await verifyPermission(appState.fileHandle))) {
|
||||
throw new AbortError();
|
||||
}
|
||||
}
|
||||
|
||||
const fileHandle = await fileSave(
|
||||
blob,
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ import { loadLibraryFromBlob } from "./blob";
|
||||
import { LibraryItems, LibraryItem } from "../types";
|
||||
import { restoreElements } from "./restore";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import type App from "../components/App";
|
||||
import App from "../components/App";
|
||||
|
||||
class Library {
|
||||
private libraryCache: LibraryItems | null = null;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
FontFamily,
|
||||
ExcalidrawSelectionElement,
|
||||
FontFamilyValues,
|
||||
} from "../element/types";
|
||||
import { AppState, NormalizedZoomValue } from "../types";
|
||||
import { ImportedDataState } from "./types";
|
||||
import { getNormalizedDimensions, isInvisiblySmallElement } from "../element";
|
||||
import { isInvisiblySmallElement, getNormalizedDimensions } from "../element";
|
||||
import { isLinearElementType } from "../element/typeChecks";
|
||||
import { randomId } from "../random";
|
||||
import {
|
||||
FONT_FAMILY,
|
||||
DEFAULT_FONT_FAMILY,
|
||||
DEFAULT_TEXT_ALIGN,
|
||||
DEFAULT_VERTICAL_ALIGN,
|
||||
FONT_FAMILY,
|
||||
} from "../constants";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
@@ -41,11 +41,11 @@ export type RestoredDataState = {
|
||||
appState: RestoredAppState;
|
||||
};
|
||||
|
||||
const getFontFamilyByName = (fontFamilyName: string): FontFamilyValues => {
|
||||
if (Object.keys(FONT_FAMILY).includes(fontFamilyName)) {
|
||||
return FONT_FAMILY[
|
||||
fontFamilyName as keyof typeof FONT_FAMILY
|
||||
] as FontFamilyValues;
|
||||
const getFontFamilyByName = (fontFamilyName: string): FontFamily => {
|
||||
for (const [id, fontFamilyString] of Object.entries(FONT_FAMILY)) {
|
||||
if (fontFamilyString.includes(fontFamilyName)) {
|
||||
return parseInt(id) as FontFamily;
|
||||
}
|
||||
}
|
||||
return DEFAULT_FONT_FAMILY;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import { mutateElement } from "./mutateElement";
|
||||
import { getPerfectElementSize } from "./sizeHelpers";
|
||||
import Scene from "../scene/Scene";
|
||||
import { NonDeletedExcalidrawElement } from "./types";
|
||||
import { PointerDownState } from "../types";
|
||||
import { PointerDownState } from "../components/App";
|
||||
|
||||
export const dragSelectedElements = (
|
||||
pointerDownState: PointerDownState,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { duplicateElement } from "./newElement";
|
||||
import { mutateElement } from "./mutateElement";
|
||||
import { API } from "../tests/helpers/api";
|
||||
import { FONT_FAMILY } from "../constants";
|
||||
|
||||
const isPrimitive = (val: any) => {
|
||||
const type = typeof val;
|
||||
@@ -80,7 +79,7 @@ it("clones text element", () => {
|
||||
opacity: 100,
|
||||
text: "hello",
|
||||
fontSize: 20,
|
||||
fontFamily: FONT_FAMILY.Virgil,
|
||||
fontFamily: 1,
|
||||
textAlign: "left",
|
||||
verticalAlign: "top",
|
||||
});
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
ExcalidrawGenericElement,
|
||||
NonDeleted,
|
||||
TextAlign,
|
||||
FontFamily,
|
||||
GroupId,
|
||||
VerticalAlign,
|
||||
Arrowhead,
|
||||
ExcalidrawFreeDrawElement,
|
||||
FontFamilyValues,
|
||||
} from "../element/types";
|
||||
import { measureText, getFontString } from "../utils";
|
||||
import { randomInteger, randomId } from "../random";
|
||||
@@ -109,7 +109,7 @@ export const newTextElement = (
|
||||
opts: {
|
||||
text: string;
|
||||
fontSize: number;
|
||||
fontFamily: FontFamilyValues;
|
||||
fontFamily: FontFamily;
|
||||
textAlign: TextAlign;
|
||||
verticalAlign: VerticalAlign;
|
||||
} & ElementConstructorOpts,
|
||||
|
||||
@@ -32,7 +32,8 @@ import {
|
||||
MaybeTransformHandleType,
|
||||
TransformHandleDirection,
|
||||
} from "./transformHandles";
|
||||
import { Point, PointerDownState } from "../types";
|
||||
import { PointerDownState } from "../components/App";
|
||||
import { Point } from "../types";
|
||||
|
||||
export const normalizeAngle = (angle: number): number => {
|
||||
if (angle >= 2 * Math.PI) {
|
||||
|
||||
@@ -3,8 +3,7 @@ import { FONT_FAMILY } from "../constants";
|
||||
|
||||
export type ChartType = "bar" | "line";
|
||||
export type FillStyle = "hachure" | "cross-hatch" | "solid";
|
||||
export type FontFamilyKeys = keyof typeof FONT_FAMILY;
|
||||
export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
|
||||
export type FontFamily = keyof typeof FONT_FAMILY;
|
||||
export type FontString = string & { _brand: "fontString" };
|
||||
export type GroupId = string;
|
||||
export type PointerType = "mouse" | "pen" | "touch";
|
||||
@@ -92,7 +91,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
|
||||
Readonly<{
|
||||
type: "text";
|
||||
fontSize: number;
|
||||
fontFamily: FontFamilyValues;
|
||||
fontFamily: FontFamily;
|
||||
text: string;
|
||||
baseline: number;
|
||||
textAlign: TextAlign;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
type CANVAS_ERROR_NAMES = "CANVAS_ERROR" | "CANVAS_POSSIBLY_TOO_BIG";
|
||||
|
||||
export class CanvasError extends Error {
|
||||
constructor(
|
||||
message: string = "Couldn't export canvas.",
|
||||
@@ -10,11 +9,3 @@ export class CanvasError extends Error {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
export class AbortError extends Error {
|
||||
constructor(message: string = "Request aborted") {
|
||||
super();
|
||||
this.name = "AbortError";
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import throttle from "lodash.throttle";
|
||||
import React, { PureComponent } from "react";
|
||||
import { ExcalidrawImperativeAPI } from "../../types";
|
||||
import { ExcalidrawImperativeAPI } from "../../components/App";
|
||||
import { ErrorDialog } from "../../components/ErrorDialog";
|
||||
import { APP_NAME, ENV, EVENT } from "../../constants";
|
||||
import { ImportedDataState } from "../../data/types";
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import React from "react";
|
||||
import { Card } from "../../components/Card";
|
||||
import { ToolButton } from "../../components/ToolButton";
|
||||
import { serializeAsJSON } from "../../data/json";
|
||||
import { getImportedKey, createIV, generateEncryptionKey } from "../data";
|
||||
import { loadFirebaseStorage } from "../data/firebase";
|
||||
import { NonDeletedExcalidrawElement } from "../../element/types";
|
||||
import { AppState } from "../../types";
|
||||
import { nanoid } from "nanoid";
|
||||
import { t } from "../../i18n";
|
||||
import { excalidrawPlusIcon } from "./icons";
|
||||
|
||||
const encryptData = async (
|
||||
key: string,
|
||||
json: string,
|
||||
): Promise<{ blob: Blob; iv: Uint8Array }> => {
|
||||
const importedKey = await getImportedKey(key, "encrypt");
|
||||
const iv = createIV();
|
||||
const encoded = new TextEncoder().encode(json);
|
||||
const ciphertext = await window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
iv,
|
||||
},
|
||||
importedKey,
|
||||
encoded,
|
||||
);
|
||||
|
||||
return { blob: new Blob([new Uint8Array(ciphertext)]), iv };
|
||||
};
|
||||
|
||||
const exportToExcalidrawPlus = async (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
appState: AppState,
|
||||
) => {
|
||||
const firebase = await loadFirebaseStorage();
|
||||
|
||||
const id = `${nanoid(12)}`;
|
||||
|
||||
const key = (await generateEncryptionKey())!;
|
||||
const encryptedData = await encryptData(
|
||||
key,
|
||||
serializeAsJSON(elements, appState),
|
||||
);
|
||||
|
||||
const blob = new Blob([encryptedData.iv, encryptedData.blob], {
|
||||
type: "application/octet-stream",
|
||||
});
|
||||
|
||||
await firebase
|
||||
.storage()
|
||||
.ref(`/migrations/scenes/${id}`)
|
||||
.put(blob, {
|
||||
customMetadata: {
|
||||
data: JSON.stringify({ version: 1, name: appState.name }),
|
||||
created: Date.now().toString(),
|
||||
},
|
||||
});
|
||||
|
||||
window.open(`https://plus.excalidraw.com/import?excalidraw=${id},${key}`);
|
||||
};
|
||||
|
||||
export const ExportToExcalidrawPlus: React.FC<{
|
||||
elements: readonly NonDeletedExcalidrawElement[];
|
||||
appState: AppState;
|
||||
onError: (error: Error) => void;
|
||||
}> = ({ elements, appState, onError }) => {
|
||||
return (
|
||||
<Card color="indigo">
|
||||
<div className="Card-icon">{excalidrawPlusIcon}</div>
|
||||
<h2>Excalidraw+</h2>
|
||||
<div className="Card-details">
|
||||
{t("exportDialog.excalidrawplus_description")}
|
||||
</div>
|
||||
<ToolButton
|
||||
className="Card-button"
|
||||
type="button"
|
||||
title={t("exportDialog.excalidrawplus_button")}
|
||||
aria-label={t("exportDialog.excalidrawplus_button")}
|
||||
showAriaLabel={true}
|
||||
onClick={async () => {
|
||||
try {
|
||||
await exportToExcalidrawPlus(elements, appState);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
onError(new Error(t("exportDialog.excalidrawplus_exportError")));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -5,19 +5,15 @@ import { getSceneVersion } from "../../element";
|
||||
import Portal from "../collab/Portal";
|
||||
import { restoreElements } from "../../data/restore";
|
||||
|
||||
// private
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
let firebasePromise: Promise<
|
||||
typeof import("firebase/app").default
|
||||
> | null = null;
|
||||
let firestorePromise: Promise<any> | null = null;
|
||||
let firebseStoragePromise: Promise<any> | null = null;
|
||||
|
||||
const _loadFirebase = async () => {
|
||||
const loadFirebase = async () => {
|
||||
const firebase = (
|
||||
await import(/* webpackChunkName: "firebase" */ "firebase/app")
|
||||
).default;
|
||||
await import(/* webpackChunkName: "firestore" */ "firebase/firestore");
|
||||
|
||||
const firebaseConfig = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
@@ -25,37 +21,13 @@ const _loadFirebase = async () => {
|
||||
return firebase;
|
||||
};
|
||||
|
||||
const _getFirebase = async (): Promise<
|
||||
const getFirebase = async (): Promise<
|
||||
typeof import("firebase/app").default
|
||||
> => {
|
||||
if (!firebasePromise) {
|
||||
firebasePromise = _loadFirebase();
|
||||
firebasePromise = loadFirebase();
|
||||
}
|
||||
return firebasePromise;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const loadFirestore = async () => {
|
||||
const firebase = await _getFirebase();
|
||||
if (!firestorePromise) {
|
||||
firestorePromise = import(
|
||||
/* webpackChunkName: "firestore" */ "firebase/firestore"
|
||||
);
|
||||
await firestorePromise;
|
||||
}
|
||||
return firebase;
|
||||
};
|
||||
|
||||
export const loadFirebaseStorage = async () => {
|
||||
const firebase = await _getFirebase();
|
||||
if (!firebseStoragePromise) {
|
||||
firebseStoragePromise = import(
|
||||
/* webpackChunkName: "storage" */ "firebase/storage"
|
||||
);
|
||||
await firebseStoragePromise;
|
||||
}
|
||||
return firebase;
|
||||
return await firebasePromise!;
|
||||
};
|
||||
|
||||
interface FirebaseStoredScene {
|
||||
@@ -136,7 +108,7 @@ export const saveToFirebase = async (
|
||||
return true;
|
||||
}
|
||||
|
||||
const firebase = await loadFirestore();
|
||||
const firebase = await getFirebase();
|
||||
const sceneVersion = getSceneVersion(elements);
|
||||
const { ciphertext, iv } = await encryptElements(roomKey, elements);
|
||||
|
||||
@@ -178,7 +150,7 @@ export const loadFromFirebase = async (
|
||||
roomKey: string,
|
||||
socket: SocketIOClient.Socket | null,
|
||||
): Promise<readonly ExcalidrawElement[] | null> => {
|
||||
const firebase = await loadFirestore();
|
||||
const firebase = await getFirebase();
|
||||
const db = firebase.firestore();
|
||||
|
||||
const docRef = db.collection("scenes").doc(roomId);
|
||||
|
||||
@@ -17,7 +17,7 @@ const generateRandomID = async () => {
|
||||
return Array.from(arr, byteToHex).join("");
|
||||
};
|
||||
|
||||
export const generateEncryptionKey = async () => {
|
||||
const generateEncryptionKey = async () => {
|
||||
const key = await window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
@@ -176,7 +176,7 @@ export const getImportedKey = (key: string, usage: KeyUsage) =>
|
||||
[usage],
|
||||
);
|
||||
|
||||
export const decryptImported = async (
|
||||
const decryptImported = async (
|
||||
iv: ArrayBuffer,
|
||||
encrypted: ArrayBuffer,
|
||||
privateKey: string,
|
||||
|
||||
@@ -8,6 +8,7 @@ import React, {
|
||||
} from "react";
|
||||
import { trackEvent } from "../analytics";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { ExcalidrawImperativeAPI } from "../components/App";
|
||||
import { ErrorDialog } from "../components/ErrorDialog";
|
||||
import { TopErrorBoundary } from "../components/TopErrorBoundary";
|
||||
import {
|
||||
@@ -30,7 +31,7 @@ import Excalidraw, {
|
||||
defaultLang,
|
||||
languages,
|
||||
} from "../packages/excalidraw/index";
|
||||
import { AppState, LibraryItems, ExcalidrawImperativeAPI } from "../types";
|
||||
import { AppState, LibraryItems } from "../types";
|
||||
import {
|
||||
debounce,
|
||||
getVersion,
|
||||
@@ -55,7 +56,6 @@ import { Tooltip } from "../components/Tooltip";
|
||||
import { shield } from "../components/icons";
|
||||
|
||||
import "./index.scss";
|
||||
import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus";
|
||||
|
||||
const languageDetector = new LanguageDetector();
|
||||
languageDetector.init({
|
||||
@@ -428,21 +428,6 @@ const ExcalidrawWrapper = () => {
|
||||
canvasActions: {
|
||||
export: {
|
||||
onExportToBackend,
|
||||
renderCustomUI: (elements, appState) => {
|
||||
return (
|
||||
<ExportToExcalidrawPlus
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
onError={(error) => {
|
||||
excalidrawAPI?.updateScene({
|
||||
appState: {
|
||||
errorMessage: error.message,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -453,7 +438,6 @@ const ExcalidrawWrapper = () => {
|
||||
detectScroll={false}
|
||||
handleKeyboardGlobally={true}
|
||||
onLibraryChange={onLibraryChange}
|
||||
autoFocus={true}
|
||||
/>
|
||||
{excalidrawAPI && <CollabWrapper excalidrawAPI={excalidrawAPI} />}
|
||||
{errorMessage && (
|
||||
|
||||
@@ -69,6 +69,7 @@ const canvas = exportToCanvas(
|
||||
{
|
||||
exportBackground: true,
|
||||
viewBackgroundColor: "#ffffff",
|
||||
scale: 1,
|
||||
},
|
||||
createCanvas,
|
||||
);
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "نمط العرض",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "مشاركة",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "غير النمط"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "إحفظ لملف",
|
||||
"link_title": "رابط قابل للمشاركة",
|
||||
"link_details": "صدر الملف للمشاهدة فقط.",
|
||||
"link_button": "التصدير كرابط",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": "التصدير كرابط"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "اقرأ مدونتنا",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Изглед",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Прочетете нашия блог",
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"background": "Color del fons",
|
||||
"fill": "Estil del fons",
|
||||
"strokeWidth": "Amplada del traç",
|
||||
"strokeShape": "Estil del traç",
|
||||
"strokeShape_gel": "Bolígraf de gel",
|
||||
"strokeShape": "",
|
||||
"strokeShape_gel": "",
|
||||
"strokeShape_fountain": "",
|
||||
"strokeShape_brush": "",
|
||||
"strokeStyle": "Estil del traç",
|
||||
@@ -42,7 +42,7 @@
|
||||
"fontSize": "Mida de lletra",
|
||||
"fontFamily": "Tipus de lletra",
|
||||
"onlySelected": "Només seleccionats",
|
||||
"withBackground": "Fons",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "",
|
||||
"exportEmbedScene_details": "Les dades de l’escena es desaran al fitxer PNG/SVG de manera que es pugui restaurar l’escena.\nAugmentarà la mida del fitxer exportat.",
|
||||
"addWatermark": "Afegir \"Fet amb Excalidraw\"",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "Mode de visualització",
|
||||
"toggleExportColorScheme": "Canvia l'esquema de colors de l'exportació",
|
||||
"share": "Compartir",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Netejar el llenç",
|
||||
"exportJSON": "Exporta a un fitxer",
|
||||
"exportImage": "Desa com a imatge",
|
||||
"exportJSON": "",
|
||||
"exportImage": "",
|
||||
"export": "Exportar",
|
||||
"exportToPng": "Exportar a PNG",
|
||||
"exportToSvg": "Exportar a SNG",
|
||||
"copyToClipboard": "Copiar al porta-retalls",
|
||||
"copyPngToClipboard": "Copiar PNG al porta-retalls",
|
||||
"scale": "Escala",
|
||||
"save": "Desa al fitxer actual",
|
||||
"save": "",
|
||||
"saveAs": "Desar com",
|
||||
"load": "Carregar",
|
||||
"getShareableLink": "Obtenir enllaç per compartir",
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "Error"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "Desa la disc",
|
||||
"disk_title": "",
|
||||
"disk_details": "",
|
||||
"disk_button": "Desa en un fitxer",
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "Exporta",
|
||||
"excalidrawplus_exportError": "No és possible exportar a Excalidraw+ ara mateix..."
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Llegiu el nostre blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Náhled",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "Sdílet",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "Přepnout tmavý řežim"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Ansichtsmodus",
|
||||
"toggleExportColorScheme": "Exportfarbschema umschalten",
|
||||
"share": "Teilen",
|
||||
"showStroke": "Auswahl für Strichfarbe anzeigen",
|
||||
"showBackground": "Auswahl für Hintergrundfarbe anzeigen",
|
||||
"toggleTheme": "Design umschalten"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "In Datei speichern",
|
||||
"link_title": "Teilbarer Link",
|
||||
"link_details": "Als schreibgeschützten Link exportieren.",
|
||||
"link_button": "Als Link exportieren",
|
||||
"excalidrawplus_description": "Speichere die Szene in deinem Excalidraw+ Arbeitsbereich.",
|
||||
"excalidrawplus_button": "Exportieren",
|
||||
"excalidrawplus_exportError": "Konnte nicht nach Excalidraw+ exportieren..."
|
||||
"link_button": "Als Link exportieren"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Lies unseren Blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Λειτουργία προβολής",
|
||||
"toggleExportColorScheme": "Εναλλαγή εξαγωγής θέματος χρωμάτων",
|
||||
"share": "Κοινοποίηση",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Διαβάστε το Blog μας",
|
||||
|
||||
@@ -180,8 +180,6 @@
|
||||
"linearElement": "Click to start multiple points, drag for single line",
|
||||
"freeDraw": "Click and drag, release when you're finished",
|
||||
"text": "Tip: you can also add text by double-clicking anywhere with the selection tool",
|
||||
"text_selected": "Double-click or press ENTER to edit text",
|
||||
"text_editing": "Press Escape or CtrlOrCmd+ENTER to finish editing",
|
||||
"linearElementMulti": "Click on last point or press Escape or Enter to finish",
|
||||
"lockAngle": "You can constrain angle by holding SHIFT",
|
||||
"resize": "You can constrain proportions by holding SHIFT while resizing,\nhold ALT to resize from the center",
|
||||
@@ -227,10 +225,7 @@
|
||||
"disk_button": "Save to file",
|
||||
"link_title": "Shareable link",
|
||||
"link_details": "Export as a read-only link.",
|
||||
"link_button": "Export to Link",
|
||||
"excalidrawplus_description": "Save the scene to your Excalidraw+ workspace.",
|
||||
"excalidrawplus_button": "Export",
|
||||
"excalidrawplus_exportError": "Couldn't export to Excalidraw+ at this moment..."
|
||||
"link_button": "Export to Link"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Read our blog",
|
||||
@@ -238,18 +233,16 @@
|
||||
"curvedArrow": "Curved arrow",
|
||||
"curvedLine": "Curved line",
|
||||
"documentation": "Documentation",
|
||||
"doubleClick": "double-click",
|
||||
"drag": "drag",
|
||||
"editor": "Editor",
|
||||
"editSelectedShape": "Edit selected shape (text/arrow/line)",
|
||||
"github": "Found an issue? Submit",
|
||||
"howto": "Follow our guides",
|
||||
"or": "or",
|
||||
"preventBinding": "Prevent arrow binding",
|
||||
"shapes": "Shapes",
|
||||
"shortcuts": "Keyboard shortcuts",
|
||||
"textFinish": "Finish editing (text editor)",
|
||||
"textNewLine": "Add new line (text editor)",
|
||||
"textFinish": "Finish editing (text)",
|
||||
"textNewLine": "Add new line (text)",
|
||||
"title": "Help",
|
||||
"view": "View",
|
||||
"zoomToFit": "Zoom to fit all elements",
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
"fontSize": "Tamaño de la fuente",
|
||||
"fontFamily": "Tipo de fuente",
|
||||
"onlySelected": "Sólo seleccionados",
|
||||
"withBackground": "Fondo",
|
||||
"exportEmbedScene": "Embeber escena",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "",
|
||||
"exportEmbedScene_details": "Los datos de escena se guardarán en el archivo PNG/SVG exportado, así la escena puede ser restaurada de la misma.\nEsto aumentará el tamaño del archivo exportado.",
|
||||
"addWatermark": "Agregar \"Hecho con Excalidraw\"",
|
||||
"handDrawn": "Dibujado a mano",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "Modo presentación",
|
||||
"toggleExportColorScheme": "Cambiar el esquema de colores de exportación",
|
||||
"share": "Compartir",
|
||||
"showStroke": "Mostrar el selector de color del trazo",
|
||||
"showBackground": "Mostrar el selector de color de fondo",
|
||||
"toggleTheme": "Alternar tema"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Limpiar lienzo y reiniciar el color de fondo",
|
||||
"exportJSON": "Exportar como archivo",
|
||||
"exportImage": "Guardar como imagen",
|
||||
"exportJSON": "",
|
||||
"exportImage": "",
|
||||
"export": "Exportar",
|
||||
"exportToPng": "Exportar a PNG",
|
||||
"exportToSvg": "Exportar a SVG",
|
||||
"copyToClipboard": "Copiar al portapapeles",
|
||||
"copyPngToClipboard": "Copiar PNG al portapapeles",
|
||||
"scale": "Escalar",
|
||||
"save": "Guardal al archivo actual",
|
||||
"save": "",
|
||||
"saveAs": "Guardar como",
|
||||
"load": "Cargar",
|
||||
"getShareableLink": "Obtener enlace para compartir",
|
||||
@@ -124,7 +122,7 @@
|
||||
"scrollBackToContent": "Volver al contenido",
|
||||
"zoomIn": "Acercarse",
|
||||
"zoomOut": "Alejarse",
|
||||
"resetZoom": "Restablecer zoom",
|
||||
"resetZoom": "Restablecer acercamiento",
|
||||
"menu": "Menú",
|
||||
"done": "Hecho",
|
||||
"edit": "Editar",
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "Error"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "Guardar en el disco",
|
||||
"disk_details": "Exportar los datos de la escena a un archivo desde el cual se puede importar más tarde.",
|
||||
"disk_button": "Guardar en el archivo",
|
||||
"link_title": "Enlace para compartir",
|
||||
"link_details": "Exportar como enlace de sólo lectura.",
|
||||
"link_button": "Exportar al link",
|
||||
"excalidrawplus_description": "Guarda la escena en tu espacio de trabajo de Excalidraw+.",
|
||||
"excalidrawplus_button": "Exportar",
|
||||
"excalidrawplus_exportError": "No se pudo exportar a Excalidraw+ en este momento..."
|
||||
"disk_title": "",
|
||||
"disk_details": "",
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Lee nuestro blog",
|
||||
@@ -253,7 +248,7 @@
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Tus dibujos están cifrados de punto a punto, por lo que los servidores de Excalidraw nunca los verán.",
|
||||
"link": "Entrada en el blog sobre cifrado de extremo a extremo"
|
||||
"link": ""
|
||||
},
|
||||
"stats": {
|
||||
"angle": "Ángulo",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "بلاگ ما را بخوانید",
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
"fontSize": "Kirjasinkoko",
|
||||
"fontFamily": "Kirjasintyyppi",
|
||||
"onlySelected": "Vain valitut",
|
||||
"withBackground": "Taustalla",
|
||||
"exportEmbedScene": "Upota työ",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "",
|
||||
"exportEmbedScene_details": "Teoksen tiedot tallennetaan PNG/SVG-tiedostoon, jolloin teoksen voi palauttaa siitä. Kasvattaa tallennetun tiedoston kokoa.",
|
||||
"addWatermark": "Lisää \"Tehty Excalidrawilla\"",
|
||||
"handDrawn": "Käsinkirjoitettu",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "Katselutila",
|
||||
"toggleExportColorScheme": "Vaihda viennin väriteema",
|
||||
"share": "Jaa",
|
||||
"showStroke": "Näytä viivan värin valitsin",
|
||||
"showBackground": "Näytä taustavärin valitsin",
|
||||
"toggleTheme": "Vaihda teema"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Tyhjennä piirtoalue",
|
||||
"exportJSON": "Vie tiedostoon",
|
||||
"exportImage": "Tallenna kuvana",
|
||||
"exportJSON": "",
|
||||
"exportImage": "",
|
||||
"export": "Vie",
|
||||
"exportToPng": "Vie PNG-tiedostona",
|
||||
"exportToSvg": "Vie SVG-tiedostona",
|
||||
"copyToClipboard": "Kopioi leikepöydälle",
|
||||
"copyPngToClipboard": "Kopioi PNG-tiedosto leikepöydälle",
|
||||
"scale": "Koko",
|
||||
"save": "Tallenna nykyiseen tiedostoon",
|
||||
"save": "",
|
||||
"saveAs": "Tallenna nimellä",
|
||||
"load": "Avaa",
|
||||
"getShareableLink": "Hae jaettava linkki",
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "Virhe"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "Tallenna levylle",
|
||||
"disk_details": "Vie työn tiedot tiedostoon, josta sen voi tuoda myöhemmin.",
|
||||
"disk_button": "Tallenna tiedostoon",
|
||||
"link_title": "Jaettava linkki",
|
||||
"link_details": "Vie vain luku -linkkinä.",
|
||||
"link_button": "Vie linkkinä",
|
||||
"excalidrawplus_description": "Tallenna teos Excalidraw+ tilaan.",
|
||||
"excalidrawplus_button": "Vie",
|
||||
"excalidrawplus_exportError": "Ei voitu viedä Excalidraw+-palveluun tällä hetkellä..."
|
||||
"disk_title": "",
|
||||
"disk_details": "",
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Lue blogiamme",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"delete": "Supprimer",
|
||||
"copyStyles": "Copier les styles",
|
||||
"pasteStyles": "Coller les styles",
|
||||
"stroke": "Trait",
|
||||
"stroke": "Contour",
|
||||
"background": "Arrière-plan",
|
||||
"fill": "Remplissage",
|
||||
"strokeWidth": "Largeur du trait",
|
||||
@@ -43,7 +43,7 @@
|
||||
"fontFamily": "Police",
|
||||
"onlySelected": "Uniquement la sélection",
|
||||
"withBackground": "Arrière-plan",
|
||||
"exportEmbedScene": "Intégrer la scène",
|
||||
"exportEmbedScene": "Scène intégrée",
|
||||
"exportEmbedScene_details": "Les données de scène seront enregistrées dans le fichier PNG/SVG exporté, afin que la scène puisse être restaurée à partir de celui-ci.\nCela augmentera la taille du fichier exporté.",
|
||||
"addWatermark": "Ajouter \"Fait avec Excalidraw\"",
|
||||
"handDrawn": "À main levée",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "Mode présentation",
|
||||
"toggleExportColorScheme": "Activer/Désactiver l'export du thème de couleur",
|
||||
"share": "Partager",
|
||||
"showStroke": "Afficher le sélecteur de couleur de trait",
|
||||
"showBackground": "Afficher le sélecteur de couleur d'arrière-plan",
|
||||
"toggleTheme": "Changer le thème"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Réinitialiser le canevas",
|
||||
"exportJSON": "Exporter comme fichier",
|
||||
"exportJSON": "Exporter dans un fichier",
|
||||
"exportImage": "Enregistrer comme image",
|
||||
"export": "Exporter",
|
||||
"exportToPng": "Enregistrer en PNG",
|
||||
"exportToSvg": "Enregistrer en SVG",
|
||||
"exportToPng": "Exporter en PNG",
|
||||
"exportToSvg": "Exporter en SVG",
|
||||
"copyToClipboard": "Copier dans le presse-papier",
|
||||
"copyPngToClipboard": "Copier le PNG dans le presse-papier",
|
||||
"copyPngToClipboard": "Copier le PNG vers le presse-papier",
|
||||
"scale": "Échelle",
|
||||
"save": "Enregistrer dans le fichier actuel",
|
||||
"save": "Sauvegarder dans le fichier actuel",
|
||||
"saveAs": "Enregistrer sous",
|
||||
"load": "Ouvrir",
|
||||
"getShareableLink": "Obtenir un lien de partage",
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "Erreur"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "Enregistrer sur le disque",
|
||||
"disk_details": "Exporter les données de la scène comme un fichier que vous pourrez importer ultérieurement.",
|
||||
"disk_button": "Enregistrer comme fichier",
|
||||
"link_title": "Lien partageable",
|
||||
"disk_title": "Sauvegarder sur le disque",
|
||||
"disk_details": "Exportez les données de la scène dans un fichier que vous pourrez importer ultérieurement.",
|
||||
"disk_button": "Sauvegarder dans un fichier",
|
||||
"link_title": "Lien à partager",
|
||||
"link_details": "Exporter comme un lien en lecture seule.",
|
||||
"link_button": "Exporter comme lien",
|
||||
"excalidrawplus_description": "Enregistrer la scène dans votre espace de travail Excalidraw+.",
|
||||
"excalidrawplus_button": "Exporter",
|
||||
"excalidrawplus_exportError": "Impossible d'exporter vers Excalidraw+ pour le moment..."
|
||||
"link_button": "Exporter vers un lien"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Lire notre blog",
|
||||
@@ -272,8 +267,8 @@
|
||||
},
|
||||
"toast": {
|
||||
"copyStyles": "Styles copiés.",
|
||||
"copyToClipboard": "Copié dans le presse-papier.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copié dans le presse-papier en PNG\n({{exportColorScheme}})",
|
||||
"copyToClipboard": "Copié vers le presse-papiers.",
|
||||
"copyToClipboardAsPng": "{{exportSelection}} copié dans le presse-papiers en PNG\n({{exportColorScheme}})",
|
||||
"fileSaved": "Fichier enregistré.",
|
||||
"fileSavedToFilename": "Enregistré sous {filename}",
|
||||
"canvas": "canevas",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "מצב תצוגה",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "קרא את הבלוג שלנו",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "हमारा ब्लॉग पढे",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Mode tampilan",
|
||||
"toggleExportColorScheme": "Ubah skema warna ekspor",
|
||||
"share": "Bagikan",
|
||||
"showStroke": "Tampilkan garis pengambil warna",
|
||||
"showBackground": "Tampilkan latar pengambil warna",
|
||||
"toggleTheme": "Ubah tema"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Simpan ke file",
|
||||
"link_title": "Tautan",
|
||||
"link_details": "Ekspor sebagai tautan yang hanya dibaca.",
|
||||
"link_button": "Ekspor ke tautan",
|
||||
"excalidrawplus_description": "Simpan pemandangan ke ruang kerja Excalidraw+ Anda.",
|
||||
"excalidrawplus_button": "Ekspor",
|
||||
"excalidrawplus_exportError": "Tidak dapat ekspor ke Excalidraw+ saat ini..."
|
||||
"link_button": "Ekspor ke tautan"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Baca blog kami",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Modalità visualizzazione",
|
||||
"toggleExportColorScheme": "Cambia lo schema di colori in esportazione",
|
||||
"share": "Condividi",
|
||||
"showStroke": "Mostra selettore colore del tratto",
|
||||
"showBackground": "Mostra selettore colore di sfondo",
|
||||
"toggleTheme": "Cambia tema"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Salva su file",
|
||||
"link_title": "Link condivisibile",
|
||||
"link_details": "Esporta come link di sola lettura.",
|
||||
"link_button": "Esporta come Link",
|
||||
"excalidrawplus_description": "Salva la scena nel tuo spazio di lavoro Excalidraw+.",
|
||||
"excalidrawplus_button": "Esporta",
|
||||
"excalidrawplus_exportError": "Non è stato possibile esportare su Excalidraw+ al questo momento..."
|
||||
"link_button": "Esporta come Link"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Leggi il nostro blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "閲覧モード",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "共有",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "テーマの切り替え"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "ファイルへ保存",
|
||||
"link_title": "共有可能なリンク",
|
||||
"link_details": "読み取り専用リンクとしてエクスポート",
|
||||
"link_button": "リンクとしてエクスポート",
|
||||
"excalidrawplus_description": "Excalidraw+ ワークスペースにシーンを保存します。",
|
||||
"excalidrawplus_button": "エクスポート",
|
||||
"excalidrawplus_exportError": "Excalidraw+ にエクスポートできませんでした..."
|
||||
"link_button": "リンクとしてエクスポート"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "公式ブログを読む",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"background": "Agilal",
|
||||
"fill": "Taččart",
|
||||
"strokeWidth": "Tehri n yizirig",
|
||||
"strokeShape": "Talɣa n yizirig",
|
||||
"strokeShape": "",
|
||||
"strokeShape_gel": "",
|
||||
"strokeShape_fountain": "",
|
||||
"strokeShape_brush": "Amfezzu",
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Askar n tmuɣli",
|
||||
"toggleExportColorScheme": "Sermed/sens asifeḍ usentel n yini",
|
||||
"share": "Bḍu",
|
||||
"showStroke": "Beqqeḍ amelqaḍ n yini n yizirig",
|
||||
"showBackground": "Beqqeḍ amelqaḍ n yini n ugilal",
|
||||
"toggleTheme": "Snifel asentel"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Sekles deg ufaylu",
|
||||
"link_title": "Aseɣwen n beṭṭu",
|
||||
"link_details": "Sifeḍ am useɣwen n tɣuri kan.",
|
||||
"link_button": "Sifeḍ deg useɣwen",
|
||||
"excalidrawplus_description": "Sekles asayes-inek•inem di tallunt n umahil Excalidraw+.",
|
||||
"excalidrawplus_button": "Sifeḍ",
|
||||
"excalidrawplus_exportError": "Ulamek asifeḍ ɣer Excalidraw+ akka tura..."
|
||||
"link_button": "Sifeḍ deg useɣwen"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Ɣeṛ ablug-nneɣ",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "보기 모드",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "블로그 읽어보기",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Visningsmodus",
|
||||
"toggleExportColorScheme": "Veksle eksport av fargepalett",
|
||||
"share": "Del",
|
||||
"showStroke": "Vis fargevelger for kantfarge",
|
||||
"showBackground": "Vis fargevelger for bakgrunnsfarge",
|
||||
"toggleTheme": "Veksle tema"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Lagre til fil",
|
||||
"link_title": "Delbar lenke",
|
||||
"link_details": "Eksporter som en skrivebeskyttet lenke.",
|
||||
"link_button": "Eksporter til lenke",
|
||||
"excalidrawplus_description": "Lagre scenen til ditt Excalidraw+ arbeidsområde.",
|
||||
"excalidrawplus_button": "Eksporter",
|
||||
"excalidrawplus_exportError": "Kunne ikke eksportere til Excalidraw+ for øyeblikket..."
|
||||
"link_button": "Eksporter til lenke"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Les bloggen vår",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Weergavemodus",
|
||||
"toggleExportColorScheme": "Kleurenschema exporteren aan/uit",
|
||||
"share": "Deel",
|
||||
"showStroke": "Toon lijn kleur kiezer",
|
||||
"showBackground": "Toon achtergrondkleur kiezer",
|
||||
"toggleTheme": "Thema aan/uit"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Opslaan naar bestand",
|
||||
"link_title": "Deelbare link",
|
||||
"link_details": "Exporteren als een alleen-lezen link.",
|
||||
"link_button": "Exporteer naar link",
|
||||
"excalidrawplus_description": "Sla de scène op in je Excalidraw+ werkruimte.",
|
||||
"excalidrawplus_button": "Exporteren",
|
||||
"excalidrawplus_exportError": "Kan op dit moment niet exporteren naar Excalidraw+..."
|
||||
"link_button": "Exporteer naar link"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Lees onze blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Visningsmodus",
|
||||
"toggleExportColorScheme": "Veksle eksport av fargepalett",
|
||||
"share": "Del",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Les bloggen vår",
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
"fontSize": "Talha poliça",
|
||||
"fontFamily": "Familha de poliça",
|
||||
"onlySelected": "Seleccion sonque",
|
||||
"withBackground": "Rèireplan",
|
||||
"exportEmbedScene": "Scèna embarcada",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "",
|
||||
"exportEmbedScene_details": "Las donadas de scèna seràn enregistradas dins lo fichièr PNG/SVG exportat, per que la scèna pòsca èsser restaurada a partir d’aqueste fichièr.\nAumentarà la talha del fichièr exportat.",
|
||||
"addWatermark": "Apondre « Fabricat amb Excalidraw »",
|
||||
"handDrawn": "A la man levada",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "Mòde de vista",
|
||||
"toggleExportColorScheme": "Alternar l’esquèma de color d’expòrt",
|
||||
"share": "Partejar",
|
||||
"showStroke": "Mostrar lo selector de color de contorn",
|
||||
"showBackground": "Mostrar lo selector de color de fons",
|
||||
"toggleTheme": "Alternar tèma"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Reïnicializar lo canabàs",
|
||||
"exportJSON": "Exportar en fichièr",
|
||||
"exportImage": "Salvar coma imatge",
|
||||
"exportJSON": "",
|
||||
"exportImage": "",
|
||||
"export": "Exportar",
|
||||
"exportToPng": "Exportar en PNG",
|
||||
"exportToSvg": "Exportar en SVG",
|
||||
"copyToClipboard": "Copiar al quichapapièrs",
|
||||
"copyPngToClipboard": "Copiar PNG al quichapapièrs",
|
||||
"scale": "Escala",
|
||||
"save": "Salvar al fichièr actual",
|
||||
"save": "",
|
||||
"saveAs": "Enregistrar jos",
|
||||
"load": "Cargar",
|
||||
"getShareableLink": "Obténer lo ligam de partatge",
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "Error"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "Salvar al disc",
|
||||
"disk_details": "Exportar las donadas de la scèna cap a un fichièr que podètz importar mai tard.",
|
||||
"disk_button": "Salvar al fichièr",
|
||||
"link_title": "Ligam de partejar",
|
||||
"link_details": "Exportar coma un ligam de lectura sola.",
|
||||
"link_button": "Exportar en ligam",
|
||||
"excalidrawplus_description": "Enregistrar la scèna dins vòstre espaci de trabalh Excalidraw+.",
|
||||
"excalidrawplus_button": "Exportar",
|
||||
"excalidrawplus_exportError": "Export impossibla cap a Excalidraw+ pel moment..."
|
||||
"disk_title": "",
|
||||
"disk_details": "",
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Legir nòstre blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "ਦੇਖੋ ਮੋਡ",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "ਸਾਂਝਾ ਕਰੋ",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "ਥੀਮ ਬਦਲੋ"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "ਸਾਡਾ ਬਲੌਗ ਪੜ੍ਹੋ",
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
{
|
||||
"ar-SA": 92,
|
||||
"bg-BG": 83,
|
||||
"ca-ES": 94,
|
||||
"ar-SA": 94,
|
||||
"bg-BG": 85,
|
||||
"ca-ES": 92,
|
||||
"cs-CZ": 36,
|
||||
"de-DE": 100,
|
||||
"el-GR": 88,
|
||||
"el-GR": 90,
|
||||
"en": 100,
|
||||
"es-ES": 98,
|
||||
"fa-IR": 79,
|
||||
"fi-FI": 99,
|
||||
"es-ES": 93,
|
||||
"fa-IR": 81,
|
||||
"fi-FI": 94,
|
||||
"fr-FR": 100,
|
||||
"he-IL": 80,
|
||||
"hi-IN": 82,
|
||||
"hu-HU": 73,
|
||||
"he-IL": 82,
|
||||
"hi-IN": 84,
|
||||
"hu-HU": 74,
|
||||
"id-ID": 100,
|
||||
"it-IT": 99,
|
||||
"ja-JP": 98,
|
||||
"kab-KAB": 98,
|
||||
"ko-KR": 83,
|
||||
"ja-JP": 99,
|
||||
"kab-KAB": 97,
|
||||
"ko-KR": 85,
|
||||
"lv-LV": 17,
|
||||
"my-MM": 68,
|
||||
"my-MM": 69,
|
||||
"nb-NO": 100,
|
||||
"nl-NL": 100,
|
||||
"nn-NO": 90,
|
||||
"oc-FR": 100,
|
||||
"pa-IN": 89,
|
||||
"pl-PL": 85,
|
||||
"pt-BR": 90,
|
||||
"pt-PT": 92,
|
||||
"nn-NO": 92,
|
||||
"oc-FR": 95,
|
||||
"pa-IN": 91,
|
||||
"pl-PL": 87,
|
||||
"pt-BR": 92,
|
||||
"pt-PT": 94,
|
||||
"ro-RO": 100,
|
||||
"ru-RU": 97,
|
||||
"sk-SK": 100,
|
||||
"ru-RU": 95,
|
||||
"sk-SK": 95,
|
||||
"sv-SE": 100,
|
||||
"tr-TR": 91,
|
||||
"uk-UA": 97,
|
||||
"zh-CN": 98,
|
||||
"tr-TR": 93,
|
||||
"uk-UA": 100,
|
||||
"zh-CN": 94,
|
||||
"zh-TW": 99
|
||||
}
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Tryb widoku",
|
||||
"toggleExportColorScheme": "",
|
||||
"share": "",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Przeczytaj na naszym blogu",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Modo de visualização",
|
||||
"toggleExportColorScheme": "Alternar esquema de cores de exportação",
|
||||
"share": "Compartilhar",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Leia o nosso blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Modo de visualização",
|
||||
"toggleExportColorScheme": "Alternar esquema de cores de exportação",
|
||||
"share": "Partilhar",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "Alternar tema"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Leia o nosso blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Mod de vizualizare",
|
||||
"toggleExportColorScheme": "Comutare schemă de culori de export",
|
||||
"share": "Distribuie",
|
||||
"showStroke": "Afișare selector culoare contur",
|
||||
"showBackground": "Afișare selector culoare fundal",
|
||||
"toggleTheme": "Comutare temă"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Salvare în fișier",
|
||||
"link_title": "URL partajabil",
|
||||
"link_details": "Exportă ca URL doar în citire.",
|
||||
"link_button": "Exportare în URL",
|
||||
"excalidrawplus_description": "Salvează scena în spațiul de lucru Excalidraw+.",
|
||||
"excalidrawplus_button": "Exportare",
|
||||
"excalidrawplus_exportError": "Excalidraw+ nu a putut fi exportat în acest moment..."
|
||||
"link_button": "Exportare în URL"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Citește blogul nostru",
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"background": "Фон",
|
||||
"fill": "Заливка",
|
||||
"strokeWidth": "Толщина штриха",
|
||||
"strokeShape": "Стиль обводки",
|
||||
"strokeShape_gel": "Гелевая ручка",
|
||||
"strokeShape_fountain": "Фонтанная ручка",
|
||||
"strokeShape_brush": "Кисть",
|
||||
"strokeShape": "",
|
||||
"strokeShape_gel": "",
|
||||
"strokeShape_fountain": "",
|
||||
"strokeShape_brush": "",
|
||||
"strokeStyle": "Стиль обводки",
|
||||
"strokeStyle_solid": "Сплошная",
|
||||
"strokeStyle_dashed": "Пунктирная",
|
||||
@@ -96,13 +96,11 @@
|
||||
"centerHorizontally": "Центрировать по горизонтали",
|
||||
"distributeHorizontally": "Распределить по горизонтали",
|
||||
"distributeVertically": "Распределить по вертикали",
|
||||
"flipHorizontal": "Переворот по горизонтали",
|
||||
"flipVertical": "Переворот по вертикали",
|
||||
"flipHorizontal": "",
|
||||
"flipVertical": "",
|
||||
"viewMode": "Вид",
|
||||
"toggleExportColorScheme": "Экспортировать цветовую схему",
|
||||
"share": "Поделиться",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Сохранить в файл",
|
||||
"link_title": "Поделитесь ссылкой",
|
||||
"link_details": "Экспорт ссылки только для чтения.",
|
||||
"link_button": "Экспорт в ссылку",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "Экспорт",
|
||||
"excalidrawplus_exportError": "Не удалось экспортировать в Excalidraw+ на данный момент..."
|
||||
"link_button": "Экспорт в ссылку"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Прочитайте наш блог",
|
||||
@@ -253,7 +248,7 @@
|
||||
},
|
||||
"encrypted": {
|
||||
"tooltip": "Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним.",
|
||||
"link": "Запись блога о сквозном шифровании в Excalidraw"
|
||||
"link": ""
|
||||
},
|
||||
"stats": {
|
||||
"angle": "Угол",
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
"fontSize": "Veľkosť písma",
|
||||
"fontFamily": "Písmo",
|
||||
"onlySelected": "Iba vybrané",
|
||||
"withBackground": "Pozadie",
|
||||
"exportEmbedScene": "Zahrnúť scénu",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "",
|
||||
"exportEmbedScene_details": "Údaje scény budú uložené do exportovaného PNG/SVG súboru, takže scéna z neho môže byť opäť obnovená.\nBude to mať za následok zvýšenie veľkosti súboru.",
|
||||
"addWatermark": "Pridať \"Vytvorené s Excalidraw\"",
|
||||
"handDrawn": "Ručne písané",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "Režim zobrazenia",
|
||||
"toggleExportColorScheme": "Prepnúť exportovanie farebnej schémy",
|
||||
"share": "Zdieľať",
|
||||
"showStroke": "Zobraziť výber farby pre obrys",
|
||||
"showBackground": "Zobraziť výber farby pre pozadie",
|
||||
"toggleTheme": "Prepnúť tému"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "Obnoviť plátno",
|
||||
"exportJSON": "Exportovať do súboru",
|
||||
"exportImage": "Uložiť ako obrázok",
|
||||
"exportJSON": "",
|
||||
"exportImage": "",
|
||||
"export": "Exportovať",
|
||||
"exportToPng": "Exportovať do PNG",
|
||||
"exportToSvg": "Exportovať do SVG",
|
||||
"copyToClipboard": "Kopírovať do schránky",
|
||||
"copyPngToClipboard": "Kopírovať PNG do schránky",
|
||||
"scale": "Mierka",
|
||||
"save": "Uložiť do aktuálneho súboru",
|
||||
"save": "",
|
||||
"saveAs": "Uložiť ako",
|
||||
"load": "Nahrať",
|
||||
"getShareableLink": "Získať odkaz na zdieľanie",
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "Chyba"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "Uložiť na disk",
|
||||
"disk_details": "Exportovať údaje scény do súboru, z ktorého môžu byť neskôr importované.",
|
||||
"disk_button": "Uložiť do súboru",
|
||||
"link_title": "Odkaz na zdieľanie",
|
||||
"link_details": "Exportovať ako odkaz iba na čítanie.",
|
||||
"link_button": "Exportovať ako odkaz",
|
||||
"excalidrawplus_description": "Uložiť scénu do vášho Excalidraw+ pracovného priestoru.",
|
||||
"excalidrawplus_button": "Exportovať",
|
||||
"excalidrawplus_exportError": "Nepodarilo sa vykonať export do Excalidraw+..."
|
||||
"disk_title": "",
|
||||
"disk_details": "",
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Prečítajte si náš blog",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Visningsläge",
|
||||
"toggleExportColorScheme": "Växla färgschema för export",
|
||||
"share": "Dela",
|
||||
"showStroke": "Visa färgväljare för linjefärg",
|
||||
"showBackground": "Visa färgväljare för bakgrundsfärg",
|
||||
"toggleTheme": "Växla tema"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Spara till fil",
|
||||
"link_title": "Delbar länk",
|
||||
"link_details": "Exportera som en skrivskyddad länk.",
|
||||
"link_button": "Exportera till länk",
|
||||
"excalidrawplus_description": "Spara skissen till din Excalidraw+ arbetsyta.",
|
||||
"excalidrawplus_button": "Exportera",
|
||||
"excalidrawplus_exportError": "Det gick inte att exportera till Excalidraw+ just nu..."
|
||||
"link_button": "Exportera till länk"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Läs vår blogg",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Görünüm modu",
|
||||
"toggleExportColorScheme": "Renk şemasını dışa aktar/aktarma",
|
||||
"share": "Paylaş",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "Temayı etkinleştir/devre dışı bırak"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": "",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Blog'umuzu okuyun",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "Режим перегляду",
|
||||
"toggleExportColorScheme": "Переключити колірну схему експорту",
|
||||
"share": "Поділитися",
|
||||
"showStroke": "",
|
||||
"showBackground": "",
|
||||
"toggleTheme": "Перемкнути тему"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "Зберегти до файлу",
|
||||
"link_title": "Доступ за посиланням",
|
||||
"link_details": "Експортувати як посилання тільки для читання.",
|
||||
"link_button": "Експортувати у посилання",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"link_button": "Експортувати у посилання"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "Наш блог",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"background": "背景",
|
||||
"fill": "填充",
|
||||
"strokeWidth": "描边宽度",
|
||||
"strokeShape": "描边形状",
|
||||
"strokeShape": "",
|
||||
"strokeShape_gel": "中性笔",
|
||||
"strokeShape_fountain": "钢笔",
|
||||
"strokeShape_brush": "墨笔",
|
||||
@@ -42,8 +42,8 @@
|
||||
"fontSize": "字体大小",
|
||||
"fontFamily": "字体",
|
||||
"onlySelected": "仅被选中",
|
||||
"withBackground": "背景",
|
||||
"exportEmbedScene": "包含画布数据",
|
||||
"withBackground": "",
|
||||
"exportEmbedScene": "",
|
||||
"exportEmbedScene_details": "画布数据将被保存到导出的 PNG/SVG 文件,以便恢复。\n将会增加导出的文件大小。",
|
||||
"addWatermark": "添加 “使用 Excalidraw 创建” 水印",
|
||||
"handDrawn": "手写",
|
||||
@@ -101,21 +101,19 @@
|
||||
"viewMode": "查看模式",
|
||||
"toggleExportColorScheme": "切换导出配色方案",
|
||||
"share": "分享",
|
||||
"showStroke": "显示描边颜色选择器",
|
||||
"showBackground": "显示背景颜色选择器",
|
||||
"toggleTheme": "切换主题"
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "重置画布",
|
||||
"exportJSON": "导出为文件",
|
||||
"exportImage": "保存为图像",
|
||||
"exportJSON": "",
|
||||
"exportImage": "",
|
||||
"export": "导出",
|
||||
"exportToPng": "导出为 PNG",
|
||||
"exportToSvg": "导出为 SVG",
|
||||
"copyToClipboard": "复制到剪贴板",
|
||||
"copyPngToClipboard": "复制 PNG 到剪切板",
|
||||
"scale": "缩放",
|
||||
"save": "保存至当前文件",
|
||||
"save": "",
|
||||
"saveAs": "保存为",
|
||||
"load": "载入文件",
|
||||
"getShareableLink": "获取共享链接",
|
||||
@@ -166,7 +164,7 @@
|
||||
"ellipse": "椭圆",
|
||||
"arrow": "箭头",
|
||||
"line": "线条",
|
||||
"freedraw": "自由书写",
|
||||
"freedraw": "",
|
||||
"text": "文字",
|
||||
"library": "库",
|
||||
"lock": "绘制后保持所选的工具栏状态"
|
||||
@@ -220,15 +218,12 @@
|
||||
"title": "错误"
|
||||
},
|
||||
"exportDialog": {
|
||||
"disk_title": "保存到本地",
|
||||
"disk_details": "将画布数据导出为文件,以便以后导入",
|
||||
"disk_button": "保存为文件",
|
||||
"link_title": "分享链接",
|
||||
"link_details": "导出为只读链接。",
|
||||
"link_button": "导出链接",
|
||||
"excalidrawplus_description": "",
|
||||
"excalidrawplus_button": "",
|
||||
"excalidrawplus_exportError": ""
|
||||
"disk_title": "",
|
||||
"disk_details": "",
|
||||
"disk_button": "",
|
||||
"link_title": "",
|
||||
"link_details": "",
|
||||
"link_button": ""
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "浏览我们的博客",
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
"viewMode": "檢視模式",
|
||||
"toggleExportColorScheme": "切換輸出配色",
|
||||
"share": "共享",
|
||||
"showStroke": "顯示線條檢色器",
|
||||
"showBackground": "顯示背景檢色器",
|
||||
"toggleTheme": "切換主題"
|
||||
},
|
||||
"buttons": {
|
||||
@@ -225,10 +223,7 @@
|
||||
"disk_button": "儲存至檔案",
|
||||
"link_title": "可共享連結",
|
||||
"link_details": "匯出為唯讀連結",
|
||||
"link_button": "匯出為連結",
|
||||
"excalidrawplus_description": "將此場景儲存至你的 Excalidraw+ 工作區",
|
||||
"excalidrawplus_button": "輸出",
|
||||
"excalidrawplus_exportError": "目前無法輸出至 Excalidraw+"
|
||||
"link_button": "匯出為連結"
|
||||
},
|
||||
"helpDialog": {
|
||||
"blog": "閱讀部落格",
|
||||
|
||||
@@ -19,12 +19,6 @@ Please add the latest change on the top under the correct section.
|
||||
|
||||
### Features
|
||||
|
||||
- Expose [`FONT_FAMILY`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#FONT_FAMILY) so that consumer can use when passing `initialData.appState.currentItemFontFamily`.
|
||||
|
||||
- Added prop [`autoFocus`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#autoFocus) to focus the excalidraw component on page load when enabled, defaults to false [#3691](https://github.com/excalidraw/excalidraw/pull/3691).
|
||||
|
||||
Note: Earlier Excalidraw component was focussed by default on page load, you need to enable `autoFocus` prop to retain the same behaviour.
|
||||
|
||||
- Added prop `UIOptions.canvasActions.export.renderCustomUI` to support Custom UI rendering inside export dialog [#3666](https://github.com/excalidraw/excalidraw/pull/3666).
|
||||
- Added prop `UIOptions.canvasActions.saveAsImage` to show/hide the **Save as image** button in the canvas actions. Defauls to `true` hence the **Save as Image** button is rendered [#3662](https://github.com/excalidraw/excalidraw/pull/3662).
|
||||
|
||||
@@ -37,10 +31,6 @@ Please add the latest change on the top under the correct section.
|
||||
- `UIOptions.canvasActions.saveAsScene` is now renamed to `UiOptions.canvasActions.export.saveFileToDisk`. Defaults to `true` hence the **save file to disk** button is rendered inside the export dialog.
|
||||
- `exportToBackend` is now renamed to `UIOptions.canvasActions.export.exportToBackend`. If this prop is not passed, the **shareable-link** button will not be rendered, same as before.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Use excalidraw Id in elements so every element has unique id [#3696](https://github.com/excalidraw/excalidraw/pull/3696).
|
||||
|
||||
### Refactor
|
||||
|
||||
- #### BREAKING CHANGE
|
||||
|
||||
@@ -153,7 +153,7 @@ To view the full example visit :point_down:
|
||||
|
||||
</details>
|
||||
|
||||
Since Excalidraw doesn't support server side rendering yet, you should render the component once the host is mounted.
|
||||
Since Excalidraw doesn't support server side rendering yet so you will have to make sure the component is rendered once host is mounted.
|
||||
|
||||
```js
|
||||
import { useState, useEffect } from "react";
|
||||
@@ -161,7 +161,7 @@ export default function IndexPage() {
|
||||
const [Comp, setComp] = useState(null);
|
||||
useEffect(() => {
|
||||
import("@excalidraw/excalidraw").then((comp) => setComp(comp.default));
|
||||
}, []);
|
||||
});
|
||||
return <>{Comp && <Comp />}</>;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -159,7 +159,7 @@ To view the full example visit :point_down:
|
||||
|
||||
</details>
|
||||
|
||||
Since Excalidraw doesn't support server side rendering yet, you should render the component once the host is mounted.
|
||||
Since Excalidraw doesn't support server side rendering yet so you will have to make sure the component is rendered once host is mounted.
|
||||
|
||||
```js
|
||||
import { useState, useEffect } from "react";
|
||||
@@ -167,7 +167,7 @@ export default function IndexPage() {
|
||||
const [Comp, setComp] = useState(null);
|
||||
useEffect(() => {
|
||||
import("@excalidraw/excalidraw-next").then((comp) => setComp(comp.default));
|
||||
}, []);
|
||||
});
|
||||
return <>{Comp && <Comp />}</>;
|
||||
}
|
||||
```
|
||||
@@ -378,7 +378,6 @@ To view the full example visit :point_down:
|
||||
| [`detectScroll`](#detectScroll) | boolean | true | Indicates whether to update the offsets when nearest ancestor is scrolled. |
|
||||
| [`handleKeyboardGlobally`](#handleKeyboardGlobally) | boolean | false | Indicates whether to bind the keyboard events to document. |
|
||||
| [`onLibraryChange`](#onLibraryChange) | <pre>(items: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200">LibraryItems</a>) => void | Promise<any> </pre> | | The callback if supplied is triggered when the library is updated and receives the library items. |
|
||||
| [`autoFocus`](#autoFocus) | boolean | false | Implies whether to focus the Excalidraw component on page load |
|
||||
|
||||
### Dimensions of Excalidraw
|
||||
|
||||
@@ -645,10 +644,6 @@ It is invoked with empty items when user clears the library. You can use this ca
|
||||
|
||||
The unique id of the excalidraw component. This can be used to identify the excalidraw component, for example importing the library items to the excalidraw component from where it was initiated when you have multiple excalidraw components rendered on the same page as shown in [multiple excalidraw demo](https://codesandbox.io/s/multiple-excalidraw-k1xx5).
|
||||
|
||||
### autoFocus
|
||||
|
||||
This prop implies whether to focus the Excalidraw component on page load. Defaults to false.
|
||||
|
||||
### Extra API's
|
||||
|
||||
#### `getSceneVersion`
|
||||
@@ -840,21 +835,3 @@ This function returns a svg with the exported elements.
|
||||
| exportBackground | boolean | true | Indicates whether background should be exported |
|
||||
| viewBackgroundColor | string | #fff | The default background color |
|
||||
| exportWithDarkMode | boolean | false | Indicates whether to export with dark mode |
|
||||
|
||||
### FONT_FAMILY
|
||||
|
||||
**_Signature_**
|
||||
|
||||
```js
|
||||
import { FONT_FAMILY } from "./constants";
|
||||
```
|
||||
|
||||
`FONT_FAMILY` contains all the font families used in `Excalidraw` as explained below
|
||||
|
||||
| Font Family | Description |
|
||||
| ----------- | -------------------- |
|
||||
| Virgil | The handwritten font |
|
||||
| Helvetica | The Normal Font |
|
||||
| Cacadia | The Code Font |
|
||||
|
||||
Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`.
|
||||
|
||||
@@ -33,7 +33,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
detectScroll = true,
|
||||
handleKeyboardGlobally = false,
|
||||
onLibraryChange,
|
||||
autoFocus = false,
|
||||
} = props;
|
||||
|
||||
const canvasActions = props.UIOptions?.canvasActions;
|
||||
@@ -93,7 +92,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
detectScroll={detectScroll}
|
||||
handleKeyboardGlobally={handleKeyboardGlobally}
|
||||
onLibraryChange={onLibraryChange}
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</InitializeApp>
|
||||
);
|
||||
@@ -180,4 +178,3 @@ export {
|
||||
exportToSvg,
|
||||
} from "../../packages/utils";
|
||||
export { serializeAsJSON } from "../../data/json";
|
||||
export { FONT_FAMILY } from "../../constants";
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"@babel/preset-env": "7.14.2",
|
||||
"@babel/preset-react": "7.13.13",
|
||||
"@babel/preset-typescript": "7.13.0",
|
||||
"autoprefixer": "10.2.6",
|
||||
"autoprefixer": "10.2.5",
|
||||
"babel-loader": "8.2.2",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"cross-env": "7.0.3",
|
||||
@@ -66,9 +66,9 @@
|
||||
"postcss-loader": "5.3.0",
|
||||
"sass-loader": "11.1.1",
|
||||
"terser-webpack-plugin": "5.1.2",
|
||||
"ts-loader": "9.2.3",
|
||||
"typescript": "4.3.2",
|
||||
"webpack": "5.38.1",
|
||||
"ts-loader": "8.1.0",
|
||||
"typescript": "4.2.4",
|
||||
"webpack": "5.37.1",
|
||||
"webpack-bundle-analyzer": "4.4.1",
|
||||
"webpack-cli": "4.7.0"
|
||||
},
|
||||
|
||||
@@ -1240,15 +1240,15 @@ ansi-styles@^4.1.0:
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
autoprefixer@10.2.6:
|
||||
version "10.2.6"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.6.tgz#aadd9ec34e1c98d403e01950038049f0eb252949"
|
||||
integrity sha512-8lChSmdU6dCNMCQopIf4Pe5kipkAGj/fvTMslCsih0uHpOrXOPUEVOmYMMqmw3cekQkSD7EhIeuYl5y0BLdKqg==
|
||||
autoprefixer@10.2.5:
|
||||
version "10.2.5"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.5.tgz#096a0337dbc96c0873526d7fef5de4428d05382d"
|
||||
integrity sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==
|
||||
dependencies:
|
||||
browserslist "^4.16.6"
|
||||
caniuse-lite "^1.0.30001230"
|
||||
browserslist "^4.16.3"
|
||||
caniuse-lite "^1.0.30001196"
|
||||
colorette "^1.2.2"
|
||||
fraction.js "^4.1.1"
|
||||
fraction.js "^4.0.13"
|
||||
normalize-range "^0.1.2"
|
||||
postcss-value-parser "^4.1.0"
|
||||
|
||||
@@ -1404,7 +1404,7 @@ braces@^3.0.1:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.16.6:
|
||||
browserslist@^4.14.5, browserslist@^4.16.3:
|
||||
version "4.16.6"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
|
||||
integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
|
||||
@@ -1433,7 +1433,7 @@ callsites@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001230:
|
||||
caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001219:
|
||||
version "1.0.30001230"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz#8135c57459854b2240b57a4a6786044bdc5a9f71"
|
||||
integrity sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==
|
||||
@@ -1551,6 +1551,11 @@ core-js@^2.4.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
||||
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
cosmiconfig@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3"
|
||||
@@ -1635,10 +1640,19 @@ emojis-list@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
||||
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
||||
|
||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.8.0:
|
||||
version "5.8.2"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b"
|
||||
integrity sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==
|
||||
enhanced-resolve@^4.0.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec"
|
||||
integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
memory-fs "^0.5.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
enhanced-resolve@^5.8.0:
|
||||
version "5.8.0"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.0.tgz#d9deae58f9d3773b6a111a5a46831da5be5c9ac0"
|
||||
integrity sha512-Sl3KRpJA8OpprrtaIswVki3cWPiPKxXuFxJXBp+zNb6s6VwNWwFRUdtmzd2ReUut8n+sCPx7QCtQ7w5wfJhSgQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.4"
|
||||
tapable "^2.2.0"
|
||||
@@ -1648,6 +1662,13 @@ envinfo@^7.7.3:
|
||||
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.4.tgz#c6311cdd38a0e86808c1c9343f667e4267c4a320"
|
||||
integrity sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==
|
||||
|
||||
errno@^0.1.3:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
|
||||
integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
|
||||
dependencies:
|
||||
prr "~1.0.1"
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
@@ -1670,7 +1691,7 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
eslint-scope@5.1.1:
|
||||
eslint-scope@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
||||
@@ -1767,10 +1788,10 @@ find-up@^4.0.0:
|
||||
locate-path "^5.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
fraction.js@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff"
|
||||
integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==
|
||||
fraction.js@^4.0.13:
|
||||
version "4.0.13"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe"
|
||||
integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
@@ -1883,6 +1904,11 @@ indexes-of@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
||||
integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
|
||||
|
||||
inherits@~2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
interpret@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
|
||||
@@ -1924,6 +1950,11 @@ is-stream@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
|
||||
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -2068,6 +2099,14 @@ make-dir@^3.0.2, make-dir@^3.1.0:
|
||||
dependencies:
|
||||
semver "^6.0.0"
|
||||
|
||||
memory-fs@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
|
||||
integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
|
||||
dependencies:
|
||||
errno "^0.1.3"
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
@@ -2317,6 +2356,16 @@ postcss@^8.2.15:
|
||||
nanoid "^3.1.23"
|
||||
source-map-js "^0.6.2"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
prr@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
@@ -2329,6 +2378,19 @@ randombytes@^2.1.0:
|
||||
dependencies:
|
||||
safe-buffer "^5.1.0"
|
||||
|
||||
readable-stream@^2.0.1:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
rechoir@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca"
|
||||
@@ -2419,7 +2481,7 @@ safe-buffer@^5.1.0:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-buffer@~5.1.1:
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
@@ -2540,6 +2602,13 @@ source-map@~0.7.2:
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
@@ -2571,6 +2640,11 @@ supports-color@^7.0.0, supports-color@^7.1.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
tapable@^1.0.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||
|
||||
tapable@^2.1.1, tapable@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
|
||||
@@ -2619,13 +2693,14 @@ totalist@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
||||
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
|
||||
|
||||
ts-loader@9.2.3:
|
||||
version "9.2.3"
|
||||
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.3.tgz#dc3b6362a4d4382493cd4f138d345f419656de68"
|
||||
integrity sha512-sEyWiU3JMHBL55CIeC4iqJQadI0U70A5af0kvgbNLHVNz2ACztQg0j/9x10bjjIht8WfFYLKfn4L6tkZ+pu+8Q==
|
||||
ts-loader@8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.1.0.tgz#d6292487df279c7cc79b6d3b70bb9d31682b693e"
|
||||
integrity sha512-YiQipGGAFj2zBfqLhp28yUvPP9jUGqHxRzrGYuc82Z2wM27YIHbElXiaZDc93c3x0mz4zvBmS6q/DgExpdj37A==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
enhanced-resolve "^5.0.0"
|
||||
enhanced-resolve "^4.0.0"
|
||||
loader-utils "^2.0.0"
|
||||
micromatch "^4.0.0"
|
||||
semver "^7.3.4"
|
||||
|
||||
@@ -2634,10 +2709,10 @@ tslib@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
typescript@4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
|
||||
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
|
||||
typescript@4.2.4:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
|
||||
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
|
||||
|
||||
unicode-canonical-property-names-ecmascript@^1.0.4:
|
||||
version "1.0.4"
|
||||
@@ -2674,7 +2749,7 @@ uri-js@^4.2.2:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
util-deprecate@^1.0.2:
|
||||
util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
@@ -2684,10 +2759,10 @@ v8-compile-cache@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"
|
||||
integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==
|
||||
|
||||
watchpack@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce"
|
||||
integrity sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==
|
||||
watchpack@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.1.1.tgz#e99630550fca07df9f90a06056987baa40a689c7"
|
||||
integrity sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw==
|
||||
dependencies:
|
||||
glob-to-regexp "^0.4.1"
|
||||
graceful-fs "^4.1.2"
|
||||
@@ -2742,18 +2817,18 @@ webpack-sources@^1.1.0:
|
||||
source-list-map "^2.0.0"
|
||||
source-map "~0.6.1"
|
||||
|
||||
webpack-sources@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.0.tgz#9ed2de69b25143a4c18847586ad9eccb19278cfa"
|
||||
integrity sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==
|
||||
webpack-sources@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac"
|
||||
integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==
|
||||
dependencies:
|
||||
source-list-map "^2.0.1"
|
||||
source-map "^0.6.1"
|
||||
|
||||
webpack@5.38.1:
|
||||
version "5.38.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.38.1.tgz#5224c7f24c18e729268d3e3bc97240d6e880258e"
|
||||
integrity sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==
|
||||
webpack@5.37.1:
|
||||
version "5.37.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.37.1.tgz#2deb5acd350583c1ab9338471f323381b0b0c14b"
|
||||
integrity sha512-btZjGy/hSjCAAVHw+cKG+L0M+rstlyxbO2C+BOTaQ5/XAnxkDrP5sVbqWhXgo4pL3X2dcOib6rqCP20Zr9PLow==
|
||||
dependencies:
|
||||
"@types/eslint-scope" "^3.7.0"
|
||||
"@types/estree" "^0.0.47"
|
||||
@@ -2765,7 +2840,7 @@ webpack@5.38.1:
|
||||
chrome-trace-event "^1.0.2"
|
||||
enhanced-resolve "^5.8.0"
|
||||
es-module-lexer "^0.4.0"
|
||||
eslint-scope "5.1.1"
|
||||
eslint-scope "^5.1.1"
|
||||
events "^3.2.0"
|
||||
glob-to-regexp "^0.4.1"
|
||||
graceful-fs "^4.2.4"
|
||||
@@ -2776,8 +2851,8 @@ webpack@5.38.1:
|
||||
schema-utils "^3.0.0"
|
||||
tapable "^2.1.1"
|
||||
terser-webpack-plugin "^5.1.1"
|
||||
watchpack "^2.2.0"
|
||||
webpack-sources "^2.3.0"
|
||||
watchpack "^2.0.0"
|
||||
webpack-sources "^2.1.1"
|
||||
|
||||
which@^2.0.1:
|
||||
version "2.0.2"
|
||||
@@ -2792,9 +2867,9 @@ wildcard@^2.0.0:
|
||||
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
|
||||
|
||||
ws@^7.3.1:
|
||||
version "7.4.6"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
|
||||
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
|
||||
version "7.4.3"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.3.tgz#1f9643de34a543b8edb124bdcbc457ae55a6e5cd"
|
||||
integrity sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.14.3",
|
||||
"@babel/plugin-transform-arrow-functions": "7.13.0",
|
||||
"@babel/plugin-transform-async-to-generator": "7.14.5",
|
||||
"@babel/plugin-transform-async-to-generator": "7.13.0",
|
||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||
"@babel/plugin-transform-typescript": "7.14.5",
|
||||
"@babel/preset-env": "7.14.5",
|
||||
"@babel/plugin-transform-typescript": "7.14.3",
|
||||
"@babel/preset-env": "7.14.1",
|
||||
"@babel/preset-typescript": "7.13.0",
|
||||
"babel-loader": "8.2.2",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
@@ -47,8 +47,8 @@
|
||||
"css-loader": "5.2.6",
|
||||
"file-loader": "6.2.0",
|
||||
"sass-loader": "11.1.1",
|
||||
"ts-loader": "9.2.3",
|
||||
"webpack": "5.38.1",
|
||||
"ts-loader": "8.1.0",
|
||||
"webpack": "5.37.1",
|
||||
"webpack-bundle-analyzer": "4.4.2",
|
||||
"webpack-cli": "4.7.0"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ import { getCommonBounds } from "../element/bounds";
|
||||
import { renderScene, renderSceneToSvg } from "../renderer/renderScene";
|
||||
import { distance, SVG_NS } from "../utils";
|
||||
import { AppState } from "../types";
|
||||
import { DEFAULT_EXPORT_PADDING, THEME_FILTER } from "../constants";
|
||||
import { THEME_FILTER } from "../constants";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
|
||||
export const SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`;
|
||||
@@ -14,34 +14,39 @@ export const exportToCanvas = (
|
||||
appState: AppState,
|
||||
{
|
||||
exportBackground,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
exportPadding = 10,
|
||||
viewBackgroundColor,
|
||||
scale = 1,
|
||||
}: {
|
||||
exportBackground: boolean;
|
||||
exportPadding?: number;
|
||||
scale?: number;
|
||||
viewBackgroundColor: string;
|
||||
},
|
||||
createCanvas: (
|
||||
width: number,
|
||||
height: number,
|
||||
) => { canvas: HTMLCanvasElement; scale: number } = (width, height) => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = width * appState.exportScale;
|
||||
canvas.height = height * appState.exportScale;
|
||||
return { canvas, scale: appState.exportScale };
|
||||
const tempCanvas = document.createElement("canvas");
|
||||
tempCanvas.width = width * scale;
|
||||
tempCanvas.height = height * scale;
|
||||
return { canvas: tempCanvas, scale };
|
||||
},
|
||||
) => {
|
||||
const [minX, minY, width, height] = getCanvasSize(elements, exportPadding);
|
||||
|
||||
const { canvas, scale = 1 } = createCanvas(width, height);
|
||||
const { canvas: tempCanvas, scale: newScale = scale } = createCanvas(
|
||||
width,
|
||||
height,
|
||||
);
|
||||
|
||||
renderScene(
|
||||
elements,
|
||||
appState,
|
||||
null,
|
||||
scale,
|
||||
rough.canvas(canvas),
|
||||
canvas,
|
||||
newScale,
|
||||
rough.canvas(tempCanvas),
|
||||
tempCanvas,
|
||||
{
|
||||
viewBackgroundColor: exportBackground ? viewBackgroundColor : null,
|
||||
exportWithDarkMode: appState.exportWithDarkMode,
|
||||
@@ -62,22 +67,22 @@ export const exportToCanvas = (
|
||||
},
|
||||
);
|
||||
|
||||
return canvas;
|
||||
return tempCanvas;
|
||||
};
|
||||
|
||||
export const exportToSvg = (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
{
|
||||
exportBackground,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
exportPadding = 10,
|
||||
viewBackgroundColor,
|
||||
exportWithDarkMode,
|
||||
exportScale = 1,
|
||||
scale = 1,
|
||||
metadata = "",
|
||||
}: {
|
||||
exportBackground: boolean;
|
||||
exportPadding?: number;
|
||||
exportScale?: number;
|
||||
scale?: number;
|
||||
viewBackgroundColor: string;
|
||||
exportWithDarkMode?: boolean;
|
||||
metadata?: string;
|
||||
@@ -90,8 +95,8 @@ export const exportToSvg = (
|
||||
svgRoot.setAttribute("version", "1.1");
|
||||
svgRoot.setAttribute("xmlns", SVG_NS);
|
||||
svgRoot.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
||||
svgRoot.setAttribute("width", `${width * exportScale}`);
|
||||
svgRoot.setAttribute("height", `${height * exportScale}`);
|
||||
svgRoot.setAttribute("width", `${width * scale}`);
|
||||
svgRoot.setAttribute("height", `${height * scale}`);
|
||||
if (exportWithDarkMode) {
|
||||
svgRoot.setAttribute("filter", THEME_FILTER);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import "jest-canvas-mock";
|
||||
|
||||
jest.mock("nanoid", () => {
|
||||
return {
|
||||
nanoid: jest.fn(() => "test-id"),
|
||||
};
|
||||
});
|
||||
// ReactDOM is located inside index.tsx file
|
||||
// as a result, we need a place for it to render into
|
||||
const element = document.createElement("div");
|
||||
|
||||
@@ -28,7 +28,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -44,7 +43,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -195,7 +193,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -211,7 +208,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -508,7 +504,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -524,7 +519,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -821,7 +815,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -837,7 +830,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -988,7 +980,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -1004,7 +995,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -1188,7 +1178,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -1204,7 +1193,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -1441,7 +1429,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -1457,7 +1444,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -1772,7 +1758,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -1787,8 +1772,7 @@ Object {
|
||||
"name": "Untitled-201933152653",
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": "backgroundColorPicker",
|
||||
"openMenu": "backgroundColorPicker",
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -2505,7 +2489,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -2521,7 +2504,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -2818,7 +2800,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -2834,7 +2815,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -3131,7 +3111,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -3147,7 +3126,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -3518,7 +3496,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -3534,7 +3511,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -3777,7 +3753,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -3793,7 +3768,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4111,7 +4085,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4127,7 +4100,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4213,7 +4185,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4229,7 +4200,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4293,7 +4263,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4309,7 +4278,6 @@ Object {
|
||||
"offsetLeft": 20,
|
||||
"offsetTop": 10,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
exports[`<Excalidraw/> Test UIOptions prop Test canvasActions should not hide any UI element when canvasActions is "undefined" 1`] = `
|
||||
<section
|
||||
aria-labelledby="test-id-canvasActions-title"
|
||||
aria-labelledby="canvasActions-title"
|
||||
class="zen-mode-transition"
|
||||
>
|
||||
<h2
|
||||
class="visually-hidden"
|
||||
id="test-id-canvasActions-title"
|
||||
id="canvasActions-title"
|
||||
>
|
||||
Canvas actions
|
||||
</h2>
|
||||
@@ -201,12 +201,12 @@ exports[`<Excalidraw/> Test UIOptions prop Test canvasActions should not hide an
|
||||
|
||||
exports[`<Excalidraw/> Test UIOptions prop should not hide any UI element when the UIOptions prop is "undefined" 1`] = `
|
||||
<section
|
||||
aria-labelledby="test-id-canvasActions-title"
|
||||
aria-labelledby="canvasActions-title"
|
||||
class="zen-mode-transition"
|
||||
>
|
||||
<h2
|
||||
class="visually-hidden"
|
||||
id="test-id-canvasActions-title"
|
||||
id="canvasActions-title"
|
||||
>
|
||||
Canvas actions
|
||||
</h2>
|
||||
@@ -28,7 +28,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -44,7 +43,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -497,7 +495,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -513,7 +510,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -972,7 +968,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -988,7 +983,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -1762,7 +1756,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -1778,7 +1771,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -1970,7 +1962,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -1986,7 +1977,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -2436,7 +2426,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -2452,7 +2441,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -2693,7 +2681,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -2709,7 +2696,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -2860,7 +2846,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -2876,7 +2861,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -3309,7 +3293,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -3324,8 +3307,7 @@ Object {
|
||||
"name": "Untitled-201933152653",
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": "strokeColorPicker",
|
||||
"openMenu": "strokeColorPicker",
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -3550,7 +3532,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -3566,7 +3547,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -3758,7 +3738,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -3774,7 +3753,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4007,7 +3985,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4023,7 +4000,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4263,7 +4239,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4279,7 +4254,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4651,7 +4625,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4667,7 +4640,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -4950,7 +4922,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -4966,7 +4937,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -5227,7 +5197,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -5243,7 +5212,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -5438,7 +5406,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -5454,7 +5421,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -5605,7 +5571,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -5621,7 +5586,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -6066,7 +6030,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -6082,7 +6045,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -6389,7 +6351,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -6405,7 +6366,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -8447,7 +8407,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -8463,7 +8422,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -8814,7 +8772,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -8830,7 +8787,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -9071,7 +9027,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -9087,7 +9042,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -9292,7 +9246,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -9308,7 +9261,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -9576,7 +9528,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -9592,7 +9543,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -9743,7 +9693,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -9759,7 +9708,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -9910,7 +9858,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -9926,7 +9873,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -10077,7 +10023,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -10093,7 +10038,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -10274,7 +10218,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -10290,7 +10233,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -10471,7 +10413,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -10487,7 +10428,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -10680,7 +10620,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -10696,7 +10635,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -10877,7 +10815,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -10893,7 +10830,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -11044,7 +10980,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -11060,7 +10995,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -11211,7 +11145,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -11227,7 +11160,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -11408,7 +11340,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -11424,7 +11355,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -11575,7 +11505,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -11591,7 +11520,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -11784,7 +11712,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -11800,7 +11727,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -12511,7 +12437,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -12527,7 +12452,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -12768,7 +12692,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -12784,7 +12707,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -12872,7 +12794,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -12888,7 +12809,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -12974,7 +12894,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -12990,7 +12909,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -13144,7 +13062,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -13160,7 +13077,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -13470,7 +13386,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -13486,7 +13401,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -13674,7 +13588,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -13690,7 +13603,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -14510,7 +14422,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -14526,7 +14437,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -14612,7 +14522,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -14628,7 +14537,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -15381,7 +15289,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -15397,7 +15304,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -15791,7 +15697,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -15807,7 +15712,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -16068,7 +15972,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -16084,7 +15987,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -16172,7 +16074,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -16188,7 +16089,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -16676,7 +16576,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -16692,7 +16591,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
@@ -16778,7 +16676,6 @@ Object {
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"exportEmbedScene": false,
|
||||
"exportScale": 1,
|
||||
"exportWithDarkMode": false,
|
||||
"fileHandle": null,
|
||||
"gridSize": null,
|
||||
@@ -16794,7 +16691,6 @@ Object {
|
||||
"offsetLeft": 0,
|
||||
"offsetTop": 0,
|
||||
"openMenu": null,
|
||||
"openPopup": null,
|
||||
"pasteDialog": Object {
|
||||
"data": null,
|
||||
"shown": false,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user