tldraw
Version:
A tiny little drawing editor.
110 lines (83 loc) • 2.52 kB
text/typescript
import { isAccelKey, StateNode, TLPointerEventInfo, TLShapeId } from '@tldraw/editor'
export class Pointing extends StateNode {
static override id = 'pointing'
_isHoldingAccelKey = false
override onEnter() {
this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
const zoomLevel = this.editor.getZoomLevel()
const currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()
const currentPagePoint = this.editor.inputs.getCurrentPagePoint()
const erasing = new Set<TLShapeId>()
const initialSize = erasing.size
for (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {
const shape = currentPageShapesSorted[i]
if (this.editor.isShapeOrAncestorLocked(shape) || this.editor.isShapeOfType(shape, 'group')) {
continue
}
if (
this.editor.isPointInShape(shape, currentPagePoint, {
hitInside: false,
margin: this.editor.options.hitTestMargin / zoomLevel,
})
) {
const hitShape = this.editor.getOutermostSelectableShape(shape)
// If we've hit a frame after hitting any other shape, stop here
if (this.editor.isShapeOfType(hitShape, 'frame') && erasing.size > initialSize) {
break
}
erasing.add(hitShape.id)
// If the user is holding the meta / ctrl key, stop after the first shape
if (this._isHoldingAccelKey) {
break
}
}
}
this.editor.setErasingShapes([...erasing])
}
override onKeyUp() {
this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
}
override onKeyDown() {
this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
}
override onLongPress(info: TLPointerEventInfo) {
this.startErasing(info)
}
override onExit(_info: any, to: string) {
if (to !== 'erasing') {
this.editor.setErasingShapes([])
}
}
override onPointerMove(info: TLPointerEventInfo) {
if (this._isHoldingAccelKey) return
if (this.editor.inputs.getIsDragging()) {
this.startErasing(info)
}
}
override onPointerUp() {
this.complete()
}
override onCancel() {
this.cancel()
}
override onComplete() {
this.complete()
}
override onInterrupt() {
this.cancel()
}
private startErasing(info: TLPointerEventInfo) {
this.parent.transition('erasing', info)
}
complete() {
const erasingShapeIds = this.editor.getErasingShapeIds()
if (erasingShapeIds.length) {
this.editor.markHistoryStoppingPoint('erase end')
this.editor.deleteShapes(erasingShapeIds)
}
this.parent.transition('idle')
}
cancel() {
this.parent.transition('idle')
}
}