UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

157 lines (130 loc) 3.9 kB
import { TLShape, createShapeId } from '@tldraw/tlschema' import { structuredClone } from '@tldraw/utils' import { Vec } from '../../../../primitives/Vec' import { Editor } from '../../../Editor' import { TLBaseBoxShape } from '../../../shapes/BaseBoxShapeUtil' import { TLPointerEventInfo } from '../../../types/event-types' import { StateNode } from '../../StateNode' import { BaseBoxShapeTool } from '../BaseBoxShapeTool' export class Pointing extends StateNode { static override id = 'pointing' override onPointerMove(info: TLPointerEventInfo) { const { editor } = this if (editor.inputs.isDragging) { const { originPagePoint } = editor.inputs const shapeType = (this.parent as BaseBoxShapeTool)!.shapeType const id = createShapeId() const creatingMarkId = editor.markHistoryStoppingPoint(`creating_box:${id}`) const newPoint = maybeSnapToGrid(originPagePoint, editor) // Allow this to trigger the max shapes reached alert this.editor.createShapes<TLBaseBoxShape>([ { id, type: shapeType, x: newPoint.x, y: newPoint.y, props: { w: 1, h: 1, }, }, ]) const shape = editor.getShape(id) if (!shape) { this.cancel() return } editor.select(id) const parent = this.parent as BaseBoxShapeTool this.editor.setCurrentTool( 'select.resizing', { ...info, target: 'selection', handle: 'bottom_right', isCreating: true, creatingMarkId, creationCursorOffset: { x: 1, y: 1 }, onInteractionEnd: this.parent.id, onCreate: parent.onCreate ? (shape: TLShape | null) => parent.onCreate?.(shape) : undefined, } /** satisfies ResizingInfo, defined in main tldraw package 😧 */ ) } } override onPointerUp() { this.complete() } override onCancel() { this.cancel() } override onComplete() { this.complete() } override onInterrupt() { this.cancel() } complete() { const { originPagePoint } = this.editor.inputs const shapeType = (this.parent as BaseBoxShapeTool)!.shapeType as TLBaseBoxShape['type'] const id = createShapeId() this.editor.markHistoryStoppingPoint(`creating_box:${id}`) // Allow this to trigger the max shapes reached alert // todo: add scale here when dynamic size is enabled (is this still needed?) this.editor.createShapes<TLBaseBoxShape>([ { id, type: shapeType, x: originPagePoint.x, y: originPagePoint.y, }, ]) const shape = this.editor.getShape<TLBaseBoxShape>(id)! if (!shape) { this.cancel() return } let { w, h } = shape.props const delta = new Vec(w / 2, h / 2) const parentTransform = this.editor.getShapeParentTransform(shape) if (parentTransform) delta.rot(-parentTransform.rotation()) let scale = 1 if (this.editor.user.getIsDynamicResizeMode()) { scale = 1 / this.editor.getZoomLevel() w *= scale h *= scale delta.mul(scale) } const next = structuredClone(shape) const newPoint = maybeSnapToGrid(new Vec(shape.x - delta.x, shape.y - delta.y), this.editor) next.x = newPoint.x next.y = newPoint.y next.props.w = w next.props.h = h if ('scale' in shape.props) { ;(next as TLBaseBoxShape & { props: { scale: number } }).props.scale = scale } this.editor.updateShape<TLBaseBoxShape>(next) this.editor.setSelectedShapes([id]) if (this.editor.getInstanceState().isToolLocked) { this.parent.transition('idle') } else { this.editor.setCurrentTool('select.idle') } } cancel() { this.parent.transition('idle') } } /** * Checks if grid mode is enabled and snaps a point to the grid if so * * @public */ export function maybeSnapToGrid(point: Vec, editor: Editor): Vec { const isGridMode = editor.getInstanceState().isGridMode const gridSize = editor.getDocumentSettings().gridSize if (isGridMode) return point.clone().snapToGrid(gridSize) return point.clone() }