diff --git a/tldraw/packages/core/src/lib/tools/TLBoxTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLBoxTool/states/IdleState.tsx index b81fc1eb46..875d99b3cf 100644 --- a/tldraw/packages/core/src/lib/tools/TLBoxTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLBoxTool/states/IdleState.tsx @@ -17,8 +17,8 @@ export class IdleState< } onPinchStart: TLStateEvents['onPinchStart'] = (...args) => { - this.app.transition('select', { returnTo: 'box' }) - this.app.onPinchStart?.(...args) + this.app.transition('select', { returnTo: this.app.currentState.id }) + this.app._events.onPinchStart?.(...args) } onKeyDown: TLStateEvents['onKeyDown'] = (info, e) => { diff --git a/tldraw/packages/core/src/lib/tools/TLDotTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLDotTool/states/IdleState.tsx index 6366bf0f29..6ac84d9d9c 100644 --- a/tldraw/packages/core/src/lib/tools/TLDotTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLDotTool/states/IdleState.tsx @@ -17,8 +17,8 @@ export class IdleState< } onPinchStart: TLStateEvents['onPinchStart'] = (...args) => { - this.app.transition('select', { returnTo: 'box' }) - this.app.onPinchStart?.(...args) + this.app.transition('select', { returnTo: this.app.currentState.id }) + this.app._events.onPinchStart?.(...args) } onKeyDown: TLStateEvents['onKeyDown'] = (info, e) => { diff --git a/tldraw/packages/core/src/lib/tools/TLDrawTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLDrawTool/states/IdleState.tsx index fdf82316ab..61592d8c9c 100644 --- a/tldraw/packages/core/src/lib/tools/TLDrawTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLDrawTool/states/IdleState.tsx @@ -17,7 +17,7 @@ export class IdleState< } onPinchStart: TLStateEvents['onPinchStart'] = (...args) => { - this.app.transition('select', { returnTo: 'draw' }) + this.app.transition('select', { returnTo: this.app.currentState.id }) this.app._events.onPinchStart?.(...args) } diff --git a/tldraw/packages/core/src/lib/tools/TLEraseTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLEraseTool/states/IdleState.tsx index cbd5ef30cf..fbd7722d6c 100644 --- a/tldraw/packages/core/src/lib/tools/TLEraseTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLEraseTool/states/IdleState.tsx @@ -16,8 +16,8 @@ export class IdleState< } onPinchStart: TLStateEvents['onPinchStart'] = (...args) => { - this.app.transition('select', { returnTo: 'draw' }) - this.app.onPinchStart?.(...args) + this.app.transition('select', { returnTo: this.app.currentState.id }) + this.app._events.onPinchStart?.(...args) } onKeyDown: TLStateEvents['onKeyDown'] = (info, e) => { diff --git a/tldraw/packages/core/src/lib/tools/TLLineTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLLineTool/states/IdleState.tsx index f1692ae2d3..a27b5f01f0 100644 --- a/tldraw/packages/core/src/lib/tools/TLLineTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLLineTool/states/IdleState.tsx @@ -17,8 +17,8 @@ export class IdleState< } onPinchStart: TLStateEvents['onPinchStart'] = (...args) => { - this.app.transition('select', { returnTo: 'Line' }) - this.app.onPinchStart?.(...args) + this.app.transition('select', { returnTo: this.app.currentState.id }) + this.app._events.onPinchStart?.(...args) } onKeyDown: TLStateEvents['onKeyDown'] = (info, e) => { diff --git a/tldraw/packages/core/src/lib/tools/TLMoveTool/TLMoveTool.ts b/tldraw/packages/core/src/lib/tools/TLMoveTool/TLMoveTool.ts index 2d18a67384..97334e1e46 100644 --- a/tldraw/packages/core/src/lib/tools/TLMoveTool/TLMoveTool.ts +++ b/tldraw/packages/core/src/lib/tools/TLMoveTool/TLMoveTool.ts @@ -1,6 +1,6 @@ import { TLApp, TLShape, TLTool } from '~lib' -import { TLCursor, TLEventMap } from '~types' -import { IdleHoldState, IdleState, PanningState } from './states' +import { TLCursor, TLEventMap, TLStateEvents } from '~types' +import { IdleHoldState, IdleState, PanningState, PinchingState } from './states' export class TLMoveTool< S extends TLShape = TLShape, @@ -10,7 +10,7 @@ export class TLMoveTool< static id = 'move' static shortcut = ['h'] - static states = [IdleState, IdleHoldState, PanningState] + static states = [IdleState, IdleHoldState, PanningState, PinchingState] static initial = 'idle' @@ -21,4 +21,13 @@ export class TLMoveTool< onEnter = (info: any) => { this.prevTool = info?.prevTool } + + onKeyDown: TLStateEvents['onKeyDown'] = (info, e) => { + switch (e.key) { + case 'Escape': { + this.app.transition('select') + break + } + } + } } diff --git a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleHoldState.tsx b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleHoldState.tsx index 4beb20d024..be6aa96178 100644 --- a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleHoldState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleHoldState.tsx @@ -1,5 +1,5 @@ import { TLApp, TLShape, TLToolState } from '~lib' -import type { TLEventMap, TLStateEvents } from '~types' +import type { TLEventMap, TLEvents, TLStateEvents } from '~types' import type { TLMoveTool } from '../TLMoveTool' export class IdleHoldState< @@ -14,4 +14,8 @@ export class IdleHoldState< if (info.order) return this.tool.transition('panning', { prevState: 'idleHold' }) } + + onPinchStart: TLEvents['pinch'] = (info, event) => { + this.tool.transition('pinching', { info, event }) + } } diff --git a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleState.tsx index 055621800e..5cf41dd1bc 100644 --- a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleState.tsx @@ -1,5 +1,5 @@ import { TLApp, TLShape, TLToolState } from '~lib' -import type { TLEventMap, TLStateEvents } from '~types' +import type { TLEventMap, TLEvents, TLStateEvents } from '~types' import type { TLMoveTool } from '../TLMoveTool' export class IdleState< @@ -20,6 +20,10 @@ export class IdleState< } } + onPinchStart: TLEvents['pinch'] = (info, event) => { + this.tool.transition('pinching', { info, event }) + } + onPointerDown: TLStateEvents['onPointerDown'] = (info, e) => { if (info.order) return this.tool.transition('panning') diff --git a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/PinchingState.ts b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/PinchingState.ts new file mode 100644 index 0000000000..a57028fd3d --- /dev/null +++ b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/PinchingState.ts @@ -0,0 +1,46 @@ +import { Vec } from '@tldraw/vec' +import { TLApp, TLMoveTool, TLShape, TLToolState } from '~lib' +import type { TLEventInfo, TLEventMap, TLEvents } from '~types' + +type GestureInfo< + S extends TLShape, + K extends TLEventMap, + E extends TLEventInfo = TLEventInfo +> = { + info: E & { delta: number[]; point: number[]; offset: number[] } + event: K['wheel'] | K['pointer'] | K['touch'] | K['keyboard'] | K['gesture'] +} + +export class PinchingState< + S extends TLShape, + K extends TLEventMap, + R extends TLApp, + P extends TLMoveTool +> extends TLToolState { + static id = 'pinching' + + private origin: number[] = [0, 0] + + private prevDelta: number[] = [0, 0] + + private pinchCamera(point: number[], delta: number[], zoom: number) { + const { camera } = this.app.viewport + const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom)) + const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint) + const p1 = Vec.sub(Vec.div(point, zoom), nextPoint) + this.app.setCamera(Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom) + } + + onEnter = (info: GestureInfo) => { + this.prevDelta = info.info.delta + this.origin = info.info.point + } + + onPinch: TLEvents['pinch'] = info => { + this.pinchCamera(info.point, [0, 0], info.offset[0]) + } + + onPinchEnd: TLEvents['pinch'] = () => { + this.tool.transition('idle') + } +} diff --git a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/index.ts b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/index.ts index 0c40725a39..30afc6a06e 100644 --- a/tldraw/packages/core/src/lib/tools/TLMoveTool/states/index.ts +++ b/tldraw/packages/core/src/lib/tools/TLMoveTool/states/index.ts @@ -1,3 +1,4 @@ export * from './PanningState' export * from './IdleState' export * from './IdleHoldState' +export * from './PinchingState' \ No newline at end of file diff --git a/tldraw/packages/core/src/lib/tools/TLSelectTool/TLSelectTool.tsx b/tldraw/packages/core/src/lib/tools/TLSelectTool/TLSelectTool.tsx index 0da02473a7..7cce836304 100644 --- a/tldraw/packages/core/src/lib/tools/TLSelectTool/TLSelectTool.tsx +++ b/tldraw/packages/core/src/lib/tools/TLSelectTool/TLSelectTool.tsx @@ -53,4 +53,10 @@ export class TLSelectTool< PinchingState, EditingShapeState, ] + + returnTo = '' + + onEnter = (info: { fromId: string, returnTo: string } & any) => { + this.returnTo = info?.returnTo + } } diff --git a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/IdleState.ts b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/IdleState.ts index 522e6ba141..41cc6eb47b 100644 --- a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/IdleState.ts +++ b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/IdleState.ts @@ -11,9 +11,9 @@ export class IdleState< static id = 'idle' onEnter = (info: { fromId: string } & any) => { - // if (info.fromId === 'editingShape') { - // this.onPointerDown(info as any, {} as any) - // } + if (info.fromId === 'pinching' && this.parent.returnTo) { + this.app.transition(this.parent.returnTo) + } } onExit = () => { diff --git a/tldraw/packages/core/src/lib/tools/TLTextTool/states/IdleState.tsx b/tldraw/packages/core/src/lib/tools/TLTextTool/states/IdleState.tsx index 559906c45e..c4e31b06a4 100644 --- a/tldraw/packages/core/src/lib/tools/TLTextTool/states/IdleState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLTextTool/states/IdleState.tsx @@ -17,8 +17,8 @@ export class IdleState< } onPinchStart: TLStateEvents['onPinchStart'] = (...args) => { - this.app.transition('select', { returnTo: 'box' }) - this.app.onPinchStart?.(...args) + this.app.transition('select', { returnTo: this.app.currentState.id }) + this.app._events.onPinchStart?.(...args) } onKeyDown: TLStateEvents['onKeyDown'] = (info, e) => {