mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-15 21:40:06 +02:00

Tests added Fix binding Remove unneeded params Unfinished simple arrow avoidance Fix newly created jumping arrow when gets outside Do not apply the jumping logic to elbow arrows for new elements Existing arrows now jump out Type updates to support fixed binding for simple arrows Fix crash for elbow arrws in mutateElement() Refactored simple arrow creation Updating tests No confirm threshold when inside biding range Fix multi-point arrow grid off Make elbow arrows respect grids Unbind arrow if bound and moved at shaft of arrow key Fix binding test Fix drag unbind when the bound element is in the selection Do not move mid point for simple arrows bound on both ends Add test for mobing mid points for simple arrows when bound on the same element on both ends Fix linear editor bug when both midpoint and endpoint is moved Fix all point multipoint arrow highlight and binding Arrow dragging gets a little drag to avoid accidental unbinding Fixed point binding for simple arrows when the arrow doesn't point to the element Fix binding disabled use-case triggering arrow editor Timed binding mode change for simple arrows Apply fixes Remove code to unbind on drag Update simple arrow fixed point when arrow is dragged or moved by arrow keys Binding highlight fixes Change bind mode timeout logic Fix tests Add Alt bindMode switch No dragging of arrows when bound, similar to elbow Fix timeout not taking effect immediately Bumop z-index for arrows when dragged Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Only transparent bindables allow binding fallthrough Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix lint Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix point click array creation interaction with fixed point binding Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Restrict new behavior to arrows only Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Allow binding inside images Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix already existing fixed binding retention Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Refactor and implement fixed point binding for unfilled elements Restore drag Removed point binding Binding code refactor Added centered focus point Binding & focus point debug Add invariants to check binding integrity in elements Binding fixes Small refactors Completely rewritten binding Include point updates after binding update Fix point updates when endpoint dragged and opposite endpoint orbits centered focus point only for new arrows Make z-index arrow reorder on bind Turn off inside binding mode after leaving a shape Remove invariants from debug feat: expose `applyTo` options, don't commit empty text element (#9744) * Expose applyTo options, skip re-draw for empty text * Don't commit empty text elements test: added test file for distribute (#9754) z-index update Bind mode on precise binding Fix binding to inside element Fix initial arrow not following cursor (white dot) Fix elbow arrow Fix z-index so it works on hover Fix fixed angle orbiting Move point click arrow creation over to common strategy Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Add binding strategy for drag arrow creation Fix elbow arrow Fix point handles Snap to center Fix transparent shape binding Internal arrow creation fix Fix point binding Fix selection bug Fix new arrow focus point Images now always bind inside Flashing arrow creation on binding band Add watchState debug method to window.h Fix debug canvas crash Remove non-needed bind mode Fix restore No keyboard movement when bound Add actionFinalize when arrow in edit mode Add drag to the Stats panel when bound arrow is moved Further simplify curve tracking Add typing to action register() Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix point at finalize Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix type errors Signed-off-by: Mark Tolmacs <mark@lazycat.hu> New arrow binding rules Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix cyclical dep Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fix jiggly arrows Fix jiggly arrow x2 Long inside-other binding Click-click binding Fix arrows Performance [PERF] Replace in-place Jacobian derivation with analytical version Different approach to inside binding Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Fixes Fix inconsistent arrow start jump out Change how images are bound to on new arrow creation Lower timeout Small insurance fix Fix curve test Signed-off-by: Mark Tolmacs <mark@lazycat.hu> No center focus point 90% inside center binding Fixing tests fix: Elbow arrow fixes fix: More arrow fixes Do not trigger arrow binding for linear elements fix: Linear elements fix: Refactor actionFinalize for linear Binding tests updated fix: Jump when cursor not moved fix: history tests Fix history snapshot Fix undo issue fix(eraser): Remove binding from the other element fix(tests): Update tests chore: Attempt filtering new set state Fix excessive history recording Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
529 lines
15 KiB
TypeScript
529 lines
15 KiB
TypeScript
import type {
|
|
ExcalidrawElement,
|
|
FontFamilyValues,
|
|
} from "@excalidraw/element/types";
|
|
import type { AppProps, AppState } from "@excalidraw/excalidraw/types";
|
|
|
|
import { COLOR_PALETTE } from "./colors";
|
|
|
|
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
export const isWindows = /^Win/.test(navigator.platform);
|
|
export const isAndroid = /\b(android)\b/i.test(navigator.userAgent);
|
|
export const isFirefox =
|
|
typeof window !== "undefined" &&
|
|
"netscape" in window &&
|
|
navigator.userAgent.indexOf("rv:") > 1 &&
|
|
navigator.userAgent.indexOf("Gecko") > 1;
|
|
export const isChrome = navigator.userAgent.indexOf("Chrome") !== -1;
|
|
export const isSafari =
|
|
!isChrome && navigator.userAgent.indexOf("Safari") !== -1;
|
|
export const isIOS =
|
|
/iPad|iPhone/i.test(navigator.platform) ||
|
|
// iPadOS 13+
|
|
(navigator.userAgent.includes("Mac") && "ontouchend" in document);
|
|
// keeping function so it can be mocked in test
|
|
export const isBrave = () =>
|
|
(navigator as any).brave?.isBrave?.name === "isBrave";
|
|
|
|
export const isMobile =
|
|
isIOS ||
|
|
/android|webos|ipod|blackberry|iemobile|opera mini/i.test(
|
|
navigator.userAgent,
|
|
) ||
|
|
/android|ios|ipod|blackberry|windows phone/i.test(navigator.platform);
|
|
|
|
export const supportsResizeObserver =
|
|
typeof window !== "undefined" && "ResizeObserver" in window;
|
|
|
|
export const APP_NAME = "Excalidraw";
|
|
|
|
// distance when creating text before it's considered `autoResize: false`
|
|
// we're using higher threshold so that clicks that end up being drags
|
|
// don't unintentionally create text elements that are wrapped to a few chars
|
|
// (happens a lot with fast clicks with the text tool)
|
|
export const TEXT_AUTOWRAP_THRESHOLD = 36; // px
|
|
export const DRAGGING_THRESHOLD = 10; // px
|
|
export const MINIMUM_ARROW_SIZE = 20; // px
|
|
export const LINE_CONFIRM_THRESHOLD = 8; // px
|
|
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
|
|
export const ELEMENT_TRANSLATE_AMOUNT = 1;
|
|
export const TEXT_TO_CENTER_SNAP_THRESHOLD = 30;
|
|
export const SHIFT_LOCKING_ANGLE = Math.PI / 12;
|
|
export const DEFAULT_LASER_COLOR = "red";
|
|
export const CURSOR_TYPE = {
|
|
TEXT: "text",
|
|
CROSSHAIR: "crosshair",
|
|
GRABBING: "grabbing",
|
|
GRAB: "grab",
|
|
POINTER: "pointer",
|
|
MOVE: "move",
|
|
AUTO: "",
|
|
};
|
|
export const POINTER_BUTTON = {
|
|
MAIN: 0,
|
|
WHEEL: 1,
|
|
SECONDARY: 2,
|
|
TOUCH: -1,
|
|
ERASER: 5,
|
|
} as const;
|
|
|
|
export const POINTER_EVENTS = {
|
|
enabled: "all",
|
|
disabled: "none",
|
|
// asserted as any so it can be freely assigned to React Element
|
|
// "pointerEnvets" CSS prop
|
|
inheritFromUI: "var(--ui-pointerEvents)" as any,
|
|
} as const;
|
|
|
|
export enum EVENT {
|
|
COPY = "copy",
|
|
PASTE = "paste",
|
|
CUT = "cut",
|
|
KEYDOWN = "keydown",
|
|
KEYUP = "keyup",
|
|
MOUSE_MOVE = "mousemove",
|
|
RESIZE = "resize",
|
|
UNLOAD = "unload",
|
|
FOCUS = "focus",
|
|
BLUR = "blur",
|
|
DRAG_OVER = "dragover",
|
|
DROP = "drop",
|
|
GESTURE_END = "gestureend",
|
|
BEFORE_UNLOAD = "beforeunload",
|
|
GESTURE_START = "gesturestart",
|
|
GESTURE_CHANGE = "gesturechange",
|
|
POINTER_MOVE = "pointermove",
|
|
POINTER_DOWN = "pointerdown",
|
|
POINTER_UP = "pointerup",
|
|
STATE_CHANGE = "statechange",
|
|
WHEEL = "wheel",
|
|
TOUCH_START = "touchstart",
|
|
TOUCH_END = "touchend",
|
|
HASHCHANGE = "hashchange",
|
|
VISIBILITY_CHANGE = "visibilitychange",
|
|
SCROLL = "scroll",
|
|
// custom events
|
|
EXCALIDRAW_LINK = "excalidraw-link",
|
|
MENU_ITEM_SELECT = "menu.itemSelect",
|
|
MESSAGE = "message",
|
|
FULLSCREENCHANGE = "fullscreenchange",
|
|
}
|
|
|
|
export const YOUTUBE_STATES = {
|
|
UNSTARTED: -1,
|
|
ENDED: 0,
|
|
PLAYING: 1,
|
|
PAUSED: 2,
|
|
BUFFERING: 3,
|
|
CUED: 5,
|
|
} as const;
|
|
|
|
export const ENV = {
|
|
TEST: "test",
|
|
DEVELOPMENT: "development",
|
|
PRODUCTION: "production",
|
|
};
|
|
|
|
export const CLASSES = {
|
|
SHAPE_ACTIONS_MENU: "App-menu__left",
|
|
ZOOM_ACTIONS: "zoom-actions",
|
|
SEARCH_MENU_INPUT_WRAPPER: "layer-ui__search-inputWrapper",
|
|
CONVERT_ELEMENT_TYPE_POPUP: "ConvertElementTypePopup",
|
|
};
|
|
|
|
export const CJK_HAND_DRAWN_FALLBACK_FONT = "Xiaolai";
|
|
export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
|
|
|
|
/**
|
|
* // TODO: shouldn't be really `const`, likely neither have integers as values, due to value for the custom fonts, which should likely be some hash.
|
|
*
|
|
* Let's think this through and consider:
|
|
* - https://developer.mozilla.org/en-US/docs/Web/CSS/generic-family
|
|
* - https://drafts.csswg.org/css-fonts-4/#font-family-prop
|
|
* - https://learn.microsoft.com/en-us/typography/opentype/spec/ibmfc
|
|
*/
|
|
export const FONT_FAMILY = {
|
|
Virgil: 1,
|
|
Helvetica: 2,
|
|
Cascadia: 3,
|
|
// leave 4 unused as it was historically used for Assistant (which we don't use anymore) or custom font (Obsidian)
|
|
Excalifont: 5,
|
|
Nunito: 6,
|
|
"Lilita One": 7,
|
|
"Comic Shanns": 8,
|
|
"Liberation Sans": 9,
|
|
Assistant: 10,
|
|
};
|
|
|
|
// Segoe UI Emoji fails to properly fallback for some glyphs: ∞, ∫, ≠
|
|
// so we need to have generic font fallback before it
|
|
export const SANS_SERIF_GENERIC_FONT = "sans-serif";
|
|
export const MONOSPACE_GENERIC_FONT = "monospace";
|
|
|
|
export const FONT_FAMILY_GENERIC_FALLBACKS = {
|
|
[SANS_SERIF_GENERIC_FONT]: 998,
|
|
[MONOSPACE_GENERIC_FONT]: 999,
|
|
};
|
|
|
|
export const FONT_FAMILY_FALLBACKS = {
|
|
[CJK_HAND_DRAWN_FALLBACK_FONT]: 100,
|
|
...FONT_FAMILY_GENERIC_FALLBACKS,
|
|
[WINDOWS_EMOJI_FALLBACK_FONT]: 1000,
|
|
};
|
|
|
|
export function getGenericFontFamilyFallback(
|
|
fontFamily: number,
|
|
): keyof typeof FONT_FAMILY_GENERIC_FALLBACKS {
|
|
switch (fontFamily) {
|
|
case FONT_FAMILY.Cascadia:
|
|
case FONT_FAMILY["Comic Shanns"]:
|
|
return MONOSPACE_GENERIC_FONT;
|
|
|
|
default:
|
|
return SANS_SERIF_GENERIC_FONT;
|
|
}
|
|
}
|
|
|
|
export const getFontFamilyFallbacks = (
|
|
fontFamily: number,
|
|
): Array<keyof typeof FONT_FAMILY_FALLBACKS> => {
|
|
const genericFallbackFont = getGenericFontFamilyFallback(fontFamily);
|
|
|
|
switch (fontFamily) {
|
|
case FONT_FAMILY.Excalifont:
|
|
return [
|
|
CJK_HAND_DRAWN_FALLBACK_FONT,
|
|
genericFallbackFont,
|
|
WINDOWS_EMOJI_FALLBACK_FONT,
|
|
];
|
|
default:
|
|
return [genericFallbackFont, WINDOWS_EMOJI_FALLBACK_FONT];
|
|
}
|
|
};
|
|
|
|
export const THEME = {
|
|
LIGHT: "light",
|
|
DARK: "dark",
|
|
} as const;
|
|
|
|
export const FRAME_STYLE = {
|
|
strokeColor: "#bbb" as ExcalidrawElement["strokeColor"],
|
|
strokeWidth: 2 as ExcalidrawElement["strokeWidth"],
|
|
strokeStyle: "solid" as ExcalidrawElement["strokeStyle"],
|
|
fillStyle: "solid" as ExcalidrawElement["fillStyle"],
|
|
roughness: 0 as ExcalidrawElement["roughness"],
|
|
roundness: null as ExcalidrawElement["roundness"],
|
|
backgroundColor: "transparent" as ExcalidrawElement["backgroundColor"],
|
|
radius: 8,
|
|
nameOffsetY: 3,
|
|
nameColorLightTheme: "#999999",
|
|
nameColorDarkTheme: "#7a7a7a",
|
|
nameFontSize: 14,
|
|
nameLineHeight: 1.25,
|
|
};
|
|
|
|
export const MIN_FONT_SIZE = 1;
|
|
export const DEFAULT_FONT_SIZE = 20;
|
|
export const DEFAULT_FONT_FAMILY: FontFamilyValues = FONT_FAMILY.Excalifont;
|
|
export const DEFAULT_TEXT_ALIGN = "left";
|
|
export const DEFAULT_VERTICAL_ALIGN = "top";
|
|
export const DEFAULT_VERSION = "{version}";
|
|
export const DEFAULT_TRANSFORM_HANDLE_SPACING = 2;
|
|
|
|
export const SIDE_RESIZING_THRESHOLD = 2 * DEFAULT_TRANSFORM_HANDLE_SPACING;
|
|
// a small epsilon to make side resizing always take precedence
|
|
// (avoids an increase in renders and changes to tests)
|
|
export const EPSILON = 0.00001;
|
|
export const DEFAULT_COLLISION_THRESHOLD =
|
|
2 * SIDE_RESIZING_THRESHOLD - EPSILON;
|
|
|
|
export const COLOR_WHITE = "#ffffff";
|
|
export const COLOR_CHARCOAL_BLACK = "#1e1e1e";
|
|
// keep this in sync with CSS
|
|
export const COLOR_VOICE_CALL = "#a2f1a6";
|
|
|
|
export const CANVAS_ONLY_ACTIONS = ["selectAll"];
|
|
|
|
export const DEFAULT_GRID_SIZE = 20;
|
|
export const DEFAULT_GRID_STEP = 5;
|
|
|
|
export const IMAGE_MIME_TYPES = {
|
|
svg: "image/svg+xml",
|
|
png: "image/png",
|
|
jpg: "image/jpeg",
|
|
gif: "image/gif",
|
|
webp: "image/webp",
|
|
bmp: "image/bmp",
|
|
ico: "image/x-icon",
|
|
avif: "image/avif",
|
|
jfif: "image/jfif",
|
|
} as const;
|
|
|
|
export const MIME_TYPES = {
|
|
text: "text/plain",
|
|
html: "text/html",
|
|
json: "application/json",
|
|
// excalidraw data
|
|
excalidraw: "application/vnd.excalidraw+json",
|
|
excalidrawlib: "application/vnd.excalidrawlib+json",
|
|
// image-encoded excalidraw data
|
|
"excalidraw.svg": "image/svg+xml",
|
|
"excalidraw.png": "image/png",
|
|
// binary
|
|
binary: "application/octet-stream",
|
|
// image
|
|
...IMAGE_MIME_TYPES,
|
|
} as const;
|
|
|
|
export const ALLOWED_PASTE_MIME_TYPES = [
|
|
MIME_TYPES.text,
|
|
MIME_TYPES.html,
|
|
...Object.values(IMAGE_MIME_TYPES),
|
|
] as const;
|
|
|
|
export const EXPORT_IMAGE_TYPES = {
|
|
png: "png",
|
|
svg: "svg",
|
|
clipboard: "clipboard",
|
|
} as const;
|
|
|
|
export const EXPORT_DATA_TYPES = {
|
|
excalidraw: "excalidraw",
|
|
excalidrawClipboard: "excalidraw/clipboard",
|
|
excalidrawLibrary: "excalidrawlib",
|
|
excalidrawClipboardWithAPI: "excalidraw-api/clipboard",
|
|
} as const;
|
|
|
|
export const getExportSource = () =>
|
|
window.EXCALIDRAW_EXPORT_SOURCE || window.location.origin;
|
|
|
|
// time in milliseconds
|
|
export const IMAGE_RENDER_TIMEOUT = 500;
|
|
export const TAP_TWICE_TIMEOUT = 300;
|
|
export const TOUCH_CTX_MENU_TIMEOUT = 500;
|
|
export const TITLE_TIMEOUT = 10000;
|
|
export const VERSION_TIMEOUT = 30000;
|
|
export const SCROLL_TIMEOUT = 100;
|
|
export const ZOOM_STEP = 0.1;
|
|
export const MIN_ZOOM = 0.1;
|
|
export const MAX_ZOOM = 30;
|
|
export const HYPERLINK_TOOLTIP_DELAY = 300;
|
|
|
|
// Report a user inactive after IDLE_THRESHOLD milliseconds
|
|
export const IDLE_THRESHOLD = 60_000;
|
|
// Report a user active each ACTIVE_THRESHOLD milliseconds
|
|
export const ACTIVE_THRESHOLD = 3_000;
|
|
|
|
// duplicates --theme-filter, should be removed soon
|
|
export const THEME_FILTER = "invert(93%) hue-rotate(180deg)";
|
|
|
|
export const URL_QUERY_KEYS = {
|
|
addLibrary: "addLibrary",
|
|
} as const;
|
|
|
|
export const URL_HASH_KEYS = {
|
|
addLibrary: "addLibrary",
|
|
} as const;
|
|
|
|
export const DEFAULT_UI_OPTIONS: AppProps["UIOptions"] = {
|
|
canvasActions: {
|
|
changeViewBackgroundColor: true,
|
|
clearCanvas: true,
|
|
export: { saveFileToDisk: true },
|
|
loadScene: true,
|
|
saveToActiveFile: true,
|
|
toggleTheme: null,
|
|
saveAsImage: true,
|
|
},
|
|
tools: {
|
|
image: true,
|
|
},
|
|
};
|
|
|
|
// breakpoints
|
|
// -----------------------------------------------------------------------------
|
|
// md screen
|
|
export const MQ_MAX_WIDTH_PORTRAIT = 730;
|
|
export const MQ_MAX_WIDTH_LANDSCAPE = 1000;
|
|
export const MQ_MAX_HEIGHT_LANDSCAPE = 500;
|
|
// sidebar
|
|
export const MQ_RIGHT_SIDEBAR_MIN_WIDTH = 1229;
|
|
// -----------------------------------------------------------------------------
|
|
|
|
export const MAX_DECIMALS_FOR_SVG_EXPORT = 2;
|
|
|
|
export const EXPORT_SCALES = [1, 2, 3];
|
|
export const DEFAULT_EXPORT_PADDING = 10; // px
|
|
|
|
export const DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT = 1440;
|
|
|
|
export const MAX_ALLOWED_FILE_BYTES = 4 * 1024 * 1024;
|
|
|
|
export const SVG_NS = "http://www.w3.org/2000/svg";
|
|
export const SVG_DOCUMENT_PREAMBLE = `<?xml version="1.0" standalone="no"?>
|
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
`;
|
|
|
|
export const ENCRYPTION_KEY_BITS = 128;
|
|
|
|
export const VERSIONS = {
|
|
excalidraw: 2,
|
|
excalidrawLibrary: 2,
|
|
} as const;
|
|
|
|
export const BOUND_TEXT_PADDING = 5;
|
|
export const ARROW_LABEL_WIDTH_FRACTION = 0.7;
|
|
export const ARROW_LABEL_FONT_SIZE_TO_MIN_WIDTH_RATIO = 11;
|
|
|
|
export const VERTICAL_ALIGN = {
|
|
TOP: "top",
|
|
MIDDLE: "middle",
|
|
BOTTOM: "bottom",
|
|
};
|
|
|
|
export const TEXT_ALIGN = {
|
|
LEFT: "left",
|
|
CENTER: "center",
|
|
RIGHT: "right",
|
|
};
|
|
|
|
export const ELEMENT_READY_TO_ERASE_OPACITY = 20;
|
|
|
|
// Radius represented as 25% of element's largest side (width/height).
|
|
// Used for LEGACY and PROPORTIONAL_RADIUS algorithms, or when the element is
|
|
// below the cutoff size.
|
|
export const DEFAULT_PROPORTIONAL_RADIUS = 0.25;
|
|
// Fixed radius for the ADAPTIVE_RADIUS algorithm. In pixels.
|
|
export const DEFAULT_ADAPTIVE_RADIUS = 32;
|
|
// roundness type (algorithm)
|
|
export const ROUNDNESS = {
|
|
// Used for legacy rounding (rectangles), which currently works the same
|
|
// as PROPORTIONAL_RADIUS, but we need to differentiate for UI purposes and
|
|
// forwards-compat.
|
|
LEGACY: 1,
|
|
|
|
// Used for linear elements & diamonds
|
|
PROPORTIONAL_RADIUS: 2,
|
|
|
|
// Current default algorithm for rectangles, using fixed pixel radius.
|
|
// It's working similarly to a regular border-radius, but attemps to make
|
|
// radius visually similar across differnt element sizes, especially
|
|
// very large and very small elements.
|
|
//
|
|
// NOTE right now we don't allow configuration and use a constant radius
|
|
// (see DEFAULT_ADAPTIVE_RADIUS constant)
|
|
ADAPTIVE_RADIUS: 3,
|
|
} as const;
|
|
|
|
export const ROUGHNESS = {
|
|
architect: 0,
|
|
artist: 1,
|
|
cartoonist: 2,
|
|
} as const;
|
|
|
|
export const STROKE_WIDTH = {
|
|
thin: 1,
|
|
bold: 2,
|
|
extraBold: 4,
|
|
} as const;
|
|
|
|
export const DEFAULT_ELEMENT_PROPS: {
|
|
strokeColor: ExcalidrawElement["strokeColor"];
|
|
backgroundColor: ExcalidrawElement["backgroundColor"];
|
|
fillStyle: ExcalidrawElement["fillStyle"];
|
|
strokeWidth: ExcalidrawElement["strokeWidth"];
|
|
strokeStyle: ExcalidrawElement["strokeStyle"];
|
|
roughness: ExcalidrawElement["roughness"];
|
|
opacity: ExcalidrawElement["opacity"];
|
|
locked: ExcalidrawElement["locked"];
|
|
} = {
|
|
strokeColor: COLOR_PALETTE.black,
|
|
backgroundColor: COLOR_PALETTE.transparent,
|
|
fillStyle: "solid",
|
|
strokeWidth: 2,
|
|
strokeStyle: "solid",
|
|
roughness: ROUGHNESS.artist,
|
|
opacity: 100,
|
|
locked: false,
|
|
};
|
|
|
|
export const LIBRARY_SIDEBAR_TAB = "library";
|
|
export const CANVAS_SEARCH_TAB = "search";
|
|
|
|
export const DEFAULT_SIDEBAR = {
|
|
name: "default",
|
|
defaultTab: LIBRARY_SIDEBAR_TAB,
|
|
} as const;
|
|
|
|
export const LIBRARY_DISABLED_TYPES = new Set([
|
|
"iframe",
|
|
"embeddable",
|
|
"image",
|
|
] as const);
|
|
|
|
// use these constants to easily identify reference sites
|
|
export const TOOL_TYPE = {
|
|
selection: "selection",
|
|
lasso: "lasso",
|
|
rectangle: "rectangle",
|
|
diamond: "diamond",
|
|
ellipse: "ellipse",
|
|
arrow: "arrow",
|
|
line: "line",
|
|
freedraw: "freedraw",
|
|
text: "text",
|
|
image: "image",
|
|
eraser: "eraser",
|
|
hand: "hand",
|
|
frame: "frame",
|
|
magicframe: "magicframe",
|
|
embeddable: "embeddable",
|
|
laser: "laser",
|
|
} as const;
|
|
|
|
export const EDITOR_LS_KEYS = {
|
|
OAI_API_KEY: "excalidraw-oai-api-key",
|
|
// legacy naming (non)scheme
|
|
MERMAID_TO_EXCALIDRAW: "mermaid-to-excalidraw",
|
|
PUBLISH_LIBRARY: "publish-library-data",
|
|
} as const;
|
|
|
|
/**
|
|
* not translated as this is used only in public, stateless API as default value
|
|
* where filename is optional and we can't retrieve name from app state
|
|
*/
|
|
export const DEFAULT_FILENAME = "Untitled";
|
|
|
|
export const STATS_PANELS = { generalStats: 1, elementProperties: 2 } as const;
|
|
|
|
export const MIN_WIDTH_OR_HEIGHT = 1;
|
|
|
|
export const ARROW_TYPE: { [T in AppState["currentItemArrowType"]]: T } = {
|
|
sharp: "sharp",
|
|
round: "round",
|
|
elbow: "elbow",
|
|
};
|
|
|
|
export const DEFAULT_REDUCED_GLOBAL_ALPHA = 0.3;
|
|
export const ELEMENT_LINK_KEY = "element";
|
|
|
|
/** used in tests */
|
|
export const ORIG_ID = Symbol.for("__test__originalId__");
|
|
|
|
export enum UserIdleState {
|
|
ACTIVE = "active",
|
|
AWAY = "away",
|
|
IDLE = "idle",
|
|
}
|
|
|
|
/**
|
|
* distance at which we merge points instead of adding a new merge-point
|
|
* when converting a line to a polygon (merge currently means overlaping
|
|
* the start and end points)
|
|
*/
|
|
export const LINE_POLYGON_POINT_MERGE_DISTANCE = 20;
|
|
|
|
export const DOUBLE_TAP_POSITION_THRESHOLD = 35;
|
|
|
|
export const BIND_MODE_TIMEOUT = 800; // ms
|