merge with master
This commit is contained in:
+221
-66
@@ -1,5 +1,17 @@
|
||||
import React from "react";
|
||||
import {
|
||||
import type {
|
||||
IMAGE_MIME_TYPES,
|
||||
UserIdleState,
|
||||
throttleRAF,
|
||||
MIME_TYPES,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import type { SuggestedBinding } from "@excalidraw/element/binding";
|
||||
|
||||
import type { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
|
||||
|
||||
import type { MaybeTransformHandleType } from "@excalidraw/element/transformHandles";
|
||||
|
||||
import type {
|
||||
PointerType,
|
||||
ExcalidrawLinearElement,
|
||||
NonDeletedExcalidrawElement,
|
||||
@@ -20,27 +32,32 @@ import {
|
||||
ExcalidrawFrameLikeElement,
|
||||
ExcalidrawElementType,
|
||||
ExcalidrawIframeLikeElement,
|
||||
} from "./element/types";
|
||||
import { Action } from "./actions/types";
|
||||
import { Point as RoughPoint } from "roughjs/bin/geometry";
|
||||
import { LinearElementEditor } from "./element/linearElementEditor";
|
||||
import { SuggestedBinding } from "./element/binding";
|
||||
import { ImportedDataState } from "./data/types";
|
||||
import type App from "./components/App";
|
||||
import type { throttleRAF } from "./utils";
|
||||
import { Spreadsheet } from "./charts";
|
||||
import { Language } from "./i18n";
|
||||
import { ClipboardData } from "./clipboard";
|
||||
import { isOverScrollBars } from "./scene/scrollbars";
|
||||
import { MaybeTransformHandleType } from "./element/transformHandles";
|
||||
import Library from "./data/library";
|
||||
import type { FileSystemHandle } from "./data/filesystem";
|
||||
import type { IMAGE_MIME_TYPES, MIME_TYPES } from "./constants";
|
||||
import { ContextMenuItems } from "./components/ContextMenu";
|
||||
import { SnapLine } from "./snapping";
|
||||
import { Merge, ValueOf } from "./utility-types";
|
||||
OrderedExcalidrawElement,
|
||||
ExcalidrawNonSelectionElement,
|
||||
} from "@excalidraw/element/types";
|
||||
|
||||
export type Point = Readonly<RoughPoint>;
|
||||
import type {
|
||||
Merge,
|
||||
MaybePromise,
|
||||
ValueOf,
|
||||
MakeBrand,
|
||||
} from "@excalidraw/common/utility-types";
|
||||
|
||||
import type { Action } from "./actions/types";
|
||||
import type { Spreadsheet } from "./charts";
|
||||
import type { ClipboardData } from "./clipboard";
|
||||
import type App from "./components/App";
|
||||
import type Library from "./data/library";
|
||||
import type { FileSystemHandle } from "./data/filesystem";
|
||||
import type { ContextMenuItems } from "./components/ContextMenu";
|
||||
import type { SnapLine } from "./snapping";
|
||||
import type { CaptureUpdateActionType } from "./store";
|
||||
import type { ImportedDataState } from "./data/types";
|
||||
|
||||
import type { Language } from "./i18n";
|
||||
import type { isOverScrollBars } from "./scene/scrollbars";
|
||||
import type React from "react";
|
||||
import type { JSX } from "react";
|
||||
|
||||
export type SocketId = string & { _brand: "SocketId" };
|
||||
|
||||
@@ -61,12 +78,28 @@ export type Collaborator = Readonly<{
|
||||
id?: string;
|
||||
socketId?: SocketId;
|
||||
isCurrentUser?: boolean;
|
||||
isInCall?: boolean;
|
||||
isSpeaking?: boolean;
|
||||
isMuted?: boolean;
|
||||
}>;
|
||||
|
||||
export type CollaboratorPointer = {
|
||||
x: number;
|
||||
y: number;
|
||||
tool: "pointer" | "laser";
|
||||
/**
|
||||
* Whether to render cursor + username. Useful when you only want to render
|
||||
* laser trail.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
renderCursor?: boolean;
|
||||
/**
|
||||
* Explicit laser color.
|
||||
*
|
||||
* @default string collaborator's cursor color
|
||||
*/
|
||||
laserColor?: string;
|
||||
};
|
||||
|
||||
export type DataURL = string & { _brand: "DataURL" };
|
||||
@@ -90,6 +123,11 @@ export type BinaryFileData = {
|
||||
* Epoch timestamp in milliseconds.
|
||||
*/
|
||||
lastRetrieved?: number;
|
||||
/**
|
||||
* indicates the version of the file. This can be used to determine whether
|
||||
* the file dataURL has changed e.g. as part of restore due to schema update.
|
||||
*/
|
||||
version?: number;
|
||||
};
|
||||
|
||||
export type BinaryFileMetadata = Omit<BinaryFileData, "dataURL">;
|
||||
@@ -98,6 +136,7 @@ export type BinaryFiles = Record<ExcalidrawElement["id"], BinaryFileData>;
|
||||
|
||||
export type ToolType =
|
||||
| "selection"
|
||||
| "lasso"
|
||||
| "rectangle"
|
||||
| "diamond"
|
||||
| "ellipse"
|
||||
@@ -140,6 +179,7 @@ type _CommonCanvasAppState = {
|
||||
width: AppState["width"];
|
||||
height: AppState["height"];
|
||||
viewModeEnabled: AppState["viewModeEnabled"];
|
||||
openDialog: AppState["openDialog"];
|
||||
editingGroupId: AppState["editingGroupId"]; // TODO: move to interactive canvas if possible
|
||||
selectedElementIds: AppState["selectedElementIds"]; // TODO: move to interactive canvas if possible
|
||||
frameToHighlight: AppState["frameToHighlight"]; // TODO: move to interactive canvas if possible
|
||||
@@ -157,7 +197,12 @@ export type StaticCanvasAppState = Readonly<
|
||||
exportScale: AppState["exportScale"];
|
||||
selectedElementsAreBeingDragged: AppState["selectedElementsAreBeingDragged"];
|
||||
gridSize: AppState["gridSize"];
|
||||
gridStep: AppState["gridStep"];
|
||||
frameRendering: AppState["frameRendering"];
|
||||
currentHoveredFontFamily: AppState["currentHoveredFontFamily"];
|
||||
hoveredElementIds: AppState["hoveredElementIds"];
|
||||
// Cropping
|
||||
croppingElementId: AppState["croppingElementId"];
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -179,9 +224,34 @@ export type InteractiveCanvasAppState = Readonly<
|
||||
// SnapLines
|
||||
snapLines: AppState["snapLines"];
|
||||
zenModeEnabled: AppState["zenModeEnabled"];
|
||||
editingTextElement: AppState["editingTextElement"];
|
||||
// Cropping
|
||||
isCropping: AppState["isCropping"];
|
||||
croppingElementId: AppState["croppingElementId"];
|
||||
// Search matches
|
||||
searchMatches: AppState["searchMatches"];
|
||||
}
|
||||
>;
|
||||
|
||||
export type ObservedAppState = ObservedStandaloneAppState &
|
||||
ObservedElementsAppState;
|
||||
|
||||
export type ObservedStandaloneAppState = {
|
||||
name: AppState["name"];
|
||||
viewBackgroundColor: AppState["viewBackgroundColor"];
|
||||
};
|
||||
|
||||
export type ObservedElementsAppState = {
|
||||
editingGroupId: AppState["editingGroupId"];
|
||||
selectedElementIds: AppState["selectedElementIds"];
|
||||
selectedGroupIds: AppState["selectedGroupIds"];
|
||||
// Avoiding storing whole instance, as it could lead into state incosistencies, empty undos/redos and etc.
|
||||
editingLinearElementId: LinearElementEditor["elementId"] | null;
|
||||
// Right now it's coupled to `editingLinearElement`, ideally it should not be really needed as we already have selectedElementIds & editingLinearElementId
|
||||
selectedLinearElementId: LinearElementEditor["elementId"] | null;
|
||||
croppingElementId: AppState["croppingElementId"];
|
||||
};
|
||||
|
||||
export interface AppState {
|
||||
contextMenu: {
|
||||
items: ContextMenuItems;
|
||||
@@ -195,9 +265,25 @@ export interface AppState {
|
||||
element: NonDeletedExcalidrawElement;
|
||||
state: "hover" | "active";
|
||||
} | null;
|
||||
draggingElement: NonDeletedExcalidrawElement | null;
|
||||
/**
|
||||
* for a newly created element
|
||||
* - set on pointer down, updated during pointer move, used on pointer up
|
||||
*/
|
||||
newElement: NonDeleted<ExcalidrawNonSelectionElement> | null;
|
||||
/**
|
||||
* for a single element that's being resized
|
||||
* - set on pointer down when it's selected and the active tool is selection
|
||||
*/
|
||||
resizingElement: NonDeletedExcalidrawElement | null;
|
||||
/**
|
||||
* multiElement is for multi-point linear element that's created by clicking as opposed to dragging
|
||||
* - when set and present, the editor will handle linear element creation logic accordingly
|
||||
*/
|
||||
multiElement: NonDeleted<ExcalidrawLinearElement> | null;
|
||||
/**
|
||||
* decoupled from newElement, dragging selection only creates selectionElement
|
||||
* - set on pointer down, updated during pointer move
|
||||
*/
|
||||
selectionElement: NonDeletedExcalidrawElement | null;
|
||||
isBindingEnabled: boolean;
|
||||
startBoundElement: NonDeleted<ExcalidrawBindableElement> | null;
|
||||
@@ -211,9 +297,10 @@ export interface AppState {
|
||||
};
|
||||
editingFrame: string | null;
|
||||
elementsToHighlight: NonDeleted<ExcalidrawElement>[] | null;
|
||||
// element being edited, but not necessarily added to elements array yet
|
||||
// (e.g. text element when typing into the input)
|
||||
editingElement: NonDeletedExcalidrawElement | null;
|
||||
/**
|
||||
* set when a new text is created or when an existing text is being edited
|
||||
*/
|
||||
editingTextElement: NonDeletedExcalidrawElement | null;
|
||||
editingLinearElement: LinearElementEditor | null;
|
||||
activeTool: {
|
||||
/**
|
||||
@@ -222,6 +309,8 @@ export interface AppState {
|
||||
*/
|
||||
lastActiveTool: ActiveTool | null;
|
||||
locked: boolean;
|
||||
// indicates if the current tool is temporarily switched on from the selection tool
|
||||
fromSelection: boolean;
|
||||
} & ActiveTool;
|
||||
penMode: boolean;
|
||||
penDetected: boolean;
|
||||
@@ -241,31 +330,33 @@ export interface AppState {
|
||||
currentItemTextAlign: TextAlign;
|
||||
currentItemStartArrowhead: Arrowhead | null;
|
||||
currentItemEndArrowhead: Arrowhead | null;
|
||||
currentHoveredFontFamily: FontFamilyValues | null;
|
||||
currentItemRoundness: StrokeRoundness;
|
||||
currentItemArrowType: "sharp" | "round" | "elbow";
|
||||
viewBackgroundColor: string;
|
||||
scrollX: number;
|
||||
scrollY: number;
|
||||
cursorButton: "up" | "down";
|
||||
scrolledOutside: boolean;
|
||||
name: string;
|
||||
name: string | null;
|
||||
isResizing: boolean;
|
||||
isRotating: boolean;
|
||||
zoom: Zoom;
|
||||
openMenu: "canvas" | "shape" | null;
|
||||
openPopup: "canvasBackground" | "elementBackground" | "elementStroke" | null;
|
||||
openPopup:
|
||||
| "canvasBackground"
|
||||
| "elementBackground"
|
||||
| "elementStroke"
|
||||
| "fontFamily"
|
||||
| null;
|
||||
openSidebar: { name: SidebarName; tab?: SidebarTabName } | null;
|
||||
openDialog:
|
||||
| null
|
||||
| { name: "imageExport" | "help" | "jsonExport" }
|
||||
| {
|
||||
name: "settings";
|
||||
source:
|
||||
| "tool" // when magicframe tool is selected
|
||||
| "generation" // when magicframe generate button is clicked
|
||||
| "settings"; // when AI settings dialog is explicitly invoked
|
||||
tab: "text-to-diagram" | "diagram-to-code";
|
||||
}
|
||||
| { name: "ttd"; tab: "text-to-diagram" | "mermaid" };
|
||||
| { name: "ttd"; tab: "text-to-diagram" | "mermaid" }
|
||||
| { name: "commandPalette" }
|
||||
| { name: "elementLinkSelector"; sourceElementId: ExcalidrawElement["id"] };
|
||||
|
||||
/**
|
||||
* Reflects user preference for whether the default sidebar should be docked.
|
||||
*
|
||||
@@ -277,13 +368,17 @@ export interface AppState {
|
||||
|
||||
lastPointerDownWith: PointerType;
|
||||
selectedElementIds: Readonly<{ [id: string]: true }>;
|
||||
hoveredElementIds: Readonly<{ [id: string]: true }>;
|
||||
previousSelectedElementIds: { [id: string]: true };
|
||||
selectedElementsAreBeingDragged: boolean;
|
||||
shouldCacheIgnoreZoom: boolean;
|
||||
toast: { message: string; closable?: boolean; duration?: number } | null;
|
||||
zenModeEnabled: boolean;
|
||||
theme: Theme;
|
||||
gridSize: number | null;
|
||||
/** grid cell px size */
|
||||
gridSize: number;
|
||||
gridStep: number;
|
||||
gridModeEnabled: boolean;
|
||||
viewModeEnabled: boolean;
|
||||
|
||||
/** top-most selected groups (i.e. does not include nested groups) */
|
||||
@@ -298,7 +393,11 @@ export interface AppState {
|
||||
|
||||
fileHandle: FileSystemHandle | null;
|
||||
collaborators: Map<SocketId, Collaborator>;
|
||||
showStats: boolean;
|
||||
stats: {
|
||||
open: boolean;
|
||||
/** bitmap. Use `STATS_PANELS` bit values */
|
||||
panels: number;
|
||||
};
|
||||
currentChartType: ChartType;
|
||||
pasteDialog:
|
||||
| {
|
||||
@@ -319,13 +418,30 @@ export interface AppState {
|
||||
y: number;
|
||||
} | null;
|
||||
objectsSnapModeEnabled: boolean;
|
||||
/** the user's clientId & username who is being followed on the canvas */
|
||||
/** the user's socket id & username who is being followed on the canvas */
|
||||
userToFollow: UserToFollow | null;
|
||||
/** the clientIds of the users following the current user */
|
||||
/** the socket ids of the users following the current user */
|
||||
followedBy: Set<SocketId>;
|
||||
scrollConstraints: ScrollConstraints | null;
|
||||
|
||||
/** image cropping */
|
||||
isCropping: boolean;
|
||||
croppingElementId: ExcalidrawElement["id"] | null;
|
||||
|
||||
searchMatches: readonly SearchMatch[];
|
||||
}
|
||||
|
||||
type SearchMatch = {
|
||||
id: string;
|
||||
focus: boolean;
|
||||
matchedLines: {
|
||||
offsetX: number;
|
||||
offsetY: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type UIAppState = Omit<
|
||||
AppState,
|
||||
| "suggestedBindings"
|
||||
@@ -381,21 +497,14 @@ export type LibraryItems_anyVersion = LibraryItems | LibraryItems_v1;
|
||||
export type LibraryItemsSource =
|
||||
| ((
|
||||
currentLibraryItems: LibraryItems,
|
||||
) =>
|
||||
| Blob
|
||||
| LibraryItems_anyVersion
|
||||
| Promise<LibraryItems_anyVersion | Blob>)
|
||||
| Blob
|
||||
| LibraryItems_anyVersion
|
||||
| Promise<LibraryItems_anyVersion | Blob>;
|
||||
) => MaybePromise<LibraryItems_anyVersion | Blob>)
|
||||
| MaybePromise<LibraryItems_anyVersion | Blob>;
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
export type ExcalidrawInitialDataState = Merge<
|
||||
ImportedDataState,
|
||||
{
|
||||
libraryItems?:
|
||||
| Required<ImportedDataState>["libraryItems"]
|
||||
| Promise<Required<ImportedDataState>["libraryItems"]>;
|
||||
libraryItems?: MaybePromise<Required<ImportedDataState>["libraryItems"]>;
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -406,14 +515,13 @@ export type OnUserFollowedPayload = {
|
||||
|
||||
export interface ExcalidrawProps {
|
||||
onChange?: (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
elements: readonly OrderedExcalidrawElement[],
|
||||
appState: AppState,
|
||||
files: BinaryFiles,
|
||||
) => void;
|
||||
initialData?:
|
||||
| ExcalidrawInitialDataState
|
||||
| null
|
||||
| Promise<ExcalidrawInitialDataState | null>;
|
||||
| (() => MaybePromise<ExcalidrawInitialDataState | null>)
|
||||
| MaybePromise<ExcalidrawInitialDataState | null>;
|
||||
excalidrawAPI?: (api: ExcalidrawImperativeAPI) => void;
|
||||
isCollaborating?: boolean;
|
||||
onPointerUpdate?: (payload: {
|
||||
@@ -425,6 +533,22 @@ export interface ExcalidrawProps {
|
||||
data: ClipboardData,
|
||||
event: ClipboardEvent | null,
|
||||
) => Promise<boolean> | boolean;
|
||||
/**
|
||||
* Called when element(s) are duplicated so you can listen or modify as
|
||||
* needed.
|
||||
*
|
||||
* Called when duplicating via mouse-drag, keyboard, paste, library insert
|
||||
* etc.
|
||||
*
|
||||
* Returned elements will be used in place of the next elements
|
||||
* (you should return all elements, including deleted, and not mutate
|
||||
* the element if changes are made)
|
||||
*/
|
||||
onDuplicate?: (
|
||||
nextElements: readonly ExcalidrawElement[],
|
||||
/** excludes the duplicated elements */
|
||||
prevElements: readonly ExcalidrawElement[],
|
||||
) => ExcalidrawElement[] | void;
|
||||
renderTopRightUI?: (
|
||||
isMobile: boolean,
|
||||
appState: UIAppState,
|
||||
@@ -436,6 +560,7 @@ export interface ExcalidrawProps {
|
||||
objectsSnapModeEnabled?: boolean;
|
||||
libraryReturnUrl?: string;
|
||||
theme?: Theme;
|
||||
// @TODO come with better API before v0.18.0
|
||||
name?: string;
|
||||
renderCustomStats?: (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
@@ -447,6 +572,7 @@ export interface ExcalidrawProps {
|
||||
onLibraryChange?: (libraryItems: LibraryItems) => void | Promise<any>;
|
||||
autoFocus?: boolean;
|
||||
generateIdForFile?: (file: File) => string | Promise<string>;
|
||||
generateLinkForSelection?: (id: string, type: "element" | "group") => string;
|
||||
onLinkOpen?: (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
event: CustomEvent<{
|
||||
@@ -476,21 +602,16 @@ export interface ExcalidrawProps {
|
||||
appState: AppState,
|
||||
) => JSX.Element | null;
|
||||
aiEnabled?: boolean;
|
||||
showDeprecatedFonts?: boolean;
|
||||
}
|
||||
|
||||
export type SceneData = {
|
||||
elements?: ImportedDataState["elements"];
|
||||
appState?: ImportedDataState["appState"];
|
||||
collaborators?: Map<SocketId, Collaborator>;
|
||||
commitToHistory?: boolean;
|
||||
captureUpdate?: CaptureUpdateActionType;
|
||||
};
|
||||
|
||||
export enum UserIdleState {
|
||||
ACTIVE = "active",
|
||||
AWAY = "away",
|
||||
IDLE = "idle",
|
||||
}
|
||||
|
||||
export type ExportOpts = {
|
||||
saveFileToDisk?: boolean;
|
||||
onExportToBackend?: (
|
||||
@@ -551,6 +672,7 @@ export type AppProps = Merge<
|
||||
* in the app, eg Manager. Factored out into a separate type to keep DRY. */
|
||||
export type AppClassProperties = {
|
||||
props: AppProps;
|
||||
state: AppState;
|
||||
interactiveCanvas: HTMLCanvasElement | null;
|
||||
/** static canvas */
|
||||
canvas: HTMLCanvasElement;
|
||||
@@ -566,6 +688,8 @@ export type AppClassProperties = {
|
||||
files: BinaryFiles;
|
||||
device: App["device"];
|
||||
scene: App["scene"];
|
||||
syncActionResult: App["syncActionResult"];
|
||||
fonts: App["fonts"];
|
||||
pasteFromClipboard: App["pasteFromClipboard"];
|
||||
id: App["id"];
|
||||
onInsertElements: App["onInsertElements"];
|
||||
@@ -575,10 +699,22 @@ export type AppClassProperties = {
|
||||
addFiles: App["addFiles"];
|
||||
addElementsFromPasteOrLibrary: App["addElementsFromPasteOrLibrary"];
|
||||
togglePenMode: App["togglePenMode"];
|
||||
toggleLock: App["toggleLock"];
|
||||
setActiveTool: App["setActiveTool"];
|
||||
setOpenDialog: App["setOpenDialog"];
|
||||
insertEmbeddableElement: App["insertEmbeddableElement"];
|
||||
onMagicframeToolSelect: App["onMagicframeToolSelect"];
|
||||
getName: App["getName"];
|
||||
dismissLinearEditor: App["dismissLinearEditor"];
|
||||
flowChartCreator: App["flowChartCreator"];
|
||||
getEffectiveGridSize: App["getEffectiveGridSize"];
|
||||
setPlugins: App["setPlugins"];
|
||||
plugins: App["plugins"];
|
||||
getEditorUIOffsets: App["getEditorUIOffsets"];
|
||||
visibleElements: App["visibleElements"];
|
||||
excalidrawContainerValue: App["excalidrawContainerValue"];
|
||||
|
||||
onPointerUpEmitter: App["onPointerUpEmitter"];
|
||||
};
|
||||
|
||||
export type PointerDownState = Readonly<{
|
||||
@@ -643,7 +779,7 @@ export type PointerDownState = Readonly<{
|
||||
|
||||
export type UnsubscribeCallback = () => void;
|
||||
|
||||
export type ExcalidrawImperativeAPI = {
|
||||
export interface ExcalidrawImperativeAPI {
|
||||
updateScene: InstanceType<typeof App>["updateScene"];
|
||||
updateLibrary: InstanceType<typeof Library>["updateLibrary"];
|
||||
resetScene: InstanceType<typeof App>["resetScene"];
|
||||
@@ -653,10 +789,11 @@ export type ExcalidrawImperativeAPI = {
|
||||
history: {
|
||||
clear: InstanceType<typeof App>["resetHistory"];
|
||||
};
|
||||
scrollToContent: InstanceType<typeof App>["scrollToContent"];
|
||||
getSceneElements: InstanceType<typeof App>["getSceneElements"];
|
||||
getAppState: () => InstanceType<typeof App>["state"];
|
||||
getFiles: () => InstanceType<typeof App>["files"];
|
||||
getName: InstanceType<typeof App>["getName"];
|
||||
scrollToContent: InstanceType<typeof App>["scrollToContent"];
|
||||
registerAction: (action: Action) => void;
|
||||
refresh: InstanceType<typeof App>["refresh"];
|
||||
setToast: InstanceType<typeof App>["setToast"];
|
||||
@@ -700,7 +837,7 @@ export type ExcalidrawImperativeAPI = {
|
||||
callback: (payload: OnUserFollowedPayload) => void,
|
||||
) => UnsubscribeCallback;
|
||||
setScrollConstraints: InstanceType<typeof App>["setScrollConstraints"];
|
||||
};
|
||||
}
|
||||
|
||||
export type Device = Readonly<{
|
||||
viewport: {
|
||||
@@ -714,7 +851,7 @@ export type Device = Readonly<{
|
||||
isTouchScreen: boolean;
|
||||
}>;
|
||||
|
||||
type FrameNameBounds = {
|
||||
export type FrameNameBounds = {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
@@ -775,3 +912,21 @@ export type ScrollConstraints = {
|
||||
viewportZoomFactor?: number;
|
||||
lockZoom?: boolean;
|
||||
};
|
||||
export type PendingExcalidrawElements = ExcalidrawElement[];
|
||||
|
||||
/** Runtime gridSize value. Null indicates disabled grid. */
|
||||
export type NullableGridSize =
|
||||
| (AppState["gridSize"] & MakeBrand<"NullableGridSize">)
|
||||
| null;
|
||||
|
||||
export type GenerateDiagramToCode = (props: {
|
||||
frame: ExcalidrawMagicFrameElement;
|
||||
children: readonly ExcalidrawElement[];
|
||||
}) => MaybePromise<{ html: string }>;
|
||||
|
||||
export type Offsets = Partial<{
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
}>;
|
||||
|
||||
Reference in New Issue
Block a user