import type { LocalPoint, Radians } from "@excalidraw/math"; import type { FONT_FAMILY, ROUNDNESS, TEXT_ALIGN, THEME, VERTICAL_ALIGN, } from "../constants"; import type { MakeBrand, MarkNonNullable, Merge, ValueOf, } from "../utility-types"; export type ChartType = "bar" | "line"; export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag"; export type FontFamilyKeys = keyof typeof FONT_FAMILY; export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys]; export type Theme = typeof THEME[keyof typeof THEME]; export type FontString = string & { _brand: "fontString" }; export type GroupId = string; export type PointerType = "mouse" | "pen" | "touch"; export type StrokeRoundness = "round" | "sharp"; export type RoundnessType = ValueOf; export type StrokeStyle = "solid" | "dashed" | "dotted"; export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN]; type VerticalAlignKeys = keyof typeof VERTICAL_ALIGN; export type VerticalAlign = typeof VERTICAL_ALIGN[VerticalAlignKeys]; export type FractionalIndex = string & { _brand: "franctionalIndex" }; export type BoundElement = Readonly<{ id: ExcalidrawLinearElement["id"]; type: "arrow" | "text"; }>; type _ExcalidrawElementBase = Readonly<{ id: string; x: number; y: number; strokeColor: string; backgroundColor: string; fillStyle: FillStyle; strokeWidth: number; strokeStyle: StrokeStyle; roundness: null | { type: RoundnessType; value?: number }; roughness: number; opacity: number; width: number; height: number; angle: Radians; /** Random integer used to seed shape generation so that the roughjs shape doesn't differ across renders. */ seed: number; /** Integer that is sequentially incremented on each change. Used to reconcile elements during collaboration or when saving to server. */ version: number; /** Random integer that is regenerated on each change. Used for deterministic reconciliation of updates during collaboration, in case the versions (see above) are identical. */ versionNonce: number; /** String in a fractional form defined by https://github.com/rocicorp/fractional-indexing. Used for ordering in multiplayer scenarios, such as during reconciliation or undo / redo. Always kept in sync with the array order by `syncMovedIndices` and `syncInvalidIndices`. Could be null, i.e. for new elements which were not yet assigned to the scene. */ index: FractionalIndex | null; isDeleted: boolean; /** List of groups the element belongs to. Ordered from deepest to shallowest. */ groupIds: readonly GroupId[]; frameId: string | null; /** other elements that are bound to this element */ boundElements: readonly BoundElement[] | null; /** epoch (ms) timestamp of last element update */ updated: number; link: string | null; locked: boolean; customData?: Record; }>; export type ExcalidrawSelectionElement = _ExcalidrawElementBase & { type: "selection"; }; export type ExcalidrawRectangleElement = _ExcalidrawElementBase & { type: "rectangle"; }; export type ExcalidrawDiamondElement = _ExcalidrawElementBase & { type: "diamond"; }; export type ExcalidrawEllipseElement = _ExcalidrawElementBase & { type: "ellipse"; }; export type ExcalidrawEmbeddableElement = _ExcalidrawElementBase & Readonly<{ type: "embeddable"; }>; export type MagicGenerationData = | { status: "pending"; } | { status: "done"; html: string } | { status: "error"; message?: string; code: "ERR_GENERATION_INTERRUPTED" | string; }; export type ExcalidrawIframeElement = _ExcalidrawElementBase & Readonly<{ type: "iframe"; // TODO move later to AI-specific frame customData?: { generationData?: MagicGenerationData }; }>; export type ExcalidrawIframeLikeElement = | ExcalidrawIframeElement | ExcalidrawEmbeddableElement; export type IframeData = | { intrinsicSize: { w: number; h: number }; error?: Error; sandbox?: { allowSameOrigin?: boolean }; } & ( | { type: "video" | "generic"; link: string } | { type: "document"; srcdoc: (theme: Theme) => string } ); export type ImageCrop = { x: number; y: number; width: number; height: number; naturalWidth: number; naturalHeight: number; }; export type ExcalidrawImageElement = _ExcalidrawElementBase & Readonly<{ type: "image"; fileId: FileId | null; /** whether respective file is persisted */ status: "pending" | "saved" | "error"; /** X and Y scale factors <-1, 1>, used for image axis flipping */ scale: [number, number]; /** whether an element is cropped */ crop: ImageCrop | null; }>; export type InitializedExcalidrawImageElement = MarkNonNullable< ExcalidrawImageElement, "fileId" >; export type ExcalidrawFrameElement = _ExcalidrawElementBase & { type: "frame"; name: string | null; }; export type ExcalidrawMagicFrameElement = _ExcalidrawElementBase & { type: "magicframe"; name: string | null; }; export type ExcalidrawFrameLikeElement = | ExcalidrawFrameElement | ExcalidrawMagicFrameElement; /** * These are elements that don't have any additional properties. */ export type ExcalidrawGenericElement = | ExcalidrawSelectionElement | ExcalidrawRectangleElement | ExcalidrawDiamondElement | ExcalidrawEllipseElement; export type ExcalidrawFlowchartNodeElement = | ExcalidrawRectangleElement | ExcalidrawDiamondElement | ExcalidrawEllipseElement; export type ExcalidrawRectanguloidElement = | ExcalidrawRectangleElement | ExcalidrawImageElement | ExcalidrawTextElement | ExcalidrawFreeDrawElement | ExcalidrawIframeLikeElement | ExcalidrawFrameLikeElement | ExcalidrawEmbeddableElement; /** * ExcalidrawElement should be JSON serializable and (eventually) contain * no computed data. The list of all ExcalidrawElements should be shareable * between peers and contain no state local to the peer. */ export type ExcalidrawElement = | ExcalidrawGenericElement | ExcalidrawTextElement | ExcalidrawLinearElement | ExcalidrawArrowElement | ExcalidrawFreeDrawElement | ExcalidrawImageElement | ExcalidrawFrameElement | ExcalidrawMagicFrameElement | ExcalidrawIframeElement | ExcalidrawEmbeddableElement; export type ExcalidrawNonSelectionElement = Exclude< ExcalidrawElement, ExcalidrawSelectionElement >; export type Ordered = TElement & { index: FractionalIndex; }; export type OrderedExcalidrawElement = Ordered; export type NonDeleted = TElement & { isDeleted: boolean; }; export type NonDeletedExcalidrawElement = NonDeleted; export type ExcalidrawTextElement = _ExcalidrawElementBase & Readonly<{ type: "text"; fontSize: number; fontFamily: FontFamilyValues; text: string; textAlign: TextAlign; verticalAlign: VerticalAlign; containerId: ExcalidrawGenericElement["id"] | null; originalText: string; /** * If `true` the width will fit the text. If `false`, the text will * wrap to fit the width. * * @default true */ autoResize: boolean; /** * Unitless line height (aligned to W3C). To get line height in px, multiply * with font size (using `getLineHeightInPx` helper). */ lineHeight: number & { _brand: "unitlessLineHeight" }; }>; export type ExcalidrawBindableElement = | ExcalidrawRectangleElement | ExcalidrawDiamondElement | ExcalidrawEllipseElement | ExcalidrawTextElement | ExcalidrawImageElement | ExcalidrawIframeElement | ExcalidrawEmbeddableElement | ExcalidrawFrameElement | ExcalidrawMagicFrameElement; export type ExcalidrawTextContainer = | ExcalidrawRectangleElement | ExcalidrawDiamondElement | ExcalidrawEllipseElement | ExcalidrawArrowElement; export type ExcalidrawTextElementWithContainer = { containerId: ExcalidrawTextContainer["id"]; } & ExcalidrawTextElement; export type FixedPoint = [number, number]; export type PointBinding = { elementId: ExcalidrawBindableElement["id"]; focus: number; gap: number; }; export type FixedPointBinding = Merge< PointBinding, { // Represents the fixed point binding information in form of a vertical and // horizontal ratio (i.e. a percentage value in the 0.0-1.0 range). This ratio // gives the user selected fixed point by multiplying the bound element width // with fixedPoint[0] and the bound element height with fixedPoint[1] to get the // bound element-local point coordinate. fixedPoint: FixedPoint; } >; export type Arrowhead = | "arrow" | "bar" | "dot" // legacy. Do not use for new elements. | "circle" | "circle_outline" | "triangle" | "triangle_outline" | "diamond" | "diamond_outline" | "crowfoot_one" | "crowfoot_many" | "crowfoot_one_or_many"; export type ExcalidrawLinearElement = _ExcalidrawElementBase & Readonly<{ type: "line" | "arrow"; points: readonly LocalPoint[]; lastCommittedPoint: LocalPoint | null; startBinding: PointBinding | null; endBinding: PointBinding | null; startArrowhead: Arrowhead | null; endArrowhead: Arrowhead | null; }>; export type FixedSegment = { start: LocalPoint; end: LocalPoint; index: number; }; export type ExcalidrawArrowElement = ExcalidrawLinearElement & Readonly<{ type: "arrow"; elbowed: boolean; }>; export type ExcalidrawElbowArrowElement = Merge< ExcalidrawArrowElement, { elbowed: true; startBinding: FixedPointBinding | null; endBinding: FixedPointBinding | null; fixedSegments: readonly FixedSegment[] | null; /** * Marks that the 3rd point should be used as the 2nd point of the arrow in * order to temporarily hide the first segment of the arrow without losing * the data from the points array. It allows creating the expected arrow * path when the arrow with fixed segments is bound on a horizontal side and * moved to a vertical and vica versa. */ startIsSpecial: boolean | null; /** * Marks that the 3rd point backwards from the end should be used as the 2nd * point of the arrow in order to temporarily hide the last segment of the * arrow without losing the data from the points array. It allows creating * the expected arrow path when the arrow with fixed segments is bound on a * horizontal side and moved to a vertical and vica versa. */ endIsSpecial: boolean | null; } >; export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase & Readonly<{ type: "freedraw"; points: readonly LocalPoint[]; pressures: readonly number[]; simulatePressure: boolean; lastCommittedPoint: LocalPoint | null; }>; export type FileId = string & { _brand: "FileId" }; export type ExcalidrawElementType = ExcalidrawElement["type"]; /** * Map of excalidraw elements. * Unspecified whether deleted or non-deleted. * Can be a subset of Scene elements. */ export type ElementsMap = Map; /** * Map of non-deleted elements. * Can be a subset of Scene elements. */ export type NonDeletedElementsMap = Map< ExcalidrawElement["id"], NonDeletedExcalidrawElement > & MakeBrand<"NonDeletedElementsMap">; /** * Map of all excalidraw Scene elements, including deleted. * Not a subset. Use this type when you need access to current Scene elements. */ export type SceneElementsMap = Map< ExcalidrawElement["id"], Ordered > & MakeBrand<"SceneElementsMap">; /** * Map of all non-deleted Scene elements. * Not a subset. Use this type when you need access to current Scene elements. */ export type NonDeletedSceneElementsMap = Map< ExcalidrawElement["id"], Ordered > & MakeBrand<"NonDeletedSceneElementsMap">; export type ElementsMapOrArray = | readonly ExcalidrawElement[] | Readonly;