diff options
Diffstat (limited to 'packages/excalidraw/element/types.ts')
| -rw-r--r-- | packages/excalidraw/element/types.ts | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/packages/excalidraw/element/types.ts b/packages/excalidraw/element/types.ts new file mode 100644 index 0000000..5965867 --- /dev/null +++ b/packages/excalidraw/element/types.ts @@ -0,0 +1,412 @@ +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<typeof ROUNDNESS>; +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<string, any>; +}>; + +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 extends ExcalidrawElement> = TElement & { + index: FractionalIndex; +}; + +export type OrderedExcalidrawElement = Ordered<ExcalidrawElement>; + +export type NonDeleted<TElement extends ExcalidrawElement> = TElement & { + isDeleted: boolean; +}; + +export type NonDeletedExcalidrawElement = NonDeleted<ExcalidrawElement>; + +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<ExcalidrawElement["id"], ExcalidrawElement>; + +/** + * 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<ExcalidrawElement> +> & + 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<NonDeletedExcalidrawElement> +> & + MakeBrand<"NonDeletedSceneElementsMap">; + +export type ElementsMapOrArray = + | readonly ExcalidrawElement[] + | Readonly<ElementsMap>; |
