@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
1,560 lines (1,486 loc) • 249 kB
TypeScript
import { Atom } from '@tldraw/state';
import { BoxModel } from '@tldraw/tlschema';
import { ComponentType } from 'react';
import { Computed } from '@tldraw/state';
import { Dispatch } from 'react';
import { Editor as Editor_2 } from '@tiptap/core';
import { EditorProviderProps as EditorProviderProps_2 } from '@tiptap/react';
import EventEmitter from 'eventemitter3';
import { ExoticComponent } from 'react';
import { HistoryEntry } from '@tldraw/store';
import { IndexKey } from '@tldraw/utils';
import { JsonObject } from '@tldraw/utils';
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { LegacyMigrations } from '@tldraw/store';
import { MigrationSequence } from '@tldraw/store';
import { NamedExoticComponent } from 'react';
import { Node as Node_2 } from '@tiptap/pm/model';
import { PerformanceTracker } from '@tldraw/utils';
import { PointerEventHandler } from 'react';
import * as React_2 from 'react';
import { default as React_3 } from 'react';
import { ReactElement } from 'react';
import { ReactNode } from 'react';
import { RecordProps } from '@tldraw/tlschema';
import { RecordsDiff } from '@tldraw/store';
import { RefObject } from 'react';
import { SerializedSchema } from '@tldraw/store';
import { SerializedStore } from '@tldraw/store';
import { SetStateAction } from 'react';
import { Signal } from '@tldraw/state';
import { Store } from '@tldraw/store';
import { StoreSchema } from '@tldraw/store';
import { StoreSideEffects } from '@tldraw/store';
import { StyleProp } from '@tldraw/tlschema';
import { StylePropValue } from '@tldraw/tlschema';
import { T } from '@tldraw/validate';
import { Timers } from '@tldraw/utils';
import { TLAsset } from '@tldraw/tlschema';
import { TLAssetId } from '@tldraw/tlschema';
import { TLAssetPartial } from '@tldraw/tlschema';
import { TLAssetStore } from '@tldraw/tlschema';
import { TLBaseShape } from '@tldraw/tlschema';
import { TLBinding } from '@tldraw/tlschema';
import { TLBindingCreate } from '@tldraw/tlschema';
import { TLBindingId } from '@tldraw/tlschema';
import { TLBindingUpdate } from '@tldraw/tlschema';
import { TLBookmarkAsset } from '@tldraw/tlschema';
import { TLCamera } from '@tldraw/tlschema';
import { TLCursor } from '@tldraw/tlschema';
import { TLCursorType } from '@tldraw/tlschema';
import { TLDefaultDashStyle } from '@tldraw/tlschema';
import { TLDefaultHorizontalAlignStyle } from '@tldraw/tlschema';
import { TLDocument } from '@tldraw/tlschema';
import { TLGroupShape } from '@tldraw/tlschema';
import { TLHandle } from '@tldraw/tlschema';
import { TLImageAsset } from '@tldraw/tlschema';
import { TLInstance } from '@tldraw/tlschema';
import { TLInstancePageState } from '@tldraw/tlschema';
import { TLInstancePresence } from '@tldraw/tlschema';
import { TLOpacityType } from '@tldraw/tlschema';
import { TLPage } from '@tldraw/tlschema';
import { TLPageId } from '@tldraw/tlschema';
import { TLParentId } from '@tldraw/tlschema';
import { TLPropsMigrations } from '@tldraw/tlschema';
import { TLRecord } from '@tldraw/tlschema';
import { TLRichText } from '@tldraw/tlschema';
import { TLScribble } from '@tldraw/tlschema';
import { TLShape } from '@tldraw/tlschema';
import { TLShapeCrop } from '@tldraw/tlschema';
import { TLShapeId } from '@tldraw/tlschema';
import { TLShapePartial } from '@tldraw/tlschema';
import { TLStore } from '@tldraw/tlschema';
import { TLStoreProps } from '@tldraw/tlschema';
import { TLStoreSchema } from '@tldraw/tlschema';
import { TLStoreSnapshot } from '@tldraw/tlschema';
import { TLUnknownBinding } from '@tldraw/tlschema';
import { TLUnknownShape } from '@tldraw/tlschema';
import { TLVideoAsset } from '@tldraw/tlschema';
import { UnknownRecord } from '@tldraw/store';
import { VecModel } from '@tldraw/tlschema';
/* Excluded from this release type: activeElementShouldCaptureKeys */
/**
* Get the angle of a point on an arc.
* @param fromAngle - The angle from center to arc's start point (A) on the circle
* @param toAngle - The angle from center to arc's end point (B) on the circle
* @param direction - The direction of the arc (1 = counter-clockwise, -1 = clockwise)
* @returns The distance in radians between the two angles according to the direction
* @public
*/
export declare function angleDistance(fromAngle: number, toAngle: number, direction: number): number;
/* Excluded from this release type: applyRotationToSnapshotShapes */
/**
* Whether two numbers numbers a and b are approximately equal.
*
* @param a - The first point.
* @param b - The second point.
* @public
*/
export declare function approximately(a: number, b: number, precision?: number): boolean;
/** @public */
export declare class Arc2d extends Geometry2d {
private _center;
private _radius;
private _start;
private _end;
private _largeArcFlag;
private _sweepFlag;
private _measure;
private _angleStart;
private _angleEnd;
constructor(config: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {
center: Vec;
end: Vec;
largeArcFlag: number;
start: Vec;
sweepFlag: number;
});
nearestPoint(point: VecLike): Vec;
hitTestLineSegment(A: VecLike, B: VecLike): boolean;
getVertices(): Vec[];
getSvgPathData(first?: boolean): string;
getLength(): number;
}
/**
* Checks whether two angles are approximately at right-angles or parallel to each other
*
* @param a - Angle a (radians)
* @param b - Angle b (radians)
* @returns True iff the angles are approximately at right-angles or parallel to each other
* @public
*/
export declare function areAnglesCompatible(a: number, b: number): boolean;
/** @public */
export declare function average(A: VecLike, B: VecLike): string;
/** @public */
export declare abstract class BaseBoxShapeTool extends StateNode {
static id: string;
static initial: string;
static children(): TLStateNodeConstructor[];
abstract shapeType: string;
onCreate?(_shape: null | TLShape): null | void;
}
/** @public */
export declare abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> extends ShapeUtil<Shape> {
getGeometry(shape: Shape): Geometry2d;
onResize(shape: any, info: TLResizeInfo<any>): any;
getHandleSnapGeometry(shape: Shape): HandleSnapGeometry;
getInterpolatedProps(startShape: Shape, endShape: Shape, t: number): Shape['props'];
}
/**
* Options passed to {@link BindingUtil.onBeforeChange} and {@link BindingUtil.onAfterChange},
* describing the data associated with a binding being changed.
*
* @public
*/
export declare interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
/** The binding record before the change is made. */
bindingBefore: Binding;
/** The binding record after the change is made. */
bindingAfter: Binding;
}
/**
* Options passed to {@link BindingUtil.onBeforeCreate} and {@link BindingUtil.onAfterCreate},
* describing a the creating a binding.
*
* @public
*/
export declare interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
/** The binding being created. */
binding: Binding;
}
/**
* Options passed to {@link BindingUtil.onBeforeDelete} and {@link BindingUtil.onAfterDelete},
* describing a binding being deleted.
*
* @public
*/
export declare interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
/** The binding being deleted. */
binding: Binding;
}
/**
* Options passed to {@link BindingUtil.onAfterChangeFromShape} and
* {@link BindingUtil.onAfterChangeToShape}, describing a bound shape being changed.
*
* @public
*/
export declare interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
/** The binding record linking these two shapes. */
binding: Binding;
/** The shape record before the change is made. */
shapeBefore: TLShape;
/** The shape record after the change is made. */
shapeAfter: TLShape;
/**
* Why did this shape change?
* - 'self': the shape itself changed
* - 'ancestry': the ancestry of the shape changed, but the shape itself may not have done
*/
reason: 'ancestry' | 'self';
}
/**
* Options passed to {@link BindingUtil.onBeforeDeleteFromShape} and
* {@link BindingUtil.onBeforeDeleteToShape}, describing a bound shape that is about to be deleted.
*
* See {@link BindingOnShapeIsolateOptions} for discussion on when to use the delete vs. the isolate
* callbacks.
*
* @public
*/
export declare interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
/** The binding record that refers to the shape in question. */
binding: Binding;
/** The shape that is about to be deleted. */
shape: TLShape;
}
/**
* Options passed to {@link BindingUtil.onBeforeIsolateFromShape} and
* {@link BindingUtil.onBeforeIsolateToShape}, describing a shape that is about to be isolated from
* the one that it's bound to.
*
* Isolation happens whenever two bound shapes are separated. For example
* 1. One is deleted, but the other is not.
* 1. One is copied, but the other is not.
* 1. One is duplicated, but the other is not.
*
* In each of these cases, if the remaining shape depends on the binding for its rendering, it may
* now be in an inconsistent state. For example, tldraw's arrow shape depends on the binding to know
* where the end of the arrow is. If we removed the binding without doing anything else, the arrow
* would suddenly be pointing to the wrong location. Instead, when the shape the arrow is pointing
* to is deleted, or the arrow is copied/duplicated, we use an isolation callback. The callback
* updates the arrow based on the binding that's about to be removed, so it doesn't end up pointing
* to the wrong place.
*
* For this style of consistency update, use isolation callbacks. For actions specific to deletion
* (like deleting a sticker when the shape it's bound to is removed), use the delete callbacks
* ({@link BindingUtil.onBeforeDeleteFromShape} and {@link BindingUtil.onBeforeDeleteToShape})
* instead.
*
* @public
*/
export declare interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding> {
/** The binding record that refers to the shape in question. */
binding: Binding;
/**
* The shape being removed. For deletion, this is the deleted shape. For copy/duplicate, this is
* the shape that _isn't_ being copied/duplicated and is getting left behind.
*/
removedShape: TLShape;
}
/** @public */
export declare abstract class BindingUtil<Binding extends TLUnknownBinding = TLUnknownBinding> {
editor: Editor;
constructor(editor: Editor);
static props?: RecordProps<TLUnknownBinding>;
static migrations?: TLPropsMigrations;
/**
* The type of the binding util, which should match the binding's type.
*
* @public
*/
static type: string;
/**
* Get the default props for a binding.
*
* @public
*/
abstract getDefaultProps(): Partial<Binding['props']>;
/**
* Called whenever a store operation involving this binding type has completed. This is useful
* for working with networks of related bindings that may need to update together.
*
* @example
* ```ts
* class MyBindingUtil extends BindingUtil<MyBinding> {
* changedBindingIds = new Set<TLBindingId>()
*
* onOperationComplete() {
* doSomethingWithChangedBindings(this.changedBindingIds)
* this.changedBindingIds.clear()
* }
*
* onAfterChange({ bindingAfter }: BindingOnChangeOptions<MyBinding>) {
* this.changedBindingIds.add(bindingAfter.id)
* }
* }
* ```
*
* @public
*/
onOperationComplete?(): void;
/**
* Called when a binding is about to be created. See {@link BindingOnCreateOptions} for details.
*
* You can optionally return a new binding to replace the one being created - for example, to
* set different initial props.
*
* @public
*/
onBeforeCreate?(options: BindingOnCreateOptions<Binding>): Binding | void;
/**
* Called after a binding has been created. See {@link BindingOnCreateOptions} for details.
*
* @public
*/
onAfterCreate?(options: BindingOnCreateOptions<Binding>): void;
/**
* Called when a binding is about to be changed. See {@link BindingOnChangeOptions} for details.
*
* Note that this only fires when the binding record is changing, not when the shapes
* associated change. Use {@link BindingUtil.onAfterChangeFromShape} and
* {@link BindingUtil.onAfterChangeToShape} for that.
*
* You can optionally return a new binding to replace the one being changed - for example, to
* enforce constraints on the binding's props.
*
* @public
*/
onBeforeChange?(options: BindingOnChangeOptions<Binding>): Binding | void;
/**
* Called after a binding has been changed. See {@link BindingOnChangeOptions} for details.
*
* Note that this only fires when the binding record is changing, not when the shapes
* associated change. Use {@link BindingUtil.onAfterChangeFromShape} and
* {@link BindingUtil.onAfterChangeToShape} for that.
*
* @public
*/
onAfterChange?(options: BindingOnChangeOptions<Binding>): void;
/**
* Called when a binding is about to be deleted. See {@link BindingOnDeleteOptions} for details.
*
* @public
*/
onBeforeDelete?(options: BindingOnDeleteOptions<Binding>): void;
/**
* Called after a binding has been deleted. See {@link BindingOnDeleteOptions} for details.
*
* @public
*/
onAfterDelete?(options: BindingOnDeleteOptions<Binding>): void;
/**
* Called after the shape referenced in a binding's `fromId` is changed. Use this to propagate
* any changes to the binding itself or the other shape as needed. See
* {@link BindingOnShapeChangeOptions} for details.
*
* @public
*/
onAfterChangeFromShape?(options: BindingOnShapeChangeOptions<Binding>): void;
/**
* Called after the shape referenced in a binding's `toId` is changed. Use this to propagate any
* changes to the binding itself or the other shape as needed. See
* {@link BindingOnShapeChangeOptions} for details.
*
* @public
*/
onAfterChangeToShape?(options: BindingOnShapeChangeOptions<Binding>): void;
/**
* Called before the shape referenced in a binding's `fromId` is about to be deleted. Use this
* with care - you may want to use {@link BindingUtil.onBeforeIsolateToShape} instead. See
* {@link BindingOnShapeDeleteOptions} for details.
*
* @public
*/
onBeforeDeleteFromShape?(options: BindingOnShapeDeleteOptions<Binding>): void;
/**
* Called before the shape referenced in a binding's `toId` is about to be deleted. Use this
* with care - you may want to use {@link BindingUtil.onBeforeIsolateFromShape} instead. See
* {@link BindingOnShapeDeleteOptions} for details.
*
* @public
*/
onBeforeDeleteToShape?(options: BindingOnShapeDeleteOptions<Binding>): void;
/**
* Called before the shape referenced in a binding's `fromId` is about to be isolated from the
* shape referenced in `toId`. See {@link BindingOnShapeIsolateOptions} for discussion on what
* isolation means, and when/how to use this callback.
*/
onBeforeIsolateFromShape?(options: BindingOnShapeIsolateOptions<Binding>): void;
/**
* Called before the shape referenced in a binding's `toId` is about to be isolated from the
* shape referenced in `fromId`. See {@link BindingOnShapeIsolateOptions} for discussion on what
* isolation means, and when/how to use this callback.
*/
onBeforeIsolateToShape?(options: BindingOnShapeIsolateOptions<Binding>): void;
}
/**
* When moving or resizing shapes, the bounds of the shape can snap to key geometry on other nearby
* shapes. Customize how a shape snaps to others with {@link ShapeUtil.getBoundsSnapGeometry}.
*
* @public
*/
export declare interface BoundsSnapGeometry {
/**
* Points that this shape will snap to. By default, this will be the corners and center of the
* shapes bounding box. To disable snapping to a specific point, use an empty array.
*/
points?: VecModel[];
}
/** @public */
export declare interface BoundsSnapPoint {
id: string;
x: number;
y: number;
handle?: SelectionCorner;
}
/** @public */
export declare class BoundsSnaps {
readonly manager: SnapManager;
readonly editor: Editor;
constructor(manager: SnapManager);
private getSnapPointsCache;
getSnapPoints(shapeId: TLShapeId): BoundsSnapPoint[];
private getSnappablePoints;
private getSnappableGapNodes;
private getVisibleGaps;
snapTranslateShapes({ lockedAxis, initialSelectionPageBounds, initialSelectionSnapPoints, dragDelta, }: {
dragDelta: Vec;
initialSelectionPageBounds: Box;
initialSelectionSnapPoints: BoundsSnapPoint[];
lockedAxis: 'x' | 'y' | null;
}): SnapData;
snapResizeShapes({ initialSelectionPageBounds, dragDelta, handle: originalHandle, isAspectRatioLocked, isResizingFromCenter, }: {
dragDelta: Vec;
handle: SelectionCorner | SelectionEdge;
initialSelectionPageBounds: Box;
isAspectRatioLocked: boolean;
isResizingFromCenter: boolean;
}): SnapData;
private collectPointSnaps;
private collectGapSnaps;
private getPointSnapLines;
private getGapSnapLines;
}
/** @public */
export declare class Box {
constructor(x?: number, y?: number, w?: number, h?: number);
x: number;
y: number;
w: number;
h: number;
get point(): Vec;
set point(val: Vec);
get minX(): number;
set minX(n: number);
get left(): number;
get midX(): number;
get maxX(): number;
get right(): number;
get minY(): number;
set minY(n: number);
get top(): number;
get midY(): number;
get maxY(): number;
get bottom(): number;
get width(): number;
set width(n: number);
get height(): number;
set height(n: number);
get aspectRatio(): number;
get center(): Vec;
set center(v: Vec);
get corners(): Vec[];
get cornersAndCenter(): Vec[];
get sides(): Array<[Vec, Vec]>;
get size(): Vec;
toFixed(): this;
setTo(B: Box): this;
set(x?: number, y?: number, w?: number, h?: number): this;
expand(A: Box): this;
expandBy(n: number): this;
scale(n: number): this;
clone(): Box;
translate(delta: VecLike): this;
snapToGrid(size: number): void;
collides(B: Box): boolean;
contains(B: Box): boolean;
includes(B: Box): boolean;
containsPoint(V: VecLike, margin?: number): boolean;
getHandlePoint(handle: SelectionCorner | SelectionEdge): Vec;
toJson(): BoxModel;
resize(handle: SelectionCorner | SelectionEdge | string, dx: number, dy: number): void;
union(box: BoxModel): this;
static From(box: BoxModel): Box;
static FromCenter(center: VecLike, size: VecLike): Box;
static FromPoints(points: VecLike[]): Box;
static Expand(A: Box, B: Box): Box;
static ExpandBy(A: Box, n: number): Box;
static Collides(A: Box, B: Box): boolean;
static Contains(A: Box, B: Box): boolean;
static Includes(A: Box, B: Box): boolean;
static ContainsPoint(A: Box, B: VecLike, margin?: number): boolean;
static Common(boxes: Box[]): Box;
static Sides(A: Box, inset?: number): Vec[][];
static Resize(box: Box, handle: SelectionCorner | SelectionEdge | string, dx: number, dy: number, isAspectRatioLocked?: boolean): {
box: Box;
scaleX: number;
scaleY: number;
};
equals(other: Box | BoxModel): boolean;
static Equals(a: Box | BoxModel, b: Box | BoxModel): boolean;
zeroFix(): this;
static ZeroFix(other: Box | BoxModel): Box;
}
/** @public */
export declare type BoxLike = Box | BoxModel;
/**
* @param a - Any angle in radians
* @returns A number between 0 and 2 * PI
* @public
*/
export declare function canonicalizeRotation(a: number): number;
/* Excluded from this release type: CanvasMaxSize */
/**
* Get the center of a circle from three points.
*
* @param a - The first point
* @param b - The second point
* @param c - The third point
*
* @returns The center of the circle or null if the points are collinear
*
* @public
*/
export declare function centerOfCircleFromThreePoints(a: VecLike, b: VecLike, c: VecLike): null | Vec;
/** @public */
export declare class Circle2d extends Geometry2d {
config: Omit<Geometry2dOptions, 'isClosed'> & {
isFilled: boolean;
radius: number;
x?: number;
y?: number;
};
private _center;
private _radius;
private _x;
private _y;
constructor(config: Omit<Geometry2dOptions, 'isClosed'> & {
isFilled: boolean;
radius: number;
x?: number;
y?: number;
});
getBounds(): Box;
getVertices(): Vec[];
nearestPoint(point: VecLike): Vec;
hitTestLineSegment(A: VecLike, B: VecLike, distance?: number): boolean;
getSvgPathData(): string;
}
/**
* Clamp a value into a range.
*
* @example
*
* ```ts
* const A = clamp(0, 1) // 1
* ```
*
* @param n - The number to clamp.
* @param min - The minimum value.
* @public
*/
export declare function clamp(n: number, min: number): number;
/**
* Clamp a value into a range.
*
* @example
*
* ```ts
* const A = clamp(0, 1, 10) // 1
* const B = clamp(11, 1, 10) // 10
* const C = clamp(5, 1, 10) // 5
* ```
*
* @param n - The number to clamp.
* @param min - The minimum value.
* @param max - The maximum value.
* @public
*/
export declare function clamp(n: number, min: number, max: number): number;
/**
* Clamp radians within 0 and 2PI
*
* @param r - The radian value.
* @public
*/
export declare function clampRadians(r: number): number;
/* Excluded from this release type: clampToBrowserMaxCanvasSize */
/** @public */
export declare class ClickManager {
editor: Editor;
constructor(editor: Editor);
private _clickId;
private _clickTimeout?;
private _clickScreenPoint?;
private _previousScreenPoint?;
_getClickTimeout(state: TLClickState, id?: string): void;
/* Excluded from this release type: _clickState */
/**
* The current click state.
*
* @public
*/
get clickState(): TLClickState | undefined;
lastPointerInfo: TLPointerEventInfo;
handlePointerEvent(info: TLPointerEventInfo): TLClickEventInfo | TLPointerEventInfo;
/* Excluded from this release type: cancelDoubleClickTimeout */
}
/**
* Get the clockwise angle distance between two angles.
*
* @param a0 - The first angle.
* @param a1 - The second angle.
* @public
*/
export declare function clockwiseAngleDist(a0: number, a1: number): number;
/**
* @public
* @react
*/
export declare function ContainerProvider({ container, children }: ContainerProviderProps): JSX_2.Element;
/** @public */
export declare interface ContainerProviderProps {
container: HTMLElement;
children: React.ReactNode;
}
/** @public */
export declare const coreShapes: readonly [typeof GroupShapeUtil];
/**
* Get the counter-clockwise angle distance between two angles.
*
* @param a0 - The first angle.
* @param a1 - The second angle.
* @public
*/
export declare function counterClockwiseAngleDist(a0: number, a1: number): number;
/**
* Converts a deep link descriptor to a url-safe string
*
* @example
* ```ts
* const url = `https://example.com?d=${createDeepLinkString({ type: 'shapes', shapeIds: ['shape:1', 'shape:2'] })}`
* navigator.clipboard.writeText(url)
* ```
*
* @param deepLink - the deep link descriptor
* @returns a url-safe string
*
* @public
*/
export declare function createDeepLinkString(deepLink: TLDeepLink): string;
/**
* Creates a signal of the instance state for a given store.
* @public
* @param store - The store to create the instance state snapshot signal for
* @returns
*/
export declare function createSessionStateSnapshotSignal(store: TLStore): Signal<null | TLSessionStateSnapshot>;
/**
* A helper for creating a TLStore schema from either an object with shapeUtils, bindingUtils, and
* migrations, or a schema.
*
* @param opts - Options for creating the schema.
*
* @public
*/
export declare function createTLSchemaFromUtils(opts: TLStoreSchemaOptions): StoreSchema<TLRecord, TLStoreProps>;
/**
* A helper for creating a TLStore.
*
* @param opts - Options for creating the store.
*
* @public
*/
export declare function createTLStore({ initialData, defaultName, id, assets, onMount, collaboration, ...rest }?: TLStoreOptions): TLStore;
/** @public */
export declare function createTLUser(opts?: {
setUserPreferences?: (userPreferences: TLUserPreferences) => void;
userPreferences?: Signal<TLUserPreferences>;
}): TLUser;
/** @public */
export declare class CubicBezier2d extends Polyline2d {
private _a;
private _b;
private _c;
private _d;
private _resolution;
constructor(config: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {
cp1: Vec;
cp2: Vec;
end: Vec;
resolution?: number;
start: Vec;
});
getVertices(): Vec[];
nearestPoint(A: VecLike): Vec;
getSvgPathData(first?: boolean): string;
static GetAtT(segment: CubicBezier2d, t: number): Vec;
getLength(_filters?: Geometry2dFilters, precision?: number): number;
}
/** @public */
export declare class CubicSpline2d extends Geometry2d {
private _points;
constructor(config: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {
points: Vec[];
});
private _segments?;
get segments(): CubicBezier2d[];
getLength(): number;
getVertices(): Vec[];
nearestPoint(A: VecLike): Vec;
hitTestLineSegment(A: VecLike, B: VecLike): boolean;
getSvgPathData(): string;
}
/** @public */
export declare function dataUrlToFile(url: string, filename: string, mimeType: string): Promise<File>;
/**
* @deprecated Licensing is now enabled in the tldraw SDK.
* @public */
export declare function debugEnableLicensing(): void;
/* Excluded from this release type: DebugFlag */
/* Excluded from this release type: DebugFlagDef */
/* Excluded from this release type: DebugFlagDefaults */
/* Excluded from this release type: debugFlags */
/* Excluded from this release type: DEFAULT_ANIMATION_OPTIONS */
/* Excluded from this release type: DEFAULT_CAMERA_OPTIONS */
/** @public @react */
export declare function DefaultBackground(): JSX_2.Element;
/** @public @react */
export declare const DefaultBrush: ({ brush, color, opacity, className }: TLBrushProps) => JSX_2.Element;
/** @public @react */
export declare function DefaultCanvas({ className }: TLCanvasComponentProps): JSX_2.Element;
/** @public @react */
export declare function DefaultCollaboratorHint({ className, zoom, point, color, viewport, opacity, }: TLCollaboratorHintProps): JSX_2.Element;
/** @public @react */
export declare const DefaultCursor: NamedExoticComponent<TLCursorProps>;
/** @public @react */
export declare const DefaultErrorFallback: TLErrorFallbackComponent;
/** @public @react */
export declare function DefaultGrid({ x, y, z, size }: TLGridProps): JSX_2.Element;
/** @public @react */
export declare function DefaultHandle({ handle, isCoarse, className, zoom }: TLHandleProps): JSX_2.Element;
/** @public @react */
export declare const DefaultHandles: ({ children }: TLHandlesProps) => JSX_2.Element;
/** @public @react */
export declare function DefaultScribble({ scribble, zoom, color, opacity, className }: TLScribbleProps): JSX_2.Element | null;
/** @public @react */
export declare function DefaultSelectionBackground({ bounds, rotation }: TLSelectionBackgroundProps): JSX_2.Element;
/** @public @react */
export declare function DefaultSelectionForeground({ bounds, rotation }: TLSelectionForegroundProps): JSX_2.Element;
/** @public @react */
export declare const DefaultShapeIndicator: NamedExoticComponent<TLShapeIndicatorProps>;
/** @public @react */
export declare const DefaultShapeIndicators: NamedExoticComponent<TLShapeIndicatorsProps>;
/** @public @react */
export declare function DefaultSnapIndicator({ className, line, zoom }: TLSnapIndicatorProps): JSX_2.Element;
/** @public @react */
export declare function DefaultSpinner(props: React.SVGProps<SVGSVGElement>): JSX_2.Element;
/** @public @react */
export declare const DefaultSvgDefs: () => null;
/** @public */
export declare const defaultTldrawOptions: {
readonly actionShortcutsLocation: "swap";
readonly adjacentShapeMargin: 10;
readonly animationMediumMs: 320;
readonly cameraMovingTimeoutMs: 64;
readonly cameraSlideFriction: 0.09;
readonly coarseDragDistanceSquared: 36;
readonly coarseHandleRadius: 20;
readonly coarsePointerWidth: 12;
readonly collaboratorCheckIntervalMs: 1200;
readonly collaboratorIdleTimeoutMs: 3000;
readonly collaboratorInactiveTimeoutMs: 60000;
readonly createTextOnCanvasDoubleClick: true;
readonly defaultSvgPadding: 32;
readonly doubleClickDurationMs: 450;
readonly dragDistanceSquared: 16;
readonly edgeScrollDelay: 200;
readonly edgeScrollDistance: 8;
readonly edgeScrollEaseDuration: 200;
readonly edgeScrollSpeed: 25;
readonly enableToolbarKeyboardShortcuts: true;
readonly exportProvider: ExoticComponent< {
children?: ReactNode | undefined;
}>;
readonly flattenImageBoundsExpand: 64;
readonly flattenImageBoundsPadding: 16;
readonly followChaseViewportSnap: 2;
readonly gridSteps: readonly [{
readonly mid: 0.15;
readonly min: -1;
readonly step: 64;
}, {
readonly mid: 0.375;
readonly min: 0.05;
readonly step: 16;
}, {
readonly mid: 1;
readonly min: 0.15;
readonly step: 4;
}, {
readonly mid: 2.5;
readonly min: 0.7;
readonly step: 1;
}];
readonly handleRadius: 12;
readonly hitTestMargin: 8;
readonly laserDelayMs: 1200;
readonly longPressDurationMs: 500;
readonly maxExportDelayMs: 5000;
readonly maxFilesAtOnce: 100;
readonly maxFontsToLoadBeforeRender: number;
readonly maxPages: 40;
readonly maxShapesPerPage: 4000;
readonly multiClickDurationMs: 200;
readonly nonce: undefined;
readonly temporaryAssetPreviewLifetimeMs: 180000;
readonly textShadowLod: 0.35;
};
/** @public */
export declare const defaultUserPreferences: Readonly<{
animationSpeed: 0 | 1;
areKeyboardShortcutsEnabled: true;
color: "#02B1CC" | "#11B3A3" | "#39B178" | "#55B467" | "#7B66DC" | "#9D5BD2" | "#BD54C6" | "#E34BA9" | "#EC5E41" | "#F04F88" | "#F2555A" | "#FF802B";
colorScheme: "light";
edgeScrollSpeed: 1;
isDynamicSizeMode: false;
isPasteAtCursorMode: false;
isSnapMode: false;
isWrapMode: false;
locale: "ar" | "bn" | "ca" | "cs" | "da" | "de" | "el" | "en" | "es" | "fa" | "fi" | "fr" | "gl" | "gu-in" | "he" | "hi-in" | "hr" | "hu" | "id" | "it" | "ja" | "km-kh" | "kn" | "ko-kr" | "ml" | "mr" | "ms" | "ne" | "nl" | "no" | "pa" | "pl" | "pt-br" | "pt-pt" | "ro" | "ru" | "sl" | "so" | "sv" | "ta" | "te" | "th" | "tl" | "tr" | "uk" | "ur" | "vi" | "zh-cn" | "zh-tw";
name: "";
}>;
/**
* Convert degrees to radians.
*
* @param d - The degree in degrees.
* @public
*/
export declare function degreesToRadians(d: number): number;
/** @public */
export declare const EASINGS: {
readonly easeInCubic: (t: number) => number;
readonly easeInExpo: (t: number) => number;
readonly easeInOutCubic: (t: number) => number;
readonly easeInOutExpo: (t: number) => number;
readonly easeInOutQuad: (t: number) => number;
readonly easeInOutQuart: (t: number) => number;
readonly easeInOutQuint: (t: number) => number;
readonly easeInOutSine: (t: number) => number;
readonly easeInQuad: (t: number) => number;
readonly easeInQuart: (t: number) => number;
readonly easeInQuint: (t: number) => number;
readonly easeInSine: (t: number) => number;
readonly easeOutCubic: (t: number) => number;
readonly easeOutExpo: (t: number) => number;
readonly easeOutQuad: (t: number) => number;
readonly easeOutQuart: (t: number) => number;
readonly easeOutQuint: (t: number) => number;
readonly easeOutSine: (t: number) => number;
readonly linear: (t: number) => number;
};
/** @public */
export declare class Edge2d extends Geometry2d {
private _start;
private _end;
private _d;
private _u;
private _ul;
constructor(config: {
end: Vec;
start: Vec;
});
getLength(): number;
getVertices(): Vec[];
nearestPoint(point: VecLike): Vec;
getSvgPathData(first?: boolean): string;
}
/** @public */
export declare class EdgeScrollManager {
editor: Editor;
constructor(editor: Editor);
private _isEdgeScrolling;
private _edgeScrollDuration;
/**
* Update the camera position when the mouse is close to the edge of the screen.
* Run this on every tick when in a state where edge scrolling is enabled.
*
* @public
*/
updateEdgeScrolling(elapsed: number): void;
/* Excluded from this release type: getEdgeProximityFactors */
private getEdgeScroll;
/**
* Moves the camera when the mouse is close to the edge of the screen.
* @public
*/
private moveCameraWhenCloseToEdge;
}
/** @public */
export declare class Editor extends EventEmitter<TLEventMap> {
readonly id: string;
constructor({ store, user, shapeUtils, bindingUtils, tools, getContainer, cameraOptions, textOptions, initialState, autoFocus, inferDarkMode, options, isShapeHidden, getShapeVisibility, fontAssetUrls, }: TLEditorOptions);
private readonly _getShapeVisibility?;
private getIsShapeHiddenCache;
isShapeHidden(shapeOrId: TLShape | TLShapeId): boolean;
readonly options: TldrawOptions;
readonly contextId: string;
/**
* The editor's store
*
* @public
*/
readonly store: TLStore;
/**
* The root state of the statechart.
*
* @public
*/
readonly root: StateNode;
/**
* A set of functions to call when the app is disposed.
*
* @public
*/
readonly disposables: Set<() => void>;
/**
* Whether the editor is disposed.
*
* @public
*/
isDisposed: boolean;
/* Excluded from this release type: _tickManager */
/**
* A manager for the app's snapping feature.
*
* @public
*/
readonly snaps: SnapManager;
/**
* A manager for the any asynchronous events and making sure they're
* cleaned up upon disposal.
*
* @public
*/
readonly timers: {
dispose: () => void;
requestAnimationFrame: (callback: FrameRequestCallback) => number;
setInterval: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
setTimeout: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
};
/**
* A manager for the user and their preferences.
*
* @public
*/
readonly user: UserPreferencesManager;
/**
* A helper for measuring text.
*
* @public
*/
readonly textMeasure: TextManager;
/**
* A utility for managing the set of fonts that should be rendered in the document.
*
* @public
*/
readonly fonts: FontManager;
/**
* A manager for the editor's environment.
*
* @deprecated This is deprecated and will be removed in a future version. Use the `tlenv` global export instead.
* @public
*/
readonly environment: {
hasCanvasSupport: boolean;
isAndroid: boolean;
isChromeForIos: boolean;
isDarwin: boolean;
isFirefox: boolean;
isIos: boolean;
isSafari: boolean;
isWebview: boolean;
};
/**
* A manager for the editor's scribbles.
*
* @public
*/
readonly scribbles: ScribbleManager;
/**
* A manager for side effects and correct state enforcement. See {@link @tldraw/store#StoreSideEffects} for details.
*
* @public
*/
readonly sideEffects: StoreSideEffects<TLRecord>;
/**
* A manager for moving the camera when the mouse is at the edge of the screen.
*
* @public
*/
edgeScrollManager: EdgeScrollManager;
/* Excluded from this release type: focusManager */
/**
* The current HTML element containing the editor.
*
* @example
* ```ts
* const container = editor.getContainer()
* ```
*
* @public
*/
getContainer: () => HTMLElement;
/**
* Dispose the editor.
*
* @public
*/
dispose(): void;
/**
* A map of shape utility classes (TLShapeUtils) by shape type.
*
* @public
*/
shapeUtils: {
readonly [K in string]?: ShapeUtil<TLUnknownShape>;
};
styleProps: {
[key: string]: Map<StyleProp<any>, string>;
};
/**
* Get a shape util from a shape itself.
*
* @example
* ```ts
* const util = editor.getShapeUtil(myArrowShape)
* const util = editor.getShapeUtil('arrow')
* const util = editor.getShapeUtil<TLArrowShape>(myArrowShape)
* const util = editor.getShapeUtil(TLArrowShape)('arrow')
* ```
*
* @param shape - A shape, shape partial, or shape type.
*
* @public
*/
getShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): ShapeUtil<S>;
getShapeUtil<S extends TLUnknownShape>(type: S['type']): ShapeUtil<S>;
getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T;
/**
* Returns true if the editor has a shape util for the given shape / shape type.
*
* @param shape - A shape, shape partial, or shape type.
*/
hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean;
hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean;
hasShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): boolean;
/**
* A map of shape utility classes (TLShapeUtils) by shape type.
*
* @public
*/
bindingUtils: {
readonly [K in string]?: BindingUtil<TLUnknownBinding>;
};
/**
* Get a binding util from a binding itself.
*
* @example
* ```ts
* const util = editor.getBindingUtil(myArrowBinding)
* const util = editor.getBindingUtil('arrow')
* const util = editor.getBindingUtil<TLArrowBinding>(myArrowBinding)
* const util = editor.getBindingUtil(TLArrowBinding)('arrow')
* ```
*
* @param binding - A binding, binding partial, or binding type.
*
* @public
*/
getBindingUtil<S extends TLUnknownBinding>(binding: {
type: S['type'];
} | S): BindingUtil<S>;
getBindingUtil<S extends TLUnknownBinding>(type: S['type']): BindingUtil<S>;
getBindingUtil<T extends BindingUtil>(type: T extends BindingUtil<infer R> ? R['type'] : string): T;
/**
* A manager for the app's history.
*
* @readonly
*/
protected readonly history: HistoryManager<TLRecord>;
/**
* Undo to the last mark.
*
* @example
* ```ts
* editor.undo()
* ```
*
* @public
*/
undo(): this;
/**
* Whether the app can undo.
*
* @public
*/
getCanUndo(): boolean;
/**
* Redo to the next mark.
*
* @example
* ```ts
* editor.redo()
* ```
*
* @public
*/
redo(): this;
clearHistory(): this;
/**
* Whether the app can redo.
*
* @public
*/
getCanRedo(): boolean;
/**
* Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
* any redos.
*
* @example
* ```ts
* editor.mark()
* editor.mark('flip shapes')
* ```
*
* @param markId - The mark's id, usually the reason for adding the mark.
*
* @public
* @deprecated use {@link Editor.markHistoryStoppingPoint} instead
*/
mark(markId?: string): this;
/**
* Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
* any redos. You typically want to do this just before a user interaction begins or is handled.
*
* @example
* ```ts
* editor.markHistoryStoppingPoint()
* editor.flipShapes(editor.getSelectedShapes())
* ```
* @example
* ```ts
* const beginRotateMark = editor.markHistoryStoppingPoint()
* // if the use cancels the rotation, you can bail back to this mark
* editor.bailToMark(beginRotateMark)
* ```
*
* @public
* @param name - The name of the mark, useful for debugging the undo/redo stacks
* @returns a unique id for the mark that can be used with `squashToMark` or `bailToMark`.
*/
markHistoryStoppingPoint(name?: string): string;
/* Excluded from this release type: getMarkIdMatching */
/**
* Coalesces all changes since the given mark into a single change, removing any intermediate marks.
*
* This is useful if you need to 'compress' the recent history to simplify the undo/redo experience of a complex interaction.
*
* @example
* ```ts
* const bumpShapesMark = editor.markHistoryStoppingPoint()
* // ... some changes
* editor.squashToMark(bumpShapesMark)
* ```
*
* @param markId - The mark id to squash to.
*/
squashToMark(markId: string): this;
/**
* Undo to the closest mark, discarding the changes so they cannot be redone.
*
* @example
* ```ts
* editor.bail()
* ```
*
* @public
*/
bail(): this;
/**
* Undo to the given mark, discarding the changes so they cannot be redone.
*
* @example
* ```ts
* const beginDrag = editor.markHistoryStoppingPoint()
* // ... some changes
* editor.bailToMark(beginDrag)
* ```
*
* @public
*/
bailToMark(id: string): this;
private _shouldIgnoreShapeLock;
/**
* Run a function in a transaction with optional options for context.
* You can use the options to change the way that history is treated
* or allow changes to locked shapes.
*
* @example
* ```ts
* // updating with
* editor.run(() => {
* editor.updateShape({ ...myShape, x: 100 })
* }, { history: "ignore" })
*
* // forcing changes / deletions for locked shapes
* editor.toggleLock([myShape])
* editor.run(() => {
* editor.updateShape({ ...myShape, x: 100 })
* editor.deleteShape(myShape)
* }, { ignoreShapeLock: true }, )
* ```
*
* @param fn - The callback function to run.
* @param opts - The options for the batch.
*
*
* @public
*/
run(fn: () => void, opts?: TLEditorRunOptions): this;
/**
* @deprecated Use `Editor.run` instead.
*/
batch(fn: () => void, opts?: TLEditorRunOptions): this;
/* Excluded from this release type: annotateError */
/* Excluded from this release type: createErrorAnnotations */
/* Excluded from this release type: _crashingError */
/* Excluded from this release type: getCrashingError */
/* Excluded from this release type: crash */
/**
* The editor's current path of active states.
*
* @example
* ```ts
* editor.getPath() // "select.idle"
* ```
*
* @public
*/
getPath(): string;
/**
* Get whether a certain tool (or other state node) is currently active.
*
* @example
* ```ts
* editor.isIn('select')
* editor.isIn('select.brushing')
* ```
*
* @param path - The path of active states, separated by periods.
*
* @public
*/
isIn(path: string): boolean;
/**
* Get whether the state node is in any of the given active paths.
*
* @example
* ```ts
* state.isInAny('select', 'erase')
* state.isInAny('select.brushing', 'erase.idle')
* ```
*
* @public
*/
isInAny(...paths: string[]): boolean;
/**
* Set the selected tool.
*
* @example
* ```ts
* editor.setCurrentTool('hand')
* editor.setCurrentTool('hand', { date: Date.now() })
* ```
*
* @param id - The id of the tool to select.
* @param info - Arbitrary data to pass along into the transition.
*
* @public
*/
setCurrentTool(id: string, info?: {}): this;
/**
* The current selected tool.
*
* @public
*/
getCurrentTool(): StateNode;
/**
* The id of the current selected tool.
*
* @public
*/
getCurrentToolId(): string;
/**
* Get a descendant by its path.
*
* @example
* ```ts
* editor.getStateDescendant('select')
* editor.getStateDescendant('select.brushing')
* ```
*
* @param path - The descendant's path of state ids, separated by periods.
*
* @public
*/
getStateDescendant<T extends StateNode>(path: string): T | undefined;
/**
* The global document settings that apply to all users.
*
* @public
**/
getDocumentSettings(): TLDocument;
/**
* Update the global document settings that apply to all users.
*
* @public
**/
updateDocumentSettings(settings: Partial<TLDocument>): this;
/**
* The current instance's state.
*
* @public
*/
getInstanceState(): TLInstance;
/**
* Update the instance's state.
*
* @param partial - A partial object to update the instance state with.
* @param historyOptions - History batch options.
*
* @public
*/
updateInstanceState(partial: Partial<Omit<TLInstance, 'currentPageId'>>, historyOptions?: TLHistoryBatchOptions): this;
/* Excluded from this release type: _updateInstanceState */
/* Excluded from this release type: _isChangingStyleTimeout */
menus: {
addOpenMenu: (id: string) => void;
clearOpenMenus: () => void;
deleteOpenMenu: (id: string) => void;
getOpenMenus: () => string[];
hasAnyOpenMenus: () => boolean;
hasOpenMenus: () => boolean;
isMenuOpen: (id: string) => boolean;
};
/**
* @deprecated Use `editor.menus.getOpenMenus` instead.
*
* @public
*/
getOpenMenus(): string[];
/**
* @deprecated Use `editor.menus.addOpenMenu` instead.
*
* @public
*/
addOpenMenu(id: string): this;
/**
* @deprecated Use `editor.menus.deleteOpenMenu` instead.
*
* @public
*/
deleteOpenMenu(id: string): this;
/**
* @deprecated Use `editor.menus.clearOpenMenus` instead.
*
* @public
*/
clearOpenMenus(): this;
/**
* @deprecated Use `editor.menus.hasAnyOpenMenus` instead.
*
* @public
*/
getIsMenuOpen(): boolean;
/**
* Set the cursor.
*
* @param cursor - The cursor to set.
* @public
*/
setCursor(cursor: Partial<TLCursor>): this;
/**
* Page states.
*
* @public
*/
getPageStates(): TLInstancePageState[];
/* Excluded from this release type: _getPageStatesQuery */
/**
* The current page state.
*
* @public
*/
getCurrentPageState(): TLInstancePageState;
/* Excluded from this release type: _getCurrentPageStateId */
/**
* Update this instance's page state.
*
* @example
* ```ts
* editor.updateCurrentPageState({ id: 'page1', editingShapeId: 'shape:123' })
* ```
*
* @param partial - The partial of the page state object containing the changes.
*
* @public
*/
updateCurrentPageState(partial: Partial<Omit<TLInstancePageState, 'editingShapeId' | 'focusedGroupId' | 'pageId' | 'selectedShapeIds'>>): this;
_updateCurrentPageState(partial: Partial<Omit<TLInstancePageState, 'selectedShapeIds'>>): void;
/**
* The current selected ids.
*
* @public
*/
getSelectedShapeIds(): TLShapeId[];
/**
* An array containing all of the currently selected shapes.
*
* @public
* @readonly
*/
getSelectedShapes(): TLShape[];
/**
* Select one or more shapes.
*
* @example
* ```ts
* editor.setSelectedShapes(['id1'])
* editor.setSelectedShapes(['id1', 'id2'])
* ```
*
* @param shapes - The shape (or shape ids) to select.
*
* @public
*/
setSelectedShapes(shapes: TLShape[] | TLShapeId[]): this;
/**
* Determine whether or not any of a shape's ancestors are selected.
*
* @param shape - The shape (or shape id) of the shape to check.
*
* @public
*/
isAncestorSelected(shape: TLShape | TLShapeId): boolean;
/**
* Select one or more shapes.
*
* @example
* ```ts
* editor.select('id1')
* editor.select('id1', 'id2')
* ```
*
* @param shapes - The shape (or the shape ids) to select.
*
* @public
*/
select(...shapes: TLShape[] | TLShapeId[]): this;
/**
* Remove a shape from the existing set of selected shapes.
*
* @example
* ```ts
* editor.deselect(shape.id)
* ```
*
* @public
*/
deselect(...shapes: TLShape[] | TLShapeId[]): this;
/**
* Select all shapes. If the user has selected shapes that share a parent,
* select all shapes within that parent. If the user has not selected any shapes,
* or if the shapes