From 3e2f2e0884383ff13fffea474362144d827202ff Mon Sep 17 00:00:00 2001 From: Lu Wilson Date: Wed, 14 Jun 2023 07:40:10 +0100 Subject: [PATCH] Add tsdocs to Editor methods (#1581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR does a first-pass of adding tsdocs to the methods of the Editor class. It's a minimal start — just descriptions of them, and their parameters. It makes the Editor docs page a lot more fleshed out though, and easier to quickly scan. There's still a lot more to do! ### Change Type - [x] `documentation` — Changes to the documentation only[^2] ### Release Notes - [dev] Added initial documentation for the Editor class. --------- Co-authored-by: Steve Ruiz --- apps/examples/e2e/shared-e2e.ts | 2 +- packages/editor/api-report.md | 55 +- packages/editor/src/lib/TldrawEditor.tsx | 24 +- packages/editor/src/lib/editor/Editor.ts | 730 +++++++++++++++++------ 4 files changed, 546 insertions(+), 265 deletions(-) diff --git a/apps/examples/e2e/shared-e2e.ts b/apps/examples/e2e/shared-e2e.ts index 679f7377b..6acd0830d 100644 --- a/apps/examples/e2e/shared-e2e.ts +++ b/apps/examples/e2e/shared-e2e.ts @@ -35,7 +35,7 @@ export async function cleanup({ page }: PlaywrightTestArgs) { export async function setupPage(page: PlaywrightTestArgs['page']) { await page.goto('http://localhost:5420/end-to-end') await page.waitForSelector('.tl-canvas') - await page.evaluate(() => (editor.enableAnimations = false)) + await page.evaluate(() => editor.setAnimationSpeed(0)) } export async function setupPageWithShapes(page: PlaywrightTestArgs['page']) { diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index be3afdb77..8cc7111d1 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -372,9 +372,7 @@ export class Editor extends EventEmitter { duration?: number; ease?: (t: number) => number; }): this; - // (undocumented) animateToShape(shapeId: TLShapeId, opts?: TLAnimationOptions): this; - // (undocumented) get animationSpeed(): number; // @internal (undocumented) annotateError(error: unknown, { origin, willCrashApp, tags, extras, }: { @@ -390,7 +388,6 @@ export class Editor extends EventEmitter { blur(): this; bringForward(ids?: TLShapeId[]): this; bringToFront(ids?: TLShapeId[]): this; - // (undocumented) get brush(): Box2dModel | null; get camera(): TLCamera; cancel(): this; @@ -435,28 +432,23 @@ export class Editor extends EventEmitter { get currentPage(): TLPage; get currentPageId(): TLPageId; get currentToolId(): string; - // (undocumented) get cursor(): TLCursor; deleteAssets(ids: TLAssetId[]): this; deleteOpenMenu(id: string): this; deletePage(id: TLPageId): void; deleteShapes(ids?: TLShapeId[]): this; deselect(...ids: TLShapeId[]): this; - // (undocumented) get devicePixelRatio(): number; dispatch(info: TLEventInfo): this; readonly disposables: Set<() => void>; dispose(): void; distributeShapes(operation: 'horizontal' | 'vertical', ids?: TLShapeId[]): this; get documentSettings(): TLDocument; - // (undocumented) - duplicatePage(id?: TLPageId, createId?: TLPageId): void; + duplicatePage(id?: TLPageId, createId?: TLPageId): this; duplicateShapes(ids?: TLShapeId[], offset?: VecLike): this; get editingId(): null | TLShapeId; // (undocumented) get editingShape(): null | TLUnknownShape; - // (undocumented) - enableAnimations: boolean; get erasingIds(): TLShapeId[]; get erasingIdsSet(): Set; // (undocumented) @@ -465,9 +457,7 @@ export class Editor extends EventEmitter { findCommonAncestor(shapes: TLShape[], predicate?: (shape: TLShape) => boolean): TLShapeId | undefined; flipShapes(operation: 'horizontal' | 'vertical', ids?: TLShapeId[]): this; focus(): this; - // (undocumented) get focusLayerId(): TLPageId | TLShapeId; - // (undocumented) get focusLayerShape(): TLShape | undefined; getAncestors(shape: TLShape, acc?: TLShape[]): TLShape[]; getAncestorsById(id: TLShapeId, acc?: TLShape[]): TLShape[]; @@ -481,24 +471,20 @@ export class Editor extends EventEmitter { getBoundsById(id: TLShapeId): Box2d | undefined; getClipPathById(id: TLShapeId): string | undefined; getContainer: () => HTMLElement; - // (undocumented) getContent(ids?: TLShapeId[]): TLContent | undefined; getCssColor(id: TLColorStyle['id']): string; getDeltaInParentSpace(shape: TLShape, delta: VecLike): Vec2d; getDeltaInShapeSpace(shape: TLShape, delta: VecLike): Vec2d; - // (undocumented) getDroppingShape(point: VecLike, droppingShapes?: TLShape[]): TLUnknownShape | undefined; - // (undocumented) getHighestIndexForParent(parentId: TLPageId | TLShapeId): string; getMaskedPageBounds(shape: TLShape): Box2d | undefined; getMaskedPageBoundsById(id: TLShapeId): Box2d | undefined; - // (undocumented) getOutermostSelectableShape(shape: TLShape, filter?: (shape: TLShape) => boolean): TLShape; getOutline(shape: TLShape): Vec2dModel[]; getOutlineById(id: TLShapeId): Vec2dModel[]; getPageBounds(shape: TLShape): Box2d | undefined; getPageBoundsById(id: TLShapeId): Box2d | undefined; - getPageById(id: TLPage['id']): TLPage | undefined; + getPageById(id: TLPageId): TLPage | undefined; getPageCenter(shape: TLShape): null | Vec2d; getPageCenterById(id: TLShapeId): null | Vec2d; getPageCorners(shape: TLShape): Vec2d[]; @@ -510,7 +496,6 @@ export class Editor extends EventEmitter { getPageStateByPageId(id: TLPageId): TLInstancePageState | undefined; getPageTransform(shape: TLShape): Matrix2d | undefined; getPageTransformById(id: TLShapeId): Matrix2d | undefined; - // (undocumented) getParentIdForNewShapeAtPoint(point: VecLike, shapeType: TLShape['type']): TLPageId | TLShapeId; getParentPageId(shape?: TLShape): TLPageId | undefined; getParentShape(shape?: TLShape): TLShape | undefined; @@ -518,7 +503,6 @@ export class Editor extends EventEmitter { getParentTransform(shape: TLShape): Matrix2d; getPointInParentSpace(shapeId: TLShapeId, point: VecLike): Vec2d; getPointInShapeSpace(shape: TLShape, point: VecLike): Vec2d; - // (undocumented) getShapeAndDescendantIds(ids: TLShapeId[]): Set; getShapeById(id: TLParentId): T | undefined; getShapeIdsInPage(pageId: TLPageId): Set; @@ -531,7 +515,6 @@ export class Editor extends EventEmitter { getSortedChildIds(parentId: TLParentId): TLShapeId[]; getStateDescendant(path: string): StateNode | undefined; getStrokeWidth(id: TLSizeStyle['id']): number; - // (undocumented) getSvg(ids?: TLShapeId[], opts?: Partial<{ scale: number; background: boolean; @@ -540,16 +523,12 @@ export class Editor extends EventEmitter { preserveAspectRatio: React.SVGAttributes['preserveAspectRatio']; }>): Promise; getTransform(shape: TLShape): Matrix2d; - // (undocumented) get gridSize(): number; - // (undocumented) groupShapes(ids?: TLShapeId[], groupId?: TLShapeId): this; hasAncestor(shape: TLShape | undefined, ancestorId: TLShapeId): boolean; get hintingIds(): TLShapeId[]; readonly history: HistoryManager; - // (undocumented) get hoveredId(): null | TLShapeId; - // (undocumented) get hoveredShape(): null | TLUnknownShape; inputs: { originPagePoint: Vec2d; @@ -578,21 +557,16 @@ export class Editor extends EventEmitter { readonly isChromeForIos: boolean; get isCoarsePointer(): boolean; set isCoarsePointer(v: boolean); - // (undocumented) get isDarkMode(): boolean; get isFocused(): boolean; - // (undocumented) get isFocusMode(): boolean; - // (undocumented) get isGridMode(): boolean; isIn(path: string): boolean; isInAny(...paths: string[]): boolean; readonly isIos: boolean; get isMenuOpen(): boolean; - // (undocumented) get isPenMode(): boolean; isPointInShape(point: VecLike, shape: TLShape): boolean; - // (undocumented) get isReadOnly(): boolean; readonly isSafari: boolean; isSelected(id: TLShapeId): boolean; @@ -603,9 +577,7 @@ export class Editor extends EventEmitter { type: string; }): shape is T; isShapeOrAncestorLocked(shape?: TLShape): boolean; - // (undocumented) get isSnapMode(): boolean; - // (undocumented) get isToolLocked(): boolean; isWithinSelection(id: TLShapeId): boolean; get locale(): string; @@ -613,7 +585,6 @@ export class Editor extends EventEmitter { moveShapesToPage(ids: TLShapeId[], pageId: TLPageId): this; nudgeShapes(ids: TLShapeId[], direction: Vec2dModel, major?: boolean, ephemeral?: boolean): this; get onlySelectedShape(): null | TLShape; - // (undocumented) get opacity(): null | number; get openMenus(): string[]; packShapes(ids?: TLShapeId[], padding?: number): this; @@ -626,13 +597,11 @@ export class Editor extends EventEmitter { }; pan(dx: number, dy: number, opts?: TLAnimationOptions): this; panZoomIntoView(ids: TLShapeId[], opts?: TLAnimationOptions): this; - // (undocumented) popFocusLayer(): this; // @internal (undocumented) get projectName(): string; // @internal get props(): null | TLNullableShapeProps; - // (undocumented) putContent(content: TLContent, options?: { point?: VecLike; select?: boolean; @@ -653,10 +622,8 @@ export class Editor extends EventEmitter { }[]; reorderShapes(operation: 'backward' | 'forward' | 'toBack' | 'toFront', ids: TLShapeId[]): this; reparentShapesById(ids: TLShapeId[], parentId: TLParentId, insertIndex?: string): this; - // (undocumented) replaceStoreContentsWithRecordsForOtherDocument(records: TLRecord[]): void; resetZoom(point?: Vec2d, opts?: TLAnimationOptions): this; - // (undocumented) resizeShape(id: TLShapeId, scale: VecLike, options?: { initialBounds?: Box2d; scaleOrigin?: VecLike; @@ -673,7 +640,6 @@ export class Editor extends EventEmitter { y: number; z: number; }; - // (undocumented) get scribble(): null | TLScribble; select(...ids: TLShapeId[]): this; selectAll(): this; @@ -681,49 +647,38 @@ export class Editor extends EventEmitter { get selectedIdsSet(): ReadonlySet; get selectedPageBounds(): Box2d | null; get selectedShapes(): TLShape[]; - // (undocumented) get selectionBounds(): Box2d | undefined; - // (undocumented) get selectionPageCenter(): null | Vec2d; get selectionRotation(): number; selectNone(): this; sendBackward(ids?: TLShapeId[]): this; sendToBack(ids?: TLShapeId[]): this; - // (undocumented) setAnimationSpeed(animationSpeed: number): this; setBrush(brush?: Box2dModel | null): this; setCamera(x: number, y: number, z?: number, { stopFollowing }?: TLViewportOptions): this; - // (undocumented) setCroppingId(id: null | TLShapeId): this; setCurrentPageId(pageId: TLPageId, { stopFollowing }?: TLViewportOptions): this; setCursor(cursor: Partial): this; - // (undocumented) setDarkMode(isDarkMode: boolean): this; setEditingId(id: null | TLShapeId): this; setErasingIds(ids?: TLShapeId[]): this; setFocusLayer(next: null | TLShapeId): this; - // (undocumented) setFocusMode(isFocusMode: boolean): this; - // (undocumented) setGridMode(isGridMode: boolean): this; setHintingIds(ids: TLShapeId[]): this; setHoveredId(id?: null | TLShapeId): this; setInstancePageState(partial: Partial, ephemeral?: boolean): void; setLocale(locale: string): void; setOpacity(opacity: number, ephemeral?: boolean, squashing?: boolean): this; - // (undocumented) setPenMode(isPenMode: boolean): this; // @internal (undocumented) setProjectName(name: string): void; setProp(key: TLShapeProp, value: any, ephemeral?: boolean, squashing?: boolean): this; - // (undocumented) setReadOnly(isReadOnly: boolean): this; setScribble(scribble?: null | TLScribble): this; setSelectedIds(ids: TLShapeId[], squashing?: boolean): this; setSelectedTool(id: string, info?: {}): this; - // (undocumented) setSnapMode(isSnapMode: boolean): this; - // (undocumented) setToolLocked(isToolLocked: boolean): this; setZoomBrush(zoomBrush?: Box2dModel | null): this; get shapeIds(): Set; @@ -731,7 +686,6 @@ export class Editor extends EventEmitter { shapeUtils: { readonly [K in string]?: ShapeUtil; }; - // (undocumented) slideCamera(opts?: { speed: number; direction: Vec2d; @@ -748,28 +702,23 @@ export class Editor extends EventEmitter { stretchShapes(operation: 'horizontal' | 'vertical', ids?: TLShapeId[]): this; static styles: TLStyleCollections; textMeasure: TextManager; - // (undocumented) toggleLock(ids?: TLShapeId[]): this; undo(): HistoryManager; - // (undocumented) ungroupShapes(ids?: TLShapeId[]): this; updateAssets(assets: TLAssetPartial[]): this; // @internal updateCullingBounds(): this; - // (undocumented) updateDocumentSettings(settings: Partial): void; updateInstanceState(partial: Partial>, ephemeral?: boolean, squashing?: boolean): this; updatePage(partial: RequiredKeys, squashing?: boolean): this; updateShapes(partials: (null | TLShapePartial | undefined)[], squashing?: boolean): this; updateViewportScreenBounds(center?: boolean): this; - // (undocumented) readonly user: UserPreferencesManager; get viewportPageBounds(): Box2d; get viewportPageCenter(): Vec2d; get viewportScreenBounds(): Box2d; get viewportScreenCenter(): Vec2d; visitDescendants(parentId: TLParentId, visitor: (id: TLShapeId) => false | void): void; - // (undocumented) get zoomBrush(): Box2dModel | null; zoomIn(point?: Vec2d, opts?: TLAnimationOptions): this; get zoomLevel(): number; diff --git a/packages/editor/src/lib/TldrawEditor.tsx b/packages/editor/src/lib/TldrawEditor.tsx index 5625b98a0..4a98e95a0 100644 --- a/packages/editor/src/lib/TldrawEditor.tsx +++ b/packages/editor/src/lib/TldrawEditor.tsx @@ -28,38 +28,24 @@ import { TLStoreWithStatus } from './utils/sync/StoreWithStatus' /** @public */ export type TldrawEditorProps = { children?: any - /** - * An array of shape utils to use in the editor. - */ + /** An array of shape utils to use in the editor. */ shapes?: readonly AnyTLShapeInfo[] - /** - * An array of tools to use in the editor. - */ + /** An array of tools to use in the editor. */ tools?: readonly TLStateNodeConstructor[] - /** - * Urls for where to find fonts and other assets. - */ + /** Urls for where to find fonts and other assets. */ assetUrls?: RecursivePartial - /** - * Whether to automatically focus the editor when it mounts. - */ + /** Whether to automatically focus the editor when it mounts. */ autoFocus?: boolean - /** - * Overrides for the tldraw user interface components. - */ + /** Overrides for the tldraw user interface components. */ components?: Partial - /** * Called when the editor has mounted. - * * @example - * * ```ts * function TldrawEditor() { * return editor.selectAll()} /> * } * ``` - * * @param editor - The editor instance. */ onMount?: (editor: Editor) => (() => void) | undefined | void diff --git a/packages/editor/src/lib/editor/Editor.ts b/packages/editor/src/lib/editor/Editor.ts index 90f428cf9..e7cca7b98 100644 --- a/packages/editor/src/lib/editor/Editor.ts +++ b/packages/editor/src/lib/editor/Editor.ts @@ -399,6 +399,8 @@ export class Editor extends EventEmitter { readonly snaps = new SnapManager(this) /** + * A manager for the user and their preferences. + * * @public */ readonly user: UserPreferencesManager @@ -429,15 +431,15 @@ export class Editor extends EventEmitter { private _canMoveCamera = atom('can move camera', true) /** - * Set whether the editor's camera can move. + * Whether the editor's camera can move. * * @example - * * ```ts * editor.canMoveCamera = false * ``` * * @param canMove - Whether the camera can move. + * * @public */ get canMoveCamera() { @@ -463,7 +465,6 @@ export class Editor extends EventEmitter { * The current HTML element containing the editor. * * @example - * * ```ts * const container = editor.getContainer() * ``` @@ -557,6 +558,11 @@ export class Editor extends EventEmitter { this.emit('crash', { error }) } + /** + * The window's device pixel ratio. + * + * @public + */ get devicePixelRatio() { return this._dprManager.dpr.value } @@ -581,9 +587,11 @@ export class Editor extends EventEmitter { /** * Add an open menu. * + * @example * ```ts * editor.addOpenMenu('menu-id') * ``` + * * @public */ addOpenMenu(id: string) { @@ -598,9 +606,11 @@ export class Editor extends EventEmitter { /** * Delete an open menu. * + * @example * ```ts * editor.deleteOpenMenu('menu-id') * ``` + * * @public */ deleteOpenMenu(id: string) { @@ -625,10 +635,10 @@ export class Editor extends EventEmitter { private _isCoarsePointer = atom('isCoarsePointer', false as any) /** - * Whether the user is using a "coarse" pointer, such as on a touch screen. + * Whether the user is using a "coarse" pointer, such as on a touch screen. This is automatically set by the canvas. * * @public - */ + **/ get isCoarsePointer() { return this._isCoarsePointer.value } @@ -647,7 +657,6 @@ export class Editor extends EventEmitter { * Whether the user is currently changing the style of a shape. This may cause the UI to change. * * @example - * * ```ts * editor.isChangingStyle = true * ``` @@ -738,13 +747,14 @@ export class Editor extends EventEmitter { * Get the page mask for a shape. * * @example - * * ```ts * const pageMask = editor.getPageMaskById(shape.id) * ``` * * @param id - The id of the shape to get the page mask for. + * * @returns The page mask for the shape. + * * @public */ getPageMaskById(id: TLShapeId) { @@ -777,13 +787,14 @@ export class Editor extends EventEmitter { * Get the clip path for a shape. * * @example - * * ```ts * const clipPath = editor.getClipPathById(shape.id) * ``` * * @param id - The shape id. + * * @returns The clip path or undefined. + * * @public */ getClipPathById(id: TLShapeId) { @@ -825,7 +836,6 @@ export class Editor extends EventEmitter { * Undo to the last mark. * * @example - * * ```ts * editor.undo() * ``` @@ -849,7 +859,6 @@ export class Editor extends EventEmitter { * Redo to the next mark. * * @example - * * ```ts * editor.redo() * ``` @@ -875,7 +884,6 @@ export class Editor extends EventEmitter { * any redos. * * @example - * * ```ts * editor.mark() * editor.mark('flip shapes') @@ -884,6 +892,7 @@ export class Editor extends EventEmitter { * @param reason - The reason for the mark. * @param onUndo - Whether to stop at the mark when undoing. * @param onRedo - Whether to stop at the mark when redoing. + * * @public */ mark(reason?: string, onUndo?: boolean, onRedo?: boolean) { @@ -894,7 +903,6 @@ export class Editor extends EventEmitter { * Clear all marks in the undo stack back to the next mark. * * @example - * * ```ts * editor.bail() * ``` @@ -910,7 +918,6 @@ export class Editor extends EventEmitter { * Clear all marks in the undo stack back to the mark with the provided mark id. * * @example - * * ```ts * editor.bailToMark('creating') * ``` @@ -926,7 +933,6 @@ export class Editor extends EventEmitter { * Run a function in a batch, which will be undone/redone as a single action. * * @example - * * ```ts * editor.batch(() => { * editor.selectAll() @@ -956,12 +962,12 @@ export class Editor extends EventEmitter { * Get a shape util by its definition. * * @example - * * ```ts * editor.getShapeUtil(ArrowShapeUtil) * ``` * * @param util - The shape util. + * * @public */ getShapeUtil; type: string }>( @@ -971,7 +977,6 @@ export class Editor extends EventEmitter { * Get a shape util from a shape itself. * * @example - * * ```ts * const util = editor.getShapeUtil(myShape) * const util = editor.getShapeUtil(myShape) @@ -979,6 +984,7 @@ export class Editor extends EventEmitter { * ``` * * @param shape - A shape or shape partial. + * * @public */ getShapeUtil(shape: S | TLShapePartial): ShapeUtil @@ -1013,12 +1019,12 @@ export class Editor extends EventEmitter { * Get an array of all the children of a shape. * * @example - * * ```ts * editor.getSortedChildIds('frame1') * ``` * * @param parentId - The id of the parent shape. + * * @public */ getSortedChildIds(parentId: TLParentId): TLShapeId[] { @@ -1030,13 +1036,13 @@ export class Editor extends EventEmitter { * Run a visitor function for all descendants of a shape. * * @example - * * ```ts * editor.visitDescendants('frame1', myCallback) * ``` * * @param parentId - The id of the parent shape. * @param visitor - The visitor function. + * * @public */ visitDescendants(parentId: TLParentId, visitor: (id: TLShapeId) => void | false) { @@ -1188,6 +1194,13 @@ export class Editor extends EventEmitter { return next } + /** + * Get the currently selected opacity. + * If any shapes are selected, this returns the opacity of the selected shapes. + * Otherwise, this returns the chosen opacity for the next shape. + * + * @public + */ @computed get opacity(): number | null { if (this.isIn('select') && this.selectedIds.length > 0) { const shapesToCheck: TLShape[] = [] @@ -1264,7 +1277,13 @@ export class Editor extends EventEmitter { return arrowBindingsIndex(this.store) } - /** GetArrowsBoundTo */ + /** + * Get all arrows bound to a shape. + * + * @param shapeId - The id of the shape. + * + * @public + */ getArrowsBoundTo(shapeId: TLShapeId) { return this._arrowBindingsIndex.value[shapeId] || EMPTY_ARRAY } @@ -1550,16 +1569,29 @@ export class Editor extends EventEmitter { /* -------------------- Shortcuts ------------------- */ - /** The global document settings that applies to all users */ + /** + * The global document settings that apply to all users. + * + * @public + **/ @computed get documentSettings() { return this.store.get(TLDOCUMENT_ID)! } - /** @public */ + /** + * Update the global document settings that apply to all users. + * + * @public + **/ updateDocumentSettings(settings: Partial) { this.store.put([{ ...this.documentSettings, ...settings }]) } + /** + * The document's grid size. + * + * @public + **/ get gridSize() { return this.documentSettings.gridSize } @@ -1574,10 +1606,20 @@ export class Editor extends EventEmitter { this.updateDocumentSettings({ name }) } + /** + * Whether the user has "always snap" mode enabled. + * + * @public + **/ get isSnapMode() { return this.user.isSnapMode } + /** + * Set whether the user has "always snap" mode enabled. + * + * @public + **/ setSnapMode(isSnapMode: boolean) { if (isSnapMode !== this.isSnapMode) { this.user.updateUserPreferences({ isSnapMode }) @@ -1585,10 +1627,20 @@ export class Editor extends EventEmitter { return this } + /** + * Whether the user has dark mode enabled. + * + * @public + **/ get isDarkMode() { return this.user.isDarkMode } + /** + * Set whether the user has dark mode enabled. + * + * @public + **/ setDarkMode(isDarkMode: boolean) { if (isDarkMode !== this.isDarkMode) { this.user.updateUserPreferences({ isDarkMode }) @@ -1596,43 +1648,85 @@ export class Editor extends EventEmitter { return this } + /** + * The user's chosen animation speed. + * + * @public + */ get animationSpeed() { return this.user.animationSpeed } - setAnimationSpeed(animationSpeed: number) { + /** + * Set the user's chosen animation speed. + * Set to 0.0 to disable animations. + * Set to 1.0 for full speed. + * + * @public + */ + setAnimationSpeed(animationSpeed: number): this { if (animationSpeed !== this.animationSpeed) { this.user.updateUserPreferences({ animationSpeed }) } return this } + /** + * Whether the instance is in focus mode or not. + * + * @public + **/ get isFocusMode() { return this.instanceState.isFocusMode } - setFocusMode(isFocusMode: boolean) { + /** + * Set whether the instance is in focus mode or not. + * + * @public + **/ + setFocusMode(isFocusMode: boolean): this { if (isFocusMode !== this.isFocusMode) { this.updateInstanceState({ isFocusMode }, true) } return this } + /** + * Whether the instance has "tool lock" mode enabled. + * + * @public + **/ get isToolLocked() { return this.instanceState.isToolLocked } - setToolLocked(isToolLocked: boolean) { + /** + * Set whether the instance has "tool lock" mode enabled. + * + * @public + **/ + setToolLocked(isToolLocked: boolean): this { if (isToolLocked !== this.isToolLocked) { this.updateInstanceState({ isToolLocked }, true) } return this } + /** + * Whether the instance's grid is enabled. + * + * @public + **/ get isGridMode() { return this.instanceState.isGridMode } + /** + * Set whether the instance's grid is enabled. + * + * @public + **/ setGridMode(isGridMode: boolean): this { if (isGridMode !== this.isGridMode) { this.updateInstanceState({ isGridMode }, true) @@ -1642,7 +1736,11 @@ export class Editor extends EventEmitter { private _isReadOnly = atom('isReadOnly', false as any) - /** @public */ + /** + * Set whether the editor is in read-only mode or not. + * + * @public + **/ setReadOnly(isReadOnly: boolean): this { this._isReadOnly.set(isReadOnly) if (isReadOnly) { @@ -1651,6 +1749,11 @@ export class Editor extends EventEmitter { return this } + /** + * Whether the editor is in read-only mode or not. + * + * @public + **/ get isReadOnly() { return this._isReadOnly.value } @@ -1661,10 +1764,20 @@ export class Editor extends EventEmitter { /** @internal */ private _touchEventsRemainingBeforeExitingPenMode = 0 + /** + * Whether the editor is in pen mode or not. + * + * @public + **/ get isPenMode() { return this._isPenMode.value } + /** + * Set whether the editor is in pen mode or not. + * + * @public + **/ setPenMode(isPenMode: boolean): this { if (isPenMode) this._touchEventsRemainingBeforeExitingPenMode = 3 if (isPenMode !== this.isPenMode) { @@ -1675,23 +1788,47 @@ export class Editor extends EventEmitter { // User / User App State - /** The current tab state */ + /** + * The current instance's state. + * + * @public + */ get instanceState(): TLInstance { return this.store.get(TLINSTANCE_ID)! } + /** + * The instance's cursor state. + * + * @public + **/ get cursor() { return this.instanceState.cursor } + /** + * The instance's brush state. + * + * @public + **/ get brush() { return this.instanceState.brush } + /** + * The instance's zoom brush state. + * + * @public + **/ get zoomBrush() { return this.instanceState.zoomBrush } + /** + * The instance's scribble state. + * + * @public + **/ get scribble() { return this.instanceState.scribble } @@ -1709,17 +1846,27 @@ export class Editor extends EventEmitter { @computed get pageState(): TLInstancePageState { return this.store.get(this.pageStateId)! } + + /** @internal */ @computed private get cameraId() { return CameraRecordType.createId(this.currentPageId) } - /** The current camera. */ + /** + * The current camera. + * + * @public + */ @computed get camera() { return this.store.get(this.cameraId)! } - /** The current camera zoom level. */ + /** + * The current camera zoom level. + * + * @public + */ @computed get zoomLevel() { return this.camera.z } @@ -1742,8 +1889,6 @@ export class Editor extends EventEmitter { return new Set(this.selectedIds) } - // Pages - /** @internal */ @computed private get _pages() { return this.store.query.records('page') @@ -1753,7 +1898,6 @@ export class Editor extends EventEmitter { * Info about the project's current pages. * * @public - * @readonly */ @computed get pages() { return this._pages.value.sort(sortByIndex) @@ -1781,14 +1925,13 @@ export class Editor extends EventEmitter { * Get a page by its ID. * * @example - * * ```ts * editor.getPageById(myPage.id) * ``` * * @public */ - getPageById(id: TLPage['id']) { + getPageById(id: TLPageId) { return this.store.get(id) } @@ -1801,7 +1944,6 @@ export class Editor extends EventEmitter { * Get a page state by its id. * * @example - * * ```ts * editor.getPageStateByPageId('page1') * ``` @@ -1816,7 +1958,6 @@ export class Editor extends EventEmitter { * Get a page by its ID. * * @example - * * ```ts * editor.getPageById(myPage.id) * ``` @@ -1827,7 +1968,13 @@ export class Editor extends EventEmitter { return this.store.get(id) } - /** Get shapes on a page. */ + /** + * Get the ids of shapes on a page. + * + * @param pageId - The id of the page. + * + * @public + **/ getShapeIdsInPage(pageId: TLPageId): Set { const result = this.store.query.exec('shape', { parentId: { eq: pageId } }) return this.getShapeAndDescendantIds(result.map((s) => s.id)) @@ -1842,12 +1989,12 @@ export class Editor extends EventEmitter { * shape's rotation. * * @example - * * ```ts * editor.getTransform(myShape) * ``` * * @param shape - The shape to get the local transform for. + * * @public */ getTransform(shape: TLShape) { @@ -1859,12 +2006,12 @@ export class Editor extends EventEmitter { * Get the local transform of a shape's parent as a matrix model. * * @example - * * ```ts * editor.getParentTransform(myShape) * ``` * * @param shape - The shape to get the parent transform for. + * * @public */ getParentTransform(shape: TLShape) { @@ -1878,12 +2025,12 @@ export class Editor extends EventEmitter { * Get the page transform (or absolute transform) of a shape. * * @example - * * ```ts * editor.getPageTransform(myShape) * ``` * * @param shape - The shape to get the page transform for. + * * @public */ getPageTransform(shape: TLShape) { @@ -1894,12 +2041,12 @@ export class Editor extends EventEmitter { * Get the page transform (or absolute transform) of a shape by its id. * * @example - * * ```ts * editor.getPageTransformById(myShape) * ``` * * @param id - The if of the shape to get the page transform for. + * * @public */ getPageTransformById(id: TLShapeId) { @@ -1910,12 +2057,12 @@ export class Editor extends EventEmitter { * Get the page point (or absolute point) of a shape. * * @example - * * ```ts * editor.getPagePoint(myShape) * ``` * * @param shape - The shape to get the page point for. + * * @public */ getPagePointById(id: TLShapeId) { @@ -1928,12 +2075,12 @@ export class Editor extends EventEmitter { * Get the page point (or absolute point) of a shape. * * @example - * * ```ts * editor.getPagePoint(myShape) * ``` * * @param shape - The shape to get the page point for. + * * @public */ getPageCenter(shape: TLShape) { @@ -1948,12 +2095,12 @@ export class Editor extends EventEmitter { * Get the page point (or absolute point) of a shape by its id. * * @example - * * ```ts * editor.getPagePoint(myShape) * ``` * * @param id - The shape id to get the page point for. + * * @public */ getPageCenterById(id: TLShapeId) { @@ -1965,12 +2112,12 @@ export class Editor extends EventEmitter { * Get the page rotation (or absolute rotation) of a shape. * * @example - * * ```ts * editor.getPageRotation(myShape) * ``` * * @param shape - The shape to get the page rotation for. + * * @public */ getPageRotation(shape: TLShape): number { @@ -1980,6 +2127,11 @@ export class Editor extends EventEmitter { /** * Get the page rotation (or absolute rotation) of a shape by its id. * + * @example + * ```ts + * editor.getPageRotationById(myShapeId) + * ``` + * * @param id - The id of the shape to get the page rotation for. */ getPageRotationById(id: TLShapeId): number { @@ -1994,12 +2146,12 @@ export class Editor extends EventEmitter { * Get the local bounds of a shape. * * @example - * * ```ts * editor.getBounds(myShape) * ``` * * @param shape - The shape to get the bounds for. + * * @public */ getBounds(shape: TLShape): Box2d { @@ -2010,12 +2162,12 @@ export class Editor extends EventEmitter { * Get the local bounds of a shape by its id. * * @example - * * ```ts * editor.getBoundsById(myShape) * ``` * * @param id - The id of the shape to get the bounds for. + * * @public */ getBoundsById(id: TLShapeId): Box2d | undefined { @@ -2028,12 +2180,12 @@ export class Editor extends EventEmitter { * Get the page (or absolute) bounds of a shape. * * @example - * * ```ts * editor.getPageBounds(myShape) * ``` * * @param shape - The shape to get the bounds for. + * * @public */ getPageBounds(shape: TLShape): Box2d | undefined { @@ -2044,12 +2196,12 @@ export class Editor extends EventEmitter { * Get the page (or absolute) bounds of a shape by its id. * * @example - * * ```ts * editor.getPageBoundsById(myShape) * ``` * * @param id - The id of the shape to get the page bounds for. + * * @public */ getPageBoundsById(id: TLShapeId): Box2d | undefined { @@ -2062,12 +2214,12 @@ export class Editor extends EventEmitter { * of the shape that was in the frame. * * @example - * * ```ts * editor.getMaskedPageBounds(myShape) * ``` * * @param shape - The shape to get the masked bounds for. + * * @public */ getMaskedPageBounds(shape: TLShape): Box2d | undefined { @@ -2080,12 +2232,12 @@ export class Editor extends EventEmitter { * the half of the shape that was in the frame. * * @example - * * ```ts * editor.getMaskedPageBoundsById(myShape) * ``` * * @param id - The id of the shape to get the masked page bounds for. + * * @public */ getMaskedPageBoundsById(id: TLShapeId): Box2d | undefined { @@ -2104,12 +2256,12 @@ export class Editor extends EventEmitter { * Get the local outline of a shape. * * @example - * * ```ts * editor.getOutline(myShape) * ``` * * @param shape - The shape to get the outline for. + * * @public */ getOutline(shape: TLShape) { @@ -2120,12 +2272,12 @@ export class Editor extends EventEmitter { * Get the local outline of a shape. * * @example - * * ```ts * editor.getOutlineById(myShape) * ``` * * @param id - The shape id to get the outline for. + * * @public */ getOutlineById(id: TLShapeId) { @@ -2136,12 +2288,12 @@ export class Editor extends EventEmitter { * Get the ancestors of a shape. * * @example - * * ```ts * const ancestors = editor.getAncestors(myShape) * ``` * * @param shape - The shape to get the ancestors for. + * * @public */ getAncestors(shape: TLShape, acc: TLShape[] = []): TLShape[] { @@ -2161,12 +2313,12 @@ export class Editor extends EventEmitter { * Get the ancestors of a shape by its id. * * @example - * * ```ts * const ancestors = editor.getAncestorsById(myShape) * ``` * * @param id - The id of the shape to get the ancestors for. + * * @public */ getAncestorsById(id: TLShapeId, acc: TLShape[] = []): TLShape[] { @@ -2179,12 +2331,12 @@ export class Editor extends EventEmitter { * Find the first ancestor matching the given predicate * * @example - * * ```ts * const ancestor = editor.findAncestor(myShape) * ``` * * @param shape - The shape to check the ancestors for. + * * @public */ findAncestor(shape: TLShape, predicate: (parent: TLShape) => boolean): TLShape | undefined { @@ -2206,7 +2358,14 @@ export class Editor extends EventEmitter { return undefined } - /** Returns true if the the given shape has the given ancestor */ + /** + * Returns true if the the given shape has the given ancestor. + * + * @param shape - The shape. + * @param ancestorId - The id of the ancestor. + * + * @public + */ hasAncestor(shape: TLShape | undefined, ancestorId: TLShapeId): boolean { if (!shape) return false if (shape.parentId === ancestorId) return true @@ -2254,6 +2413,7 @@ export class Editor extends EventEmitter { * Check whether a shape is within the bounds of the current viewport. * * @param id - The id of the shape to check. + * * @public */ isShapeInViewport(id: TLShapeId) { @@ -2266,6 +2426,7 @@ export class Editor extends EventEmitter { * Check whether a shape or its parent is locked. * * @param id - The id of the shape to check. + * * @public */ isShapeOrAncestorLocked(shape?: TLShape): boolean { @@ -2436,12 +2597,12 @@ export class Editor extends EventEmitter { * Get the corners of a shape in page space. * * @example - * * ```ts * const corners = editor.getPageCorners(myShape) * ``` * * @param shape - The shape to get the corners for. + * * @public */ getPageCorners(shape: TLShape): Vec2d[] { @@ -2462,13 +2623,13 @@ export class Editor extends EventEmitter { * such as when a shape is the child of a frame and is partially clipped by the frame. * * @example - * * ```ts * editor.isPointInShape({ x: 100, y: 100 }, myShape) * ``` * * @param point - The page point to test. * @param shape - The shape to test against. + * * @public */ isPointInShape(point: VecLike, shape: TLShape): boolean { @@ -2488,12 +2649,12 @@ export class Editor extends EventEmitter { * Get the shapes, if any, at a given page point. * * @example - * * ```ts * editor.getShapesAtPoint({ x: 100, y: 100 }) * ``` * * @param point - The page point to test. + * * @public */ getShapesAtPoint(point: VecLike): TLShape[] { @@ -2515,13 +2676,13 @@ export class Editor extends EventEmitter { * `{ x: 10, y: 10 }` in the shape's local space. * * @example - * * ```ts * editor.getPointInShapeSpace(myShape, { x: 100, y: 100 }) * ``` * * @param shape - The shape to get the point in the local space of. * @param point - The page point to get in the local space of the shape. + * * @public */ getPointInShapeSpace(shape: TLShape, point: VecLike): Vec2d { @@ -2534,13 +2695,13 @@ export class Editor extends EventEmitter { * `{ x: 10, y: 10 }` in the shape's local space. * * @example - * * ```ts * editor.getPointInShapeSpace(myShape.id, { x: 100, y: 100 }) * ``` * * @param shape - The shape to get the point in the local space of. * @param point - The page point to get in the local space of the shape. + * * @public */ getPointInParentSpace(shapeId: TLShapeId, point: VecLike): Vec2d { @@ -2560,13 +2721,13 @@ export class Editor extends EventEmitter { * Convert a delta in page space to a delta in the local space of a shape. * * @example - * * ```ts * editor.getDeltaInShapeSpace(myShape, { x: 100, y: 100 }) * ``` * * @param shape - The shape to get the delta in the local space of. * @param delta - The page delta to convert. + * * @public */ getDeltaInShapeSpace(shape: TLShape, delta: VecLike): Vec2d { @@ -2579,13 +2740,13 @@ export class Editor extends EventEmitter { * Convert a delta in page space to a delta in the parent space of a shape. * * @example - * * ```ts * editor.getDeltaInParentSpace(myShape, { x: 100, y: 100 }) * ``` * * @param shape - The shape to get the delta in the parent space of. * @param delta - The page delta to convert. + * * @public */ getDeltaInParentSpace(shape: TLShape, delta: VecLike): Vec2d { @@ -2602,12 +2763,12 @@ export class Editor extends EventEmitter { * parents. * * @example - * * ```ts * editor.getParentsMappedToChildren(['id1', 'id2', 'id3']) * ``` * * @param ids - The ids to get the parents and children of. + * * @public */ getParentsMappedToChildren(ids: TLShapeId[]) { @@ -2629,13 +2790,13 @@ export class Editor extends EventEmitter { * element. This should be done whenever the container's position on the screen changes. * * @example - * * ```ts * editor.updateViewportScreenBounds() + * editor.updateViewportScreenBounds(true) * ``` * - * @param center - Whether to preserve the viewport page center as the viewport changes. - * (optional) + * @param center - (optional) Whether to preserve the viewport page center as the viewport changes. + * * @public */ updateViewportScreenBounds(center = false) { @@ -2750,11 +2911,11 @@ export class Editor extends EventEmitter { * as at the end of a pan, zoom, or animation. * * @example - * * ```ts * editor.updateCullingBounds() * ``` * + * * @internal */ updateCullingBounds(): this { @@ -2778,7 +2939,6 @@ export class Editor extends EventEmitter { * Convert a point in screen space to a point in page space. * * @example - * * ```ts * editor.screenToPage(100, 100) * ``` @@ -2786,6 +2946,7 @@ export class Editor extends EventEmitter { * @param x - The x coordinate of the point in screen space. * @param y - The y coordinate of the point in screen space. * @param camera - The camera to use. Defaults to the current camera. + * * @public */ screenToPage(x: number, y: number, z = 0.5, camera: Vec2dModel = this.camera) { @@ -2802,7 +2963,6 @@ export class Editor extends EventEmitter { * Convert a point in page space to a point in screen space. * * @example - * * ```ts * editor.pageToScreen(100, 100) * ``` @@ -2810,6 +2970,7 @@ export class Editor extends EventEmitter { * @param x - The x coordinate of the point in screen space. * @param y - The y coordinate of the point in screen space. * @param camera - The camera to use. Defaults to the current camera. + * * @public */ pageToScreen(x: number, y: number, z = 0.5, camera: Vec2dModel = this.camera) { @@ -2823,10 +2984,20 @@ export class Editor extends EventEmitter { /* Focus Layers */ + /** + * The shape id of the current focus layer. + * + * @public + */ get focusLayerId() { return this.pageState.focusLayerId ?? this.currentPageId } + /** + * The shape of the current focus layer. + * + * @public + */ get focusLayerShape(): TLShape | undefined { const id = this.pageState.focusLayerId if (!id) { @@ -2835,6 +3006,11 @@ export class Editor extends EventEmitter { return this.getShapeById(id) } + /** + * Exit the current focus layer, moving up to the next group if there is one. + * + * @public + */ popFocusLayer() { const current = this.pageState.focusLayerId const focusedShape = current && this.getShapeById(current) @@ -2858,6 +3034,7 @@ export class Editor extends EventEmitter { * Set the focus layer to the given shape id. * * @param next - The next focus layer id or null to reset the focus layer to the page + * * @public */ setFocusLayer(next: null | TLShapeId) { @@ -2893,6 +3070,7 @@ export class Editor extends EventEmitter { * Set the hinted shape ids. * * @param ids - The ids to set as hinted. + * * @public */ setHintingIds(ids: TLShapeId[]): this { @@ -2928,6 +3106,7 @@ export class Editor extends EventEmitter { * Set the current editing id. * * @param id - The id of the shape to edit or null to clear the editing id. + * * @public */ setEditingId(id: TLShapeId | null): this { @@ -2968,6 +3147,13 @@ export class Editor extends EventEmitter { return this } + /** + * Set the current cropping shape's id. + * + * @param id - The id of the shape to crop or null to clear the cropping id. + * + * @public + */ setCroppingId(id: TLShapeId | null): this { if (id !== this.croppingId) { if (!id) { @@ -2986,6 +3172,16 @@ export class Editor extends EventEmitter { return this } + /** + * Get the id of what should be the parent of a new shape at a given point. The parent can be a page or shape. + * + * @param point - The point to find the parent for. + * @param shapeType - The type of shape that will be created. + * + * @returns The id of the parent. + * + * @public + */ getParentIdForNewShapeAtPoint(point: VecLike, shapeType: TLShape['type']) { const shapes = this.sortedShapesArray @@ -3006,6 +3202,16 @@ export class Editor extends EventEmitter { return this.focusLayerId } + /** + * Get the shape that some shapes should be dropped on at a given point. + * + * @param point - The point to find the parent for. + * @param droppingShapes - The shapes that are being dropped. + * + * @returns The shape to drop on. + * + * @public + */ getDroppingShape(point: VecLike, droppingShapes: TLShape[] = []) { const shapes = this.sortedShapesArray @@ -3028,8 +3234,18 @@ export class Editor extends EventEmitter { return undefined } - // This returns the node that should be selected when you click on this one, assuming there is nothing - // already selected. It will not return anything higher than or including the current focus layer. + /** + * Get the shape that should be selected when you click on a given shape, assuming there is + * nothing already selected. It will not return anything higher than or including the current + * focus layer. + * + * @param shape - The shape to get the outermost selectable shape for. + * @param filter - A function to filter the selectable shapes. + * + * @returns The outermost selectable shape. + * + * @public + */ getOutermostSelectableShape(shape: TLShape, filter?: (shape: TLShape) => boolean): TLShape { let match = shape let node = shape as TLShape | undefined @@ -3060,10 +3276,10 @@ export class Editor extends EventEmitter { static styles = STYLES /** - * The current page bounds of all the selected shapes (Not the same thing as the page bounds of - * the selection bounding box when the selection has been rotated) + * The current page bounds of all the selected shapes (Not the same thing as the page bounds of the selection bounding box when the selection has been rotated) * * @readonly + * * @public */ @computed get selectedPageBounds(): Box2d | null { @@ -3076,7 +3292,12 @@ export class Editor extends EventEmitter { return Box2d.Common(compact(selectedIds.map((id) => this.getPageBoundsById(id)))) } - /** The rotation of the selection bounding box. */ + /** + * The rotation of the selection bounding box. + * + * @readonly + * @public + */ @computed get selectionRotation(): number { const { selectedIds } = this if (selectedIds.length === 0) { @@ -3094,6 +3315,12 @@ export class Editor extends EventEmitter { return 0 } + /** + * The bounds of the selection bounding box. + * + * @readonly + * @public + */ @computed get selectionBounds(): Box2d | undefined { const { selectedIds } = this @@ -3126,6 +3353,12 @@ export class Editor extends EventEmitter { return box } + /** + * The center of the selection bounding box. + * + * @readonly + * @public + */ @computed get selectionPageCenter() { const { selectionBounds, selectionRotation } = this if (!selectionBounds) return null @@ -3136,12 +3369,12 @@ export class Editor extends EventEmitter { * An array containing all of the shapes in the current page. * * @example - * * ```ts * editor.shapesArray * ``` * * @readonly + * * @public */ @computed get shapesArray() { @@ -3153,12 +3386,12 @@ export class Editor extends EventEmitter { * for nested shapes): e.g. A, B, BA, BB, C. * * @example - * * ```ts * editor.sortedShapesArray * ``` * * @readonly + * * @public */ @computed get sortedShapesArray(): TLShape[] { @@ -3191,7 +3424,6 @@ export class Editor extends EventEmitter { * An array containing all of the currently selected shapes. * * @example - * * ```ts * editor.selectedShapes * ``` @@ -3208,13 +3440,13 @@ export class Editor extends EventEmitter { * The app's only selected shape. * * @example - * * ```ts * editor.onlySelectedShape * ``` * * @returns Null if there is no shape or more than one selected shape, otherwise the selected * shape. + * * @public * @readonly */ @@ -3227,7 +3459,6 @@ export class Editor extends EventEmitter { * Get whether a shape matches the type of a TLShapeUtil. * * @example - * * ```ts * const isArrowShape = isShapeOfType(someShape, ArrowShapeUtil) * ``` @@ -3248,12 +3479,12 @@ export class Editor extends EventEmitter { * Get a shape by its id. * * @example - * * ```ts * editor.getShapeById('box1') * ``` * * @param id - The id of the shape to get. + * * @public */ getShapeById(id: TLParentId): T | undefined { @@ -3266,7 +3497,6 @@ export class Editor extends EventEmitter { * the page. * * @example - * * ```ts * editor.getParentShape(myShape) * ``` @@ -3281,7 +3511,9 @@ export class Editor extends EventEmitter { /** * If siblingShape and targetShape are siblings, this returns targetShape. If targetShape has an * ancestor who is a sibling of siblingShape, this returns that ancestor. Otherwise, this returns - * undefined + * undefined. + * + * @internal */ private getNearestSiblingShape( siblingShape: TLShape, @@ -3302,7 +3534,15 @@ export class Editor extends EventEmitter { return ancestor } - /** Get the id of the containing page for a given shape. */ + /** + * Get the id of the containing page for a given shape. + * + * @param shape - The shape to get the page id for. + * + * @returns The id of the page that contains the shape, or undefined if the shape is undefined. + * + * @public + */ getParentPageId(shape?: TLShape): TLPageId | undefined { if (shape === undefined) return undefined if (isPageId(shape.parentId)) { @@ -3316,7 +3556,6 @@ export class Editor extends EventEmitter { * Get whether the given shape is the descendant of the given page. * * @example - * * ```ts * editor.isShapeInPage(myShape) * editor.isShapeInPage(myShape, 'page1') @@ -3324,6 +3563,7 @@ export class Editor extends EventEmitter { * * @param shape - The shape to check. * @param pageId - The id of the page to check against. Defaults to the current page. + * * @public */ isShapeInPage(shape: TLShape, pageId = this.currentPageId): boolean { @@ -3370,12 +3610,12 @@ export class Editor extends EventEmitter { * Get the CSS color value for a given color id. * * @example - * * ```ts * editor.getCssColor('red') * ``` * * @param id - The id of the color to get. + * * @public */ getCssColor(id: TLColorStyle['id']): string { @@ -3386,12 +3626,12 @@ export class Editor extends EventEmitter { * Get the stroke width value for a given size id. * * @example - * * ```ts * editor.getStrokeWidth('m') * ``` * * @param id - The id of the size to get. + * * @public */ getStrokeWidth(id: TLSizeStyle['id']): number { @@ -3426,7 +3666,6 @@ export class Editor extends EventEmitter { * Set the selected tool. * * @example - * * ```ts * editor.setSelectedTool('hand') * editor.setSelectedTool('hand', { date: Date.now() }) @@ -3434,6 +3673,7 @@ export class Editor extends EventEmitter { * * @param id - The id of the tool to select. * @param info - Arbitrary data to pass along into the transition. + * * @public */ setSelectedTool(id: string, info = {}) { @@ -3445,13 +3685,13 @@ export class Editor extends EventEmitter { * Get a descendant by its path. * * @example - * * ```ts * state.getStateDescendant('select') * state.getStateDescendant('select.brushing') * ``` * * @param path - The descendant's path of state ids, separated by periods. + * * @public */ getStateDescendant(path: string): StateNode | undefined { @@ -3471,13 +3711,13 @@ export class Editor extends EventEmitter { * 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 { @@ -3500,7 +3740,6 @@ export class Editor extends EventEmitter { * 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') @@ -3562,7 +3801,6 @@ export class Editor extends EventEmitter { * Update the input points from a pointer or pinch event. * * @param info - The event info. - * @internal */ private _updateInputsFromEvent(info: TLPointerEventInfo | TLPinchEventInfo) { const { previousScreenPoint, previousPagePoint, currentScreenPoint, currentPagePoint } = @@ -3695,12 +3933,12 @@ export class Editor extends EventEmitter { * Dispatch an event to the editor. * * @example - * * ```ts * editor.dispatch(myPointerEvent) * ``` * * @param info - The event info. + * * @public */ dispatch(info: TLEventInfo): this { @@ -4157,6 +4395,11 @@ export class Editor extends EventEmitter { return this } + /** + * Replace the store's contents with the given records. + * + * @param records - The records to replace the store's contents with. + */ replaceStoreContentsWithRecordsForOtherDocument(records: TLRecord[]) { transact(() => { this.store.clear() @@ -4175,6 +4418,15 @@ export class Editor extends EventEmitter { }) } + /** + * Get content that can be exported for the given shape ids. + * + * @param ids - The ids of the shapes to get content for. Defaults to the selected shape ids. + * + * @returns The exported content. + * + * @public + */ getContent(ids: TLShapeId[] = this.selectedIds): TLContent | undefined { if (!ids) return if (ids.length === 0) return @@ -4310,6 +4562,14 @@ export class Editor extends EventEmitter { /* --------------------- Commands --------------------- */ + /** + * Place content into the editor. + * + * @param content - The content. + * @param options - Options for placing the content. + * + * @public + */ putContent( content: TLContent, options: { @@ -4621,6 +4881,15 @@ export class Editor extends EventEmitter { /* --------------------- Shapes --------------------- */ + /** + * Get the index above the highest child of a given parent. + * + * @param parentId - The id of the parent. + * + * @returns The index. + * + * @public + */ getHighestIndexForParent(parentId: TLShapeId | TLPageId) { const children = this._parentIdsToChildIds.value[parentId] @@ -4634,13 +4903,13 @@ export class Editor extends EventEmitter { * Create shapes. * * @example - * * ```ts * editor.createShapes([{ id: 'box1', type: 'text', props: { text: "ok" } }]) * ``` * * @param partials - The shape partials to create. * @param select - Whether to select the created shapes. Defaults to false. + * * @public */ createShapes(partials: TLShapePartial[], select = false) { @@ -4825,12 +5094,12 @@ export class Editor extends EventEmitter { * Animate shapes. * * @example - * * ```ts * editor.animateShapes([{ id: 'box1', type: 'box', x: 100, y: 100 }]) * ``` * * @param partials - The shape partials to update. + * * @public */ animateShapes( @@ -4929,16 +5198,16 @@ export class Editor extends EventEmitter { } /** - * Update shapes. + * Update shapes using partials of each shape. * * @example - * * ```ts * editor.updateShapes([{ id: 'box1', type: 'geo', props: { w: 100, h: 100 } }]) * ``` * * @param partials - The shape partials to update. * @param squashing - Whether the change is ephemeral. + * * @public */ updateShapes( @@ -5062,13 +5331,13 @@ export class Editor extends EventEmitter { * Delete shapes. * * @example - * * ```ts * editor.deleteShapes() * editor.deleteShapes(['box1', 'box2']) * ``` * * @param ids - The ids of the shapes to delete. Defaults to the selected shapes. + * * @public */ deleteShapes(ids: TLShapeId[] = this.selectedIds) { @@ -5130,7 +5399,8 @@ export class Editor extends EventEmitter { ) /** - * Get the editor's locale. + * Get the user's locale. + * * @public */ get locale() { @@ -5138,13 +5408,14 @@ export class Editor extends EventEmitter { } /** - * Update the editor's locale. This affects which translations are used when rendering UI elements. + * Update the user's locale. This affects which translations are used when rendering UI elements. * * @example - * * ```ts * editor.setLocale('fr') * ``` + * + * @public */ setLocale(locale: string) { this.user.updateUserPreferences({ locale }) @@ -5154,12 +5425,12 @@ export class Editor extends EventEmitter { * Update a page. * * @example - * * ```ts * editor.updatePage({ id: 'page2', name: 'Page 2' }) * ``` * * @param partial - The partial of the shape to update. + * * @public */ updatePage(partial: RequiredKeys, squashing = false) { @@ -5199,7 +5470,6 @@ export class Editor extends EventEmitter { * Create a page. * * @example - * * ```ts * editor.createPage('New Page') * editor.createPage('New Page', 'page1') @@ -5207,6 +5477,7 @@ export class Editor extends EventEmitter { * * @param id - The new page's id. * @param title - The new page's title. + * * @public */ createPage(title: string, id: TLPageId = PageRecordType.createId(), belowPageIndex?: string) { @@ -5279,10 +5550,18 @@ export class Editor extends EventEmitter { } ) + /** + * Duplicate a page. + * + * @param id - The id of the page to duplicate. Defaults to the current page. + * @param createId - The id of the new page. Defaults to a new id. + * + * @public + */ duplicatePage(id: TLPageId = this.currentPageId, createId: TLPageId = PageRecordType.createId()) { - if (this.pages.length >= MAX_PAGES) return + if (this.pages.length >= MAX_PAGES) return this const page = this.getPageById(id) - if (!page) return + if (!page) return this const camera = { ...this.camera } const content = this.getContent(this.getSortedChildIds(page.id)) @@ -5297,18 +5576,20 @@ export class Editor extends EventEmitter { return this.putContent(content) } }) + + return this } /** * Delete a page. * * @example - * * ```ts * editor.deletePage('page1') * ``` * * @param id - The id of the page to delete. + * * @public */ deletePage(id: TLPageId) { @@ -5363,7 +5644,6 @@ export class Editor extends EventEmitter { * Update a page state. * * @example - * * ```ts * editor.setInstancePageState({ id: 'page1', editingId: 'shape:123' }) * editor.setInstancePageState({ id: 'page1', editingId: 'shape:123' }, true) @@ -5371,6 +5651,7 @@ export class Editor extends EventEmitter { * * @param partial - The partial of the page state object containing the changes. * @param ephemeral - Whether the command is ephemeral. + * * @public */ setInstancePageState(partial: Partial, ephemeral = false) { @@ -5398,7 +5679,6 @@ export class Editor extends EventEmitter { * Select one or more shapes. * * @example - * * ```ts * editor.setSelectedIds(['id1']) * editor.setSelectedIds(['id1', 'id2']) @@ -5407,6 +5687,7 @@ export class Editor extends EventEmitter { * @param ids - The ids to select. * @param squashing - Whether the change should create a new history entry or combine with the * previous (if the previous is the same type). + * * @public */ setSelectedIds(ids: TLShapeId[], squashing = false) { @@ -5446,12 +5727,12 @@ export class Editor extends EventEmitter { * Determine whether or not a shape is selected * * @example - * * ```ts * editor.isSelected('id1') * ``` * * @param id - The id of the shape to check. + * * @public */ isSelected(id: TLShapeId) { @@ -5463,6 +5744,7 @@ export class Editor extends EventEmitter { * selection if it or any of its parents is selected. * * @param id - The id of the shape to check. + * * @public */ isWithinSelection(id: TLShapeId) { @@ -5481,7 +5763,11 @@ export class Editor extends EventEmitter { return this.store.query.records('asset') } - /** Get all assets in the editor. */ + /** + * Get all assets in the editor. + * + * @public + */ get assets() { return this._assets.value } @@ -5490,12 +5776,12 @@ export class Editor extends EventEmitter { * Create one or more assets. * * @example - * * ```ts * editor.createAssets([...myAssets]) * ``` * * @param assets - The assets to create. + * * @public */ createAssets(assets: TLAsset[]) { @@ -5527,12 +5813,12 @@ export class Editor extends EventEmitter { * Delete one or more assets. * * @example - * * ```ts * editor.deleteAssets(['asset1', 'asset2']) * ``` * * @param ids - The assets to delete. + * * @public */ deleteAssets(ids: TLAssetId[]) { @@ -5565,12 +5851,12 @@ export class Editor extends EventEmitter { * Update one or more assets. * * @example - * * ```ts * editor.updateAssets([{ id: 'asset1', name: 'New name' }]) * ``` * * @param assets - The assets to update. + * * @public */ updateAssets(assets: TLAssetPartial[]) { @@ -5613,12 +5899,12 @@ export class Editor extends EventEmitter { * Get an asset by its src property. * * @example - * * ```ts * editor.getAssetBySource('https://example.com/image.png') * ``` * * @param src - The source value of the asset. + * * @public */ getAssetBySrc(src: string) { @@ -5629,12 +5915,12 @@ export class Editor extends EventEmitter { * Get an asset by its id. * * @example - * * ```ts * editor.getAssetById('asset1') * ``` * * @param id - The id of the asset. + * * @public */ getAssetById(id: TLAssetId): TLAsset | undefined { @@ -5642,6 +5928,16 @@ export class Editor extends EventEmitter { } /* ------------------- SubCommands ------------------ */ + /** + * Get an exported SVG of the given shapes. + * + * @param ids - The ids of the shapes to export. Defaults to selected shapes. + * @param opts - Options for the export. + * + * @returns The SVG element. + * + * @public + */ async getSvg( ids: TLShapeId[] = this.selectedIds.length ? this.selectedIds @@ -5948,13 +6244,13 @@ export class Editor extends EventEmitter { * Rename a page. * * @example - * * ```ts * editor.renamePage('page1', 'My Page') * ``` * * @param id - The id of the page to rename. * @param name - The new name. + * * @public */ renamePage(id: TLPageId, name: string, squashing = false) { @@ -5967,13 +6263,13 @@ export class Editor extends EventEmitter { * Move shapes to page. * * @example - * * ```ts * editor.moveShapesToPage(['box1', 'box2'], 'page1') * ``` * * @param ids - The ids of the shapes to move. * @param pageId - The id of the page where the shapes will be moved. + * * @public */ moveShapesToPage(ids: TLShapeId[], pageId: TLPageId): this { @@ -6027,6 +6323,13 @@ export class Editor extends EventEmitter { return this } + /** + * Toggle the lock state of one or more shapes. If there is a mix of locked and unlocked shapes, all shapes will be locked. + * + * @param ids - The ids of the shapes to toggle. Defaults to selected shapes. + * + * @public + */ toggleLock(ids: TLShapeId[] = this.selectedIds): this { if (this.isReadOnly || ids.length === 0) return this @@ -6063,6 +6366,7 @@ export class Editor extends EventEmitter { * * @param operation - The operation to perform. * @param ids - The ids to reorder. + * * @public */ reorderShapes(operation: 'toBack' | 'toFront' | 'forward' | 'backward', ids: TLShapeId[]) { @@ -6234,13 +6538,13 @@ export class Editor extends EventEmitter { * Send shapes to the back of the page's object list. * * @example - * * ```ts * editor.sendToBack() * editor.sendToBack(['id1', 'id2']) * ``` * * @param ids - The ids of the shapes to move. Defaults to the ids of the selected shapes. + * * @public */ sendToBack(ids = this.pageState.selectedIds) { @@ -6252,13 +6556,13 @@ export class Editor extends EventEmitter { * Send shapes backward in the page's object list. * * @example - * * ```ts * editor.sendBackward() * editor.sendBackward(['id1', 'id2']) * ``` * * @param ids - The ids of the shapes to move. Defaults to the ids of the selected shapes. + * * @public */ sendBackward(ids = this.pageState.selectedIds) { @@ -6270,13 +6574,13 @@ export class Editor extends EventEmitter { * Bring shapes forward in the page's object list. * * @example - * * ```ts * editor.bringForward() * editor.bringForward(['id1', 'id2']) * ``` * * @param ids - The ids of the shapes to move. Defaults to the ids of the selected shapes. + * * @public */ bringForward(ids = this.pageState.selectedIds) { @@ -6288,13 +6592,13 @@ export class Editor extends EventEmitter { * Bring shapes to the front of the page's object list. * * @example - * * ```ts * editor.bringToFront() * editor.bringToFront(['id1', 'id2']) * ``` * * @param ids - The ids of the shapes to move. Defaults to the ids of the selected shapes. + * * @public */ bringToFront(ids = this.pageState.selectedIds) { @@ -6306,7 +6610,6 @@ export class Editor extends EventEmitter { * Flip shape positions. * * @example - * * ```ts * editor.flipShapes('horizontal') * editor.flipShapes('horizontal', ['box1', 'box2']) @@ -6314,6 +6617,7 @@ export class Editor extends EventEmitter { * * @param operation - Whether to flip horizontally or vertically. * @param ids - The ids of the shapes to flip. Defaults to selected shapes. + * * @public */ flipShapes(operation: 'horizontal' | 'vertical', ids: TLShapeId[] = this.selectedIds) { @@ -6365,7 +6669,6 @@ export class Editor extends EventEmitter { * Stack shape. * * @example - * * ```ts * editor.stackShapes('horizontal') * editor.stackShapes('horizontal', ['box1', 'box2']) @@ -6375,6 +6678,7 @@ export class Editor extends EventEmitter { * @param operation - Whether to stack horizontally or vertically. * @param ids - The ids of the shapes to stack. Defaults to selected shapes. * @param gap - A specific gap to use when stacking. + * * @public */ stackShapes( @@ -6505,7 +6809,6 @@ export class Editor extends EventEmitter { /** * Pack shapes into a grid centered on their current position. Based on potpack * (https://github.com/mapbox/potpack) - * * @param ids - The ids of the shapes to pack. Defaults to selected shapes. * @param padding - The padding to apply to the packed shapes. */ @@ -6655,7 +6958,6 @@ export class Editor extends EventEmitter { * Align shape positions. * * @example - * * ```ts * editor.alignShapes('left') * editor.alignShapes('left', ['box1', 'box2']) @@ -6663,6 +6965,7 @@ export class Editor extends EventEmitter { * * @param operation - The align operation to apply. * @param ids - The ids of the shapes to align. Defaults to selected shapes. + * * @public */ alignShapes( @@ -6742,7 +7045,6 @@ export class Editor extends EventEmitter { * Distribute shape positions. * * @example - * * ```ts * editor.distributeShapes('left') * editor.distributeShapes('left', ['box1', 'box2']) @@ -6750,6 +7052,7 @@ export class Editor extends EventEmitter { * * @param operation - Whether to distribute shapes horizontally or vertically. * @param ids - The ids of the shapes to distribute. Defaults to selected shapes. + * * @public */ distributeShapes( @@ -6916,10 +7219,19 @@ export class Editor extends EventEmitter { return destination } + /** + * Resize a shape. + * + * @param id - The id of the shape to resize. + * @param scale - The scale factor to apply to the shape. + * @param options - Additional options. + * + * @public + */ resizeShape( id: TLShapeId, scale: VecLike, - options?: { + options: { initialBounds?: Box2d scaleOrigin?: VecLike scaleAxisRotation?: number @@ -6927,29 +7239,29 @@ export class Editor extends EventEmitter { initialPageTransform?: MatLike dragHandle?: TLResizeHandle mode?: TLResizeMode - } + } = {} ) { if (this.isReadOnly) return this if (!Number.isFinite(scale.x)) scale = new Vec2d(1, scale.y) if (!Number.isFinite(scale.y)) scale = new Vec2d(scale.x, 1) - const initialShape = options?.initialShape ?? this.getShapeById(id) + const initialShape = options.initialShape ?? this.getShapeById(id) if (!initialShape) return this - const scaleOrigin = options?.scaleOrigin ?? this.getPageBoundsById(id)?.center + const scaleOrigin = options.scaleOrigin ?? this.getPageBoundsById(id)?.center if (!scaleOrigin) return this const pageRotation = this.getPageRotationById(id) if (pageRotation == null) return this - const scaleAxisRotation = options?.scaleAxisRotation ?? pageRotation + const scaleAxisRotation = options.scaleAxisRotation ?? pageRotation - const pageTransform = options?.initialPageTransform ?? this.getPageTransformById(id) + const pageTransform = options.initialPageTransform ?? this.getPageTransformById(id) if (!pageTransform) return this - const initialBounds = options?.initialBounds ?? this.getBoundsById(id) + const initialBounds = options.initialBounds ?? this.getBoundsById(id) if (!initialBounds) return this @@ -7019,9 +7331,9 @@ export class Editor extends EventEmitter { { ...initialShape, x, y }, { newPoint: newLocalPoint, - handle: options?.dragHandle ?? 'bottom_right', + handle: options.dragHandle ?? 'bottom_right', // don't set isSingle to true for children - mode: options?.mode ?? 'scale_shape', + mode: options.mode ?? 'scale_shape', scaleX: myScale.x, scaleY: myScale.y, initialBounds, @@ -7070,7 +7382,6 @@ export class Editor extends EventEmitter { * Stretch shape sizes and positions to fill their common bounding box. * * @example - * * ```ts * editor.stretchShapes('horizontal') * editor.stretchShapes('horizontal', ['box1', 'box2']) @@ -7078,6 +7389,7 @@ export class Editor extends EventEmitter { * * @param operation - Whether to stretch shapes horizontally or vertically. * @param ids - The ids of the shapes to stretch. Defaults to selected shapes. + * * @public */ stretchShapes( @@ -7155,7 +7467,6 @@ export class Editor extends EventEmitter { * rotations. * * @example - * * ```ts * editor.reparentShapesById(['box1', 'box2'], 'frame1') * ``` @@ -7163,6 +7474,7 @@ export class Editor extends EventEmitter { * @param ids - The ids of the shapes to reparent. * @param parentId - The id of the new parent shape. * @param insertIndex - The index to insert the children. + * * @public */ reparentShapesById(ids: TLShapeId[], parentId: TLParentId, insertIndex?: string) { @@ -7242,13 +7554,13 @@ export class Editor extends EventEmitter { * Select one or more shapes. * * @example - * * ```ts * editor.select('id1') * editor.select('id1', 'id2') * ``` * * @param ids - The ids to select. + * * @public */ select(...ids: TLShapeId[]) { @@ -7260,7 +7572,6 @@ export class Editor extends EventEmitter { * Remove a shape from the existing set of selected shapes. * * @example - * * ```ts * editor.deselect(shape.id) * ``` @@ -7279,7 +7590,6 @@ export class Editor extends EventEmitter { * Select all direct children of the current page. * * @example - * * ```ts * editor.selectAll() * ``` @@ -7295,6 +7605,15 @@ export class Editor extends EventEmitter { return this } + /** + * Get the shape ids of all descendants of the given shapes (including the shapes themselves). + * + * @param ids - The ids of the shapes to get descendants of. + * + * @returns The decscendant ids. + * + * @public + */ getShapeAndDescendantIds(ids: TLShapeId[]): Set { const idsToInclude = new Set() @@ -7317,7 +7636,6 @@ export class Editor extends EventEmitter { * Clear the selection. * * @example - * * ```ts * editor.selectNone() * ``` @@ -7336,13 +7654,13 @@ export class Editor extends EventEmitter { * Set the current page. * * @example - * * ```ts * editor.setCurrentPageId('page1') * ``` * * @param pageId - The id of the page to set as the current page. * @param options - Options for setting the current page. + * * @public */ setCurrentPageId(pageId: TLPageId, { stopFollowing = true }: TLViewportOptions = {}): this { @@ -7407,7 +7725,15 @@ export class Editor extends EventEmitter { } ) - /** Set the current user tab state */ + /** + * Update the instance's state. + * + * @param partial - A partial object to update the instance state with. + * @param ephemeral - Whether the change is ephemeral. Ephemeral changes don't get added to the undo/redo stack. Defaults to false. + * @param squashing - Whether the change will be squashed into the existing history entry rather than creating a new one. Defaults to false. + * + * @public + */ updateInstanceState( partial: Partial>, ephemeral = false, @@ -7443,10 +7769,22 @@ export class Editor extends EventEmitter { } ) + /** + * The current hovered shape id. + * + * @readonly + * @public + */ @computed get hoveredId() { return this.pageState.hoveredId } + /** + * The current hovered shape. + * + * @readonly + * @public + */ @computed get hoveredShape() { if (!this.hoveredId) return null return this.getShapeById(this.hoveredId) ?? null @@ -7456,13 +7794,13 @@ export class Editor extends EventEmitter { * Set the current hovered shape. * * @example - * * ```ts * editor.setHoveredId('box1') * editor.setHoveredId() // Clears the hovered shape. * ``` * * @param id - The id of the page to set as the current page + * * @public */ setHoveredId(id: TLShapeId | null = null): this { @@ -7476,13 +7814,13 @@ export class Editor extends EventEmitter { * Set the current erasing shapes. * * @example - * * ```ts * editor.setErasingIds(['box1', 'box2']) * editor.setErasingIds() // Clears the erasing set * ``` * * @param ids - The ids of shapes to set as erasing. + * * @public */ setErasingIds(ids: TLShapeId[] = []): this { @@ -7497,13 +7835,13 @@ export class Editor extends EventEmitter { * Set the current cursor. * * @example - * * ```ts * editor.setCursor({ type: 'default' }) * editor.setCursor({ type: 'default', rotation: Math.PI / 2, color: 'red' }) * ``` * * @param cursor - A partial of the cursor object. + * * @public */ setCursor(cursor: Partial): this { @@ -7531,13 +7869,13 @@ export class Editor extends EventEmitter { * Set the current scribble. * * @example - * * ```ts * editor.setScribble(nextScribble) * editor.setScribble() // clears the scribble * ``` * * @param scribble - The new scribble object. + * * @public */ setScribble(scribble: TLScribble | null = null): this { @@ -7549,13 +7887,13 @@ export class Editor extends EventEmitter { * Set the current brush. * * @example - * * ```ts * editor.setBrush({ x: 0, y: 0, w: 100, h: 100 }) * editor.setBrush() // Clears the brush * ``` * * @param brush - The brush box model to set, or null for no brush model. + * * @public */ setBrush(brush: Box2dModel | null = null): this { @@ -7568,13 +7906,13 @@ export class Editor extends EventEmitter { * Set the current zoom brush. * * @example - * * ```ts * editor.setZoomBrush({ x: 0, y: 0, w: 100, h: 100 }) * editor.setZoomBrush() // Clears the zoom * ``` * * @param zoomBrush - The zoom box model to set, or null for no zoom model. + * * @public */ setZoomBrush(zoomBrush: Box2dModel | null = null): this { @@ -7587,7 +7925,6 @@ export class Editor extends EventEmitter { * Rotate shapes by a delta in radians. * * @example - * * ```ts * editor.rotateShapesBy(['box1', 'box2'], Math.PI) * editor.rotateShapesBy(['box1', 'box2'], Math.PI / 2) @@ -7609,7 +7946,6 @@ export class Editor extends EventEmitter { * Move shapes by a delta. * * @example - * * ```ts * editor.nudgeShapes(['box1', 'box2'], { x: 0, y: 1 }) * editor.nudgeShapes(['box1', 'box2'], { x: 0, y: 1 }, true) @@ -7619,7 +7955,7 @@ export class Editor extends EventEmitter { * @param direction - The direction in which to move the shapes. * @param major - Whether this is a major nudge, e.g. a shift + arrow nudge. */ - nudgeShapes(ids: TLShapeId[], direction: Vec2dModel, major = false, ephemeral = false) { + nudgeShapes(ids: TLShapeId[], direction: Vec2dModel, major = false, ephemeral = false): this { if (ids.length <= 0) return this const step = this.isGridMode @@ -7668,7 +8004,6 @@ export class Editor extends EventEmitter { * Duplicate shapes. * * @example - * * ```ts * editor.duplicateShapes() * editor.duplicateShapes(['id1', 'id2']) @@ -7677,9 +8012,10 @@ export class Editor extends EventEmitter { * * @param ids - The ids of the shapes to duplicate. Defaults to the ids of the selected shapes. * @param offset - The offset (in pixels) to apply to the duplicated shapes. + * * @public */ - duplicateShapes(ids: TLShapeId[] = this.selectedIds, offset?: VecLike) { + duplicateShapes(ids: TLShapeId[] = this.selectedIds, offset?: VecLike): this { if (ids.length <= 0) return this const initialIds = new Set(ids) @@ -7862,14 +8198,11 @@ export class Editor extends EventEmitter { * editor.setOpacity(0.5, true) * ``` * - * @param opacity - The opacity to set. Must be a number between 0 and 1 - * inclusive. - * @param ephemeral - Whether the opacity change is ephemeral. Ephemeral - * changes don't get added to the undo/redo stack. Defaults to false. - * @param squashing - Whether the opacity change will be squashed into the - * existing history entry rather than creating a new one. Defaults to false. + * @param opacity - The opacity to set. Must be a number between 0 and 1 inclusive. + * @param ephemeral - Whether the opacity change is ephemeral. Ephemeral changes don't get added to the undo/redo stack. Defaults to false. + * @param squashing - Whether the opacity change will be squashed into the existing history entry rather than creating a new one. Defaults to false. */ - setOpacity(opacity: number, ephemeral = false, squashing = false) { + setOpacity(opacity: number, ephemeral = false, squashing = false): this { this.history.batch(() => { if (this.isIn('select')) { const { @@ -7928,13 +8261,12 @@ export class Editor extends EventEmitter { * * @param key - The key to set. * @param value - The value to set. - * @param ephemeral - Whether the style change is ephemeral. Ephemeral - * changes don't get added to the undo/redo stack. Defaults to false. - * @param squashing - Whether the style change will be squashed into the - * existing history entry rather than creating a new one. Defaults to false. + * @param ephemeral - Whether the style change is ephemeral. Ephemeral changes don't get added to the undo/redo stack. Defaults to false. + * @param squashing - Whether the style change will be squashed into the existing history entry rather than creating a new one. Defaults to false. + * * @public */ - setProp(key: TLShapeProp, value: any, ephemeral = false, squashing = false) { + setProp(key: TLShapeProp, value: any, ephemeral = false, squashing = false): this { this.history.batch(() => { if (this.isIn('select')) { const { @@ -8048,7 +8380,7 @@ export class Editor extends EventEmitter { private _willSetInitialBounds = true /** @internal */ - private _setCamera(x: number, y: number, z = this.camera.z) { + private _setCamera(x: number, y: number, z = this.camera.z): this { const currentCamera = this.camera if (currentCamera.x === x && currentCamera.y === y && currentCamera.z === z) return this const nextCamera = { ...currentCamera, x, y, z } @@ -8081,7 +8413,6 @@ export class Editor extends EventEmitter { * Set the current camera. * * @example - * * ```ts * editor.setCamera(0, 0) * editor.setCamera(0, 0, 1) @@ -8091,6 +8422,7 @@ export class Editor extends EventEmitter { * @param y - The camera's y position. * @param z - The camera's z position. Defaults to the current zoom. * @param options - Options for the camera change. + * * @public */ setCamera( @@ -8098,7 +8430,7 @@ export class Editor extends EventEmitter { y: number, z = this.camera.z, { stopFollowing = true }: TLViewportOptions = {} - ) { + ): this { this.stopCameraAnimation() if (stopFollowing && this.instanceState.followingUserId) { this.stopFollowingUser() @@ -8110,13 +8442,10 @@ export class Editor extends EventEmitter { return this } - enableAnimations = true - /** * Animate the camera. * * @example - * * ```ts * editor.animateCamera(0, 0) * editor.animateCamera(0, 0, 1) @@ -8127,6 +8456,7 @@ export class Editor extends EventEmitter { * @param y - The camera's y position. * @param z - The camera's z position. Defaults to the current zoom. * @param opts - Options for the animation. + * * @public */ animateCamera( @@ -8134,7 +8464,7 @@ export class Editor extends EventEmitter { y: number, z = this.camera.z, opts: TLAnimationOptions = DEFAULT_ANIMATION_OPTIONS - ) { + ): this { x = Number.isNaN(x) ? 0 : x y = Number.isNaN(y) ? 0 : y z = Number.isNaN(z) ? 1 : z @@ -8144,10 +8474,6 @@ export class Editor extends EventEmitter { const targetViewport = new Box2d(-x, -y, w, h) - if (!this.enableAnimations) { - return this.setCamera(x, y, this.viewportScreenBounds.width / w) - } - return this._animateToViewport(targetViewport, opts) } @@ -8155,7 +8481,6 @@ export class Editor extends EventEmitter { * Center the camera on a point (in page space). * * @example - * * ```ts * editor.centerOnPoint(100, 100) * ``` @@ -8163,6 +8488,7 @@ export class Editor extends EventEmitter { * @param x - The x position of the point. * @param y - The y position of the point. * @param opts - The options for an animation. + * * @public */ centerOnPoint(x: number, y: number, opts?: TLAnimationOptions): this { @@ -8207,7 +8533,6 @@ export class Editor extends EventEmitter { * Zoom the camera to fit the current page's content in the viewport. * * @example - * * ```ts * editor.zoomToFit() * ``` @@ -8236,12 +8561,12 @@ export class Editor extends EventEmitter { * Set the zoom back to 100%. * * @example - * * ```ts * editor.resetZoom() * ``` * * @param opts - The options for an animation. + * * @public */ resetZoom(point = this.viewportScreenCenter, opts?: TLAnimationOptions): this { @@ -8262,7 +8587,6 @@ export class Editor extends EventEmitter { * Zoom the camera in. * * @example - * * ```ts * editor.zoomIn() * editor.zoomIn(editor.viewportScreenCenter, { duration: 120 }) @@ -8270,6 +8594,7 @@ export class Editor extends EventEmitter { * ``` * * @param opts - The options for an animation. + * * @public */ zoomIn(point = this.viewportScreenCenter, opts?: TLAnimationOptions): this { @@ -8306,7 +8631,6 @@ export class Editor extends EventEmitter { * Zoom the camera out. * * @example - * * ```ts * editor.zoomOut() * editor.zoomOut(editor.viewportScreenCenter, { duration: 120 }) @@ -8314,6 +8638,7 @@ export class Editor extends EventEmitter { * ``` * * @param opts - The options for an animation. + * * @public */ zoomOut(point = this.viewportScreenCenter, opts?: TLAnimationOptions): this { @@ -8351,12 +8676,12 @@ export class Editor extends EventEmitter { * Zoom the camera to fit the current selection in the viewport. * * @example - * * ```ts * editor.zoomToSelection() * ``` * * @param opts - The options for an animation. + * * @public */ zoomToSelection(opts?: TLAnimationOptions): this { @@ -8380,11 +8705,11 @@ export class Editor extends EventEmitter { } /** - * Pan or pan/zoom the selected ids into view. This method tries to not change the zoom if - * possible. + * Pan or pan/zoom the selected ids into view. This method tries to not change the zoom if possible. * * @param ids - The ids of the shapes to pan and zoom into view. * @param opts - The options for an animation. + * * @public */ panZoomIntoView(ids: TLShapeId[], opts?: TLAnimationOptions): this { @@ -8458,7 +8783,6 @@ export class Editor extends EventEmitter { * Zoom the camera to fit a bounding box (in page space). * * @example - * * ```ts * editor.zoomToBounds(0, 0, 100, 100) * ``` @@ -8468,6 +8792,7 @@ export class Editor extends EventEmitter { * @param width - The bounding box's width. * @param height - The bounding box's height. * @param targetZoom - The desired zoom level. Defaults to 0.1. + * * @public */ zoomToBounds( @@ -8519,7 +8844,6 @@ export class Editor extends EventEmitter { * Pan the camera. * * @example - * * ```ts * editor.pan(100, 100) * editor.pan(100, 100, { duration: 1000 }) @@ -8643,6 +8967,12 @@ export class Editor extends EventEmitter { return this } + /** + * Slide the camera in a certain direction. + * + * @param opts - Options for the slide + * @public + */ slideCamera( opts = {} as { speed: number @@ -8691,6 +9021,7 @@ export class Editor extends EventEmitter { * Start viewport-following a user. * * @param userId - The id of the user to follow. + * * @public */ startFollowingUser(userId: string) { @@ -8823,6 +9154,11 @@ export class Editor extends EventEmitter { return this } + /** + * Animate the camera to a shape. + * + * @public + */ animateToShape(shapeId: TLShapeId, opts: TLAnimationOptions = DEFAULT_ANIMATION_OPTIONS): this { if (!this.canMoveCamera) return this @@ -8858,7 +9194,6 @@ export class Editor extends EventEmitter { * Blur the app, cancelling any interaction state. * * @example - * * ```ts * editor.blur() * ``` @@ -8876,7 +9211,6 @@ export class Editor extends EventEmitter { * Focus the editor. * * @example - * * ```ts * editor.focus() * ``` @@ -8893,7 +9227,6 @@ export class Editor extends EventEmitter { * Dispatch a cancel event. * * @example - * * ```ts * editor.cancel() * ``` @@ -8909,7 +9242,6 @@ export class Editor extends EventEmitter { * Dispatch an interrupt event. * * @example - * * ```ts * editor.interrupt() * ``` @@ -8925,7 +9257,6 @@ export class Editor extends EventEmitter { * Dispatch a complete event. * * @example - * * ```ts * editor.complete() * ``` @@ -8959,6 +9290,14 @@ export class Editor extends EventEmitter { /* --------------------- Groups --------------------- */ + /** + * Group some shapes together. + * + * @param ids - Ids of the shapes to group. Defaults to the selected shapes. + * @param groupId - Id of the group to create. Defaults to a new shape id. + * + * @public + */ groupShapes(ids: TLShapeId[] = this.selectedIds, groupId = createShapeId()) { if (this.isReadOnly) return this @@ -9007,6 +9346,13 @@ export class Editor extends EventEmitter { return this } + /** + * Ungroup some shapes. + * + * @param ids - Ids of the shapes to ungroup. Defaults to the selected shapes. + * + * @public + */ ungroupShapes(ids: TLShapeId[] = this.selectedIds) { if (this.isReadOnly) return this if (ids.length === 0) return this