فهرست منبع

fix(whiteboard): refactor pinch to support mobile

Peng Xiao 3 سال پیش
والد
کامیت
bebb8cf897
38فایلهای تغییر یافته به همراه171 افزوده شده و 209 حذف شده
  1. 1 1
      tldraw/apps/tldraw-logseq/src/lib/tools/LogseqPortalTool/LogseqPortalTool.tsx
  2. 0 9
      tldraw/packages/core/src/lib/TLApp/TLApp.ts
  3. 0 4
      tldraw/packages/core/src/lib/TLBaseLineBindingState.ts
  4. 8 18
      tldraw/packages/core/src/lib/TLInputs.ts
  5. 0 13
      tldraw/packages/core/src/lib/TLState.ts
  6. 14 12
      tldraw/packages/core/src/lib/TLViewport.ts
  7. 0 4
      tldraw/packages/core/src/lib/tools/TLBoxTool/states/CreatingState.tsx
  8. 0 4
      tldraw/packages/core/src/lib/tools/TLDotTool/states/CreatingState.tsx
  9. 7 3
      tldraw/packages/core/src/lib/tools/TLDrawTool/TLDrawTool.tsx
  10. 5 5
      tldraw/packages/core/src/lib/tools/TLDrawTool/states/CreatingState.tsx
  11. 3 4
      tldraw/packages/core/src/lib/tools/TLDrawTool/states/IdleState.tsx
  12. 41 0
      tldraw/packages/core/src/lib/tools/TLDrawTool/states/PinchingState.ts
  13. 1 0
      tldraw/packages/core/src/lib/tools/TLDrawTool/states/index.ts
  14. 0 4
      tldraw/packages/core/src/lib/tools/TLEraseTool/states/ErasingState.tsx
  15. 5 1
      tldraw/packages/core/src/lib/tools/TLMoveTool/TLMoveTool.ts
  16. 0 4
      tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleState.tsx
  17. 1 1
      tldraw/packages/core/src/lib/tools/TLMoveTool/states/PanningState.tsx
  18. 2 2
      tldraw/packages/core/src/lib/tools/TLMoveTool/states/PinchingState.ts
  19. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/BrushingState.ts
  20. 2 31
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PinchingState.ts
  21. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingBoundsBackgroundState.ts
  22. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingCanvasState.ts
  23. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingHandleState.ts
  24. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingMinimapState.ts
  25. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingResizeHandleState.ts
  26. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingRotateHandleState.ts
  27. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingSelectedShapeState.ts
  28. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingShapeBehindBoundsState.ts
  29. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingShapeState.ts
  30. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/ResizingState.ts
  31. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/RotatingState.ts
  32. 0 4
      tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts
  33. 0 1
      tldraw/packages/core/src/types/TLEventHandlers.ts
  34. 0 1
      tldraw/packages/core/src/types/TLEventMap.ts
  35. 2 3
      tldraw/packages/core/src/types/TLEvents.ts
  36. 79 30
      tldraw/packages/react/src/hooks/useGestureEvents.ts
  37. 0 1
      tldraw/packages/react/src/types/TLReactCustomEvents.ts
  38. 0 1
      tldraw/packages/react/src/types/TLReactEventHandlers.ts

+ 1 - 1
tldraw/apps/tldraw-logseq/src/lib/tools/LogseqPortalTool/LogseqPortalTool.tsx

@@ -16,6 +16,6 @@ export class LogseqPortalTool extends TLTool<
   Shape = LogseqPortalShape
   Shape = LogseqPortalShape
 
 
   onPinch: TLEvents<Shape>['pinch'] = info => {
   onPinch: TLEvents<Shape>['pinch'] = info => {
-    this.app.viewport.pinchCamera(info.point, [0, 0], info.offset[0])
+    this.app.viewport.pinchZoom(info.point, info.delta, info.delta[2])
   }
   }
 }
 }

+ 0 - 9
tldraw/packages/core/src/lib/TLApp/TLApp.ts

@@ -927,15 +927,6 @@ export class TLApp<
 
 
   readonly onTransition: TLStateEvents<S, K>['onTransition'] = () => {}
   readonly onTransition: TLStateEvents<S, K>['onTransition'] = () => {}
 
 
-  readonly onWheel: TLEvents<S, K>['wheel'] = (info, e) => {
-    if (e.ctrlKey || e.metaKey || this.isIn('select.contextMenu')) {
-      return
-    }
-
-    this.viewport.panCamera(info.delta)
-    this.inputs.onWheel([...this.viewport.getPagePoint([e.clientX, e.clientY]), 0.5], e)
-  }
-
   readonly onPointerDown: TLEvents<S, K>['pointer'] = (info, e) => {
   readonly onPointerDown: TLEvents<S, K>['pointer'] = (info, e) => {
     // Pan canvas when holding middle click
     // Pan canvas when holding middle click
     if (!this.editingShape && e.button === 1 && !this.isIn('move')) {
     if (!this.editingShape && e.button === 1 && !this.isIn('move')) {

+ 0 - 4
tldraw/packages/core/src/lib/TLBaseLineBindingState.ts

@@ -219,10 +219,6 @@ export class TLBaseLineBindingState<
     this.app.persist()
     this.app.persist()
   }
   }
 
 
-  onWheel: TLStateEvents<S, K>['onWheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onExit: TLStateEvents<S, K>['onExit'] = () => {
   onExit: TLStateEvents<S, K>['onExit'] = () => {
     this.app.clearBindingShape()
     this.app.clearBindingShape()
     this.app.history.resume()
     this.app.history.resume()

+ 8 - 18
tldraw/packages/core/src/lib/TLInputs.ts

@@ -33,9 +33,10 @@ export class TLInputs<K extends TLEventMap> {
     Object.assign(this.containerOffset, containerOffset)
     Object.assign(this.containerOffset, containerOffset)
   }
   }
 
 
-  @action private updateModifiers(
-    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['wheel'] | K['touch']
-  ) {
+  @action private updateModifiers(event: K['gesture'] | K['pointer'] | K['keyboard'] | K['touch']) {
+    if (!event.isPrimary) {
+      return
+    }
     if ('clientX' in event) {
     if ('clientX' in event) {
       this.previousScreenPoint = this.currentScreenPoint
       this.previousScreenPoint = this.currentScreenPoint
       this.currentScreenPoint = Vec.sub([event.clientX, event.clientY], this.containerOffset)
       this.currentScreenPoint = Vec.sub([event.clientX, event.clientY], this.containerOffset)
@@ -48,18 +49,7 @@ export class TLInputs<K extends TLEventMap> {
     }
     }
   }
   }
 
 
-  @action onWheel = (pagePoint: number[], event: K['wheel']) => {
-    // if (this.state === 'pinching') return
-    this.updateModifiers(event)
-    this.previousPoint = this.currentPoint
-    this.currentPoint = pagePoint
-    // start panning = true here in panCamera (called in TLApp)
-    this.state = 'panning'
-    // otherwise, set panning = false?
-  }
-
   @action onPointerDown = (pagePoint: number[], event: K['pointer']) => {
   @action onPointerDown = (pagePoint: number[], event: K['pointer']) => {
-    // if (this.pointerIds.size > 0) return
     this.pointerIds.add(event.pointerId)
     this.pointerIds.add(event.pointerId)
     this.updateModifiers(event)
     this.updateModifiers(event)
     this.originScreenPoint = this.currentScreenPoint
     this.originScreenPoint = this.currentScreenPoint
@@ -69,7 +59,7 @@ export class TLInputs<K extends TLEventMap> {
 
 
   @action onPointerMove = (
   @action onPointerMove = (
     pagePoint: number[],
     pagePoint: number[],
-    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['wheel'] | K['touch']
+    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['touch']
   ) => {
   ) => {
     if (this.state === 'pinching') return
     if (this.state === 'pinching') return
     if (this.state === 'panning') {
     if (this.state === 'panning') {
@@ -110,7 +100,7 @@ export class TLInputs<K extends TLEventMap> {
 
 
   @action onPinchStart = (
   @action onPinchStart = (
     pagePoint: number[],
     pagePoint: number[],
-    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['wheel'] | K['touch']
+    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['touch']
   ) => {
   ) => {
     this.updateModifiers(event)
     this.updateModifiers(event)
     this.state = 'pinching'
     this.state = 'pinching'
@@ -118,7 +108,7 @@ export class TLInputs<K extends TLEventMap> {
 
 
   @action onPinch = (
   @action onPinch = (
     pagePoint: number[],
     pagePoint: number[],
-    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['wheel'] | K['touch']
+    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['touch']
   ) => {
   ) => {
     if (this.state !== 'pinching') return
     if (this.state !== 'pinching') return
     this.updateModifiers(event)
     this.updateModifiers(event)
@@ -126,7 +116,7 @@ export class TLInputs<K extends TLEventMap> {
 
 
   @action onPinchEnd = (
   @action onPinchEnd = (
     pagePoint: number[],
     pagePoint: number[],
-    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['wheel'] | K['touch']
+    event: K['gesture'] | K['pointer'] | K['keyboard'] | K['touch']
   ) => {
   ) => {
     if (this.state !== 'pinching') return
     if (this.state !== 'pinching') return
     this.updateModifiers(event)
     this.updateModifiers(event)

+ 0 - 13
tldraw/packages/core/src/lib/TLState.ts

@@ -204,18 +204,6 @@ export abstract class TLRootState<S extends TLShape, K extends TLEventMap>
       this.onExit?.(info)
       this.onExit?.(info)
     },
     },
 
 
-    /**
-     * Respond to wheel events forwarded to the state by its parent. Run the current active child
-     * state's handler, then the state's own handler.
-     *
-     * @param info The event info from TLInputs.
-     * @param event The DOM event.
-     */
-    onWheel: (info, event) => {
-      this.onWheel?.(info, event)
-      this.forwardEvent('onWheel', info, event)
-    },
-
     /**
     /**
      * Respond to pointer down events forwarded to the state by its parent. Run the current active
      * Respond to pointer down events forwarded to the state by its parent. Run the current active
      * child state's handler, then the state's own handler.
      * child state's handler, then the state's own handler.
@@ -382,7 +370,6 @@ export abstract class TLRootState<S extends TLShape, K extends TLEventMap>
   onEnter?: TLStateEvents<S, K>['onEnter']
   onEnter?: TLStateEvents<S, K>['onEnter']
   onExit?: TLStateEvents<S, K>['onExit']
   onExit?: TLStateEvents<S, K>['onExit']
   onTransition?: TLStateEvents<S, K>['onTransition']
   onTransition?: TLStateEvents<S, K>['onTransition']
-  onWheel?: TLEvents<S, K>['wheel']
   onPointerDown?: TLEvents<S, K>['pointer']
   onPointerDown?: TLEvents<S, K>['pointer']
   onPointerUp?: TLEvents<S, K>['pointer']
   onPointerUp?: TLEvents<S, K>['pointer']
   onPointerMove?: TLEvents<S, K>['pointer']
   onPointerMove?: TLEvents<S, K>['pointer']

+ 14 - 12
tldraw/packages/core/src/lib/TLViewport.ts

@@ -46,15 +46,6 @@ export class TLViewport {
     return this
     return this
   }
   }
 
 
-  private _currentView = {
-    minX: 0,
-    minY: 0,
-    maxX: 1,
-    maxY: 1,
-    width: 1,
-    height: 1,
-  }
-
   @computed get currentView(): TLBounds {
   @computed get currentView(): TLBounds {
     const {
     const {
       bounds,
       bounds,
@@ -82,10 +73,21 @@ export class TLViewport {
     return Vec.mul(Vec.add(point, camera.point), camera.zoom)
     return Vec.mul(Vec.add(point, camera.point), camera.zoom)
   }
   }
 
 
-  pinchCamera = (point: number[], delta: number[], zoom: number): this => {
+  onZoom = (point: number[], zoom: number): this => {
+    return this.pinchZoom(point, [0, 0], zoom)
+  }
+
+  /**
+   * Pinch to a new zoom level, possibly together with a pan.
+   *
+   * @param point The current point under the cursor.
+   * @param delta The movement delta.
+   * @param zoom The new zoom level
+   */
+  pinchZoom = (point: number[], delta: number[], zoom: number): this => {
     const { camera } = this
     const { camera } = this
-    zoom = Math.max(TLViewport.minZoom, Math.min(TLViewport.maxZoom, zoom))
     const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
     const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
+    zoom = Vec.clamp(zoom, TLViewport.minZoom, TLViewport.maxZoom)
     const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
     const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
     const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
     const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
     return this.update({ point: Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom })
     return this.update({ point: Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom })
@@ -94,7 +96,7 @@ export class TLViewport {
   setZoom = (zoom: number) => {
   setZoom = (zoom: number) => {
     const { bounds } = this
     const { bounds } = this
     const center = [bounds.width / 2, bounds.height / 2]
     const center = [bounds.width / 2, bounds.height / 2]
-    this.pinchCamera(center, [0, 0], zoom)
+    this.onZoom(center, zoom)
   }
   }
 
 
   zoomIn = () => {
   zoomIn = () => {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLBoxTool/states/CreatingState.tsx

@@ -89,10 +89,6 @@ export class CreatingState<
     this.app.persist()
     this.app.persist()
   }
   }
 
 
-  onWheel: TLStateEvents<S, K>['onWheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
     switch (e.key) {
     switch (e.key) {
       case 'Escape': {
       case 'Escape': {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLDotTool/states/CreatingState.tsx

@@ -51,10 +51,6 @@ export class CreatingState<
     this.app.persist()
     this.app.persist()
   }
   }
 
 
-  onWheel: TLStateEvents<S, K>['onWheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
     switch (e.key) {
     switch (e.key) {
       case 'Escape': {
       case 'Escape': {

+ 7 - 3
tldraw/packages/core/src/lib/tools/TLDrawTool/TLDrawTool.tsx

@@ -1,8 +1,8 @@
-import { type TLEventMap, TLCursor } from '../../../types'
+import { type TLEventMap, TLCursor, TLEvents } from '../../../types'
 import type { TLDrawShape, TLShape, TLDrawShapeProps } from '../../shapes'
 import type { TLDrawShape, TLShape, TLDrawShapeProps } from '../../shapes'
 import type { TLApp } from '../../TLApp'
 import type { TLApp } from '../../TLApp'
 import { TLTool } from '../../TLTool'
 import { TLTool } from '../../TLTool'
-import { IdleState, CreatingState } from './states'
+import { IdleState, CreatingState, PinchingState } from './states'
 
 
 export abstract class TLDrawTool<
 export abstract class TLDrawTool<
   T extends TLDrawShape = TLDrawShape,
   T extends TLDrawShape = TLDrawShape,
@@ -12,7 +12,7 @@ export abstract class TLDrawTool<
 > extends TLTool<S, K, R> {
 > extends TLTool<S, K, R> {
   static id = 'draw'
   static id = 'draw'
 
 
-  static states = [IdleState, CreatingState]
+  static states = [IdleState, CreatingState, PinchingState]
 
 
   static initial = 'idle'
   static initial = 'idle'
 
 
@@ -30,4 +30,8 @@ export abstract class TLDrawTool<
     new (props: TLDrawShapeProps): T
     new (props: TLDrawShapeProps): T
     id: string
     id: string
   }
   }
+
+  onPinchStart: TLEvents<S>['pinch'] = (info, event) => {
+    this.transition('pinching', { info, event })
+  }
 }
 }

+ 5 - 5
tldraw/packages/core/src/lib/tools/TLDrawTool/states/CreatingState.tsx

@@ -1,5 +1,5 @@
 import { Vec } from '@tldraw/vec'
 import { Vec } from '@tldraw/vec'
-import type { TLEventMap, TLStateEvents } from '../../../../types'
+import type { TLEventMap, TLEvents, TLStateEvents } from '../../../../types'
 import { lerp, uniqueId, PointUtils } from '../../../../utils'
 import { lerp, uniqueId, PointUtils } from '../../../../utils'
 import type { TLShape, TLDrawShape } from '../../../shapes'
 import type { TLShape, TLDrawShape } from '../../../shapes'
 import type { TLApp } from '../../../TLApp'
 import type { TLApp } from '../../../TLApp'
@@ -36,6 +36,10 @@ export class CreatingState<
     }
     }
   }
   }
 
 
+  onPinchStart: TLEvents<S>['pinch'] = (info, event) => {
+    this.tool.transition('pinching', { info, event })
+  }
+
   onEnter = () => {
   onEnter = () => {
     const { Shape, previousShape } = this.tool
     const { Shape, previousShape } = this.tool
     const { originPoint } = this.app.inputs
     const { originPoint } = this.app.inputs
@@ -93,10 +97,6 @@ export class CreatingState<
     this.app.persist()
     this.app.persist()
   }
   }
 
 
-  onWheel: TLStateEvents<S, K>['onWheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
     switch (e.key) {
     switch (e.key) {
       case 'Escape': {
       case 'Escape': {

+ 3 - 4
tldraw/packages/core/src/lib/tools/TLDrawTool/states/IdleState.tsx

@@ -1,4 +1,4 @@
-import type { TLEventMap, TLStateEvents } from '../../../../types'
+import type { TLEventMap, TLEvents, TLStateEvents } from '../../../../types'
 import type { TLShape, TLDrawShape } from '../../../shapes'
 import type { TLShape, TLDrawShape } from '../../../shapes'
 import type { TLApp } from '../../../TLApp'
 import type { TLApp } from '../../../TLApp'
 import { TLToolState } from '../../../TLToolState'
 import { TLToolState } from '../../../TLToolState'
@@ -18,9 +18,8 @@ export class IdleState<
     this.tool.transition('creating')
     this.tool.transition('creating')
   }
   }
 
 
-  onPinchStart: TLStateEvents<S, K>['onPinchStart'] = (...args) => {
-    this.app.transition('select', { returnTo: this.app.currentState.id })
-    this.app._events.onPinchStart?.(...args)
+  onPinchStart: TLEvents<S>['pinch'] = (info, event) => {
+    this.tool.transition('pinching', { info, event })
   }
   }
 
 
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {

+ 41 - 0
tldraw/packages/core/src/lib/tools/TLDrawTool/states/PinchingState.ts

@@ -0,0 +1,41 @@
+import type { TLEventMap, TLEventInfo, TLEvents } from '../../../../types'
+import type { TLDrawShape, TLShape } from '../../../shapes'
+import type { TLApp } from '../../../TLApp'
+import { TLToolState } from '../../../TLToolState'
+import type { TLDrawTool } from '../TLDrawTool'
+
+type GestureInfo<
+  S extends TLShape,
+  K extends TLEventMap,
+  E extends TLEventInfo<S> = TLEventInfo<S>
+> = {
+  info: E & { delta: number[]; point: number[]; offset: number[] }
+  event: K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
+}
+
+export class PinchingState<
+  S extends TLShape,
+  T extends S & TLDrawShape,
+  K extends TLEventMap,
+  R extends TLApp<S, K>,
+  P extends TLDrawTool<T, S, K, R>
+> extends TLToolState<S, K, R, P> {
+  static id = 'pinching'
+
+  private origin: number[] = [0, 0]
+
+  private prevDelta: number[] = [0, 0]
+
+  onEnter = (info: GestureInfo<S, K>) => {
+    this.prevDelta = info.info.delta
+    this.origin = info.info.point
+  }
+
+  onPinch: TLEvents<S>['pinch'] = info => {
+    this.app.viewport.pinchZoom(info.point, info.delta, info.delta[2])
+  }
+
+  onPinchEnd: TLEvents<S>['pinch'] = () => {
+    this.tool.transition('idle')
+  }
+}

+ 1 - 0
tldraw/packages/core/src/lib/tools/TLDrawTool/states/index.ts

@@ -1,2 +1,3 @@
 export * from './CreatingState'
 export * from './CreatingState'
 export * from './IdleState'
 export * from './IdleState'
+export * from './PinchingState'

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLEraseTool/states/ErasingState.tsx

@@ -39,10 +39,6 @@ export class ErasingState<
     this.tool.transition('idle')
     this.tool.transition('idle')
   }
   }
 
 
-  onWheel: TLStateEvents<S, K>['onWheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
   onKeyDown: TLStateEvents<S>['onKeyDown'] = (info, e) => {
     switch (e.key) {
     switch (e.key) {
       case 'Escape': {
       case 'Escape': {

+ 5 - 1
tldraw/packages/core/src/lib/tools/TLMoveTool/TLMoveTool.ts

@@ -1,4 +1,4 @@
-import { type TLEventMap, TLCursor, type TLStateEvents } from '../../../types'
+import { type TLEventMap, TLCursor, type TLStateEvents, TLEvents } from '../../../types'
 import type { TLShape } from '../../shapes'
 import type { TLShape } from '../../shapes'
 import type { TLApp } from '../../TLApp'
 import type { TLApp } from '../../TLApp'
 import { TLTool } from '../../TLTool'
 import { TLTool } from '../../TLTool'
@@ -32,4 +32,8 @@ export class TLMoveTool<
       }
       }
     }
     }
   }
   }
+
+  onPinchStart: TLEvents<S>['pinch'] = (info, event) => {
+    this.transition('pinching', { info, event })
+  }
 }
 }

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLMoveTool/states/IdleState.tsx

@@ -22,10 +22,6 @@ export class IdleState<
     }
     }
   }
   }
 
 
-  onPinchStart: TLEvents<S>['pinch'] = (info, event) => {
-    this.tool.transition('pinching', { info, event })
-  }
-
   onPointerDown: TLStateEvents<S, K>['onPointerDown'] = (info, e) => {
   onPointerDown: TLStateEvents<S, K>['onPointerDown'] = (info, e) => {
     if (info.order) return
     if (info.order) return
     this.tool.transition('panning')
     this.tool.transition('panning')

+ 1 - 1
tldraw/packages/core/src/lib/tools/TLMoveTool/states/PanningState.tsx

@@ -1,5 +1,5 @@
 import Vec from '@tldraw/vec'
 import Vec from '@tldraw/vec'
-import { type TLEventMap, TLCursor, type TLStateEvents } from '../../../../types'
+import { type TLEventMap, TLCursor, type TLStateEvents, TLEvents } from '../../../../types'
 import type { TLShape } from '../../../shapes'
 import type { TLShape } from '../../../shapes'
 import type { TLApp } from '../../../TLApp'
 import type { TLApp } from '../../../TLApp'
 import { TLToolState } from '../../../TLToolState'
 import { TLToolState } from '../../../TLToolState'

+ 2 - 2
tldraw/packages/core/src/lib/tools/TLMoveTool/states/PinchingState.ts

@@ -10,7 +10,7 @@ type GestureInfo<
   E extends TLEventInfo<S> = TLEventInfo<S>
   E extends TLEventInfo<S> = TLEventInfo<S>
 > = {
 > = {
   info: E & { delta: number[]; point: number[]; offset: number[] }
   info: E & { delta: number[]; point: number[]; offset: number[] }
-  event: K['wheel'] | K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
+  event: K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
 }
 }
 
 
 export class PinchingState<
 export class PinchingState<
@@ -31,7 +31,7 @@ export class PinchingState<
   }
   }
 
 
   onPinch: TLEvents<S>['pinch'] = info => {
   onPinch: TLEvents<S>['pinch'] = info => {
-    this.app.viewport.pinchCamera(info.point, [0, 0], info.offset[0])
+    this.app.viewport.pinchZoom(info.point, info.delta, info.delta[2])
   }
   }
 
 
   onPinchEnd: TLEvents<S>['pinch'] = () => {
   onPinchEnd: TLEvents<S>['pinch'] = () => {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/BrushingState.ts

@@ -32,10 +32,6 @@ export class BrushingState<
     this.tree.clear()
     this.tree.clear()
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const {
     const {
       inputs: { shiftKey, ctrlKey, originPoint, currentPoint },
       inputs: { shiftKey, ctrlKey, originPoint, currentPoint },

+ 2 - 31
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PinchingState.ts

@@ -10,7 +10,7 @@ type GestureInfo<
   E extends TLEventInfo<S> = TLEventInfo<S>
   E extends TLEventInfo<S> = TLEventInfo<S>
 > = {
 > = {
   info: E & { delta: number[]; point: number[]; offset: number[] }
   info: E & { delta: number[]; point: number[]; offset: number[] }
-  event: K['wheel'] | K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
+  event: K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
 }
 }
 
 
 export class PinchingState<
 export class PinchingState<
@@ -22,13 +22,7 @@ export class PinchingState<
   static id = 'pinching'
   static id = 'pinching'
 
 
   onPinch: TLEvents<S>['pinch'] = (info, event: any) => {
   onPinch: TLEvents<S>['pinch'] = (info, event: any) => {
-    const { camera } = this.app.viewport
-
-    // Normalize the value of deltaZ from raw WheelEvent
-    const deltaZ = normalizeWheel(event)[2] * 0.01
-    if (deltaZ === 0) return
-    const zoom = camera.zoom - deltaZ * camera.zoom
-    this.app.viewport.pinchCamera(info.point, [0, 0], zoom)
+    this.app.viewport.pinchZoom(info.point, info.delta, info.delta[2])
   }
   }
 
 
   onPinchEnd: TLEvents<S>['pinch'] = () => {
   onPinchEnd: TLEvents<S>['pinch'] = () => {
@@ -39,26 +33,3 @@ export class PinchingState<
     this.tool.transition('idle')
     this.tool.transition('idle')
   }
   }
 }
 }
-
-// Adapted from https://stackoverflow.com/a/13650579
-function normalizeWheel(event: WheelEvent) {
-  const MAX_ZOOM_STEP = 10
-  const { deltaY, deltaX } = event
-
-  let deltaZ = 0
-
-  if (event.ctrlKey || event.metaKey) {
-    const signY = Math.sign(event.deltaY)
-    const absDeltaY = Math.abs(event.deltaY)
-
-    let dy = deltaY
-
-    if (absDeltaY > MAX_ZOOM_STEP) {
-      dy = MAX_ZOOM_STEP * signY
-    }
-
-    deltaZ = dy
-  }
-
-  return [deltaX, deltaY, deltaZ]
-}

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingBoundsBackgroundState.ts

@@ -15,10 +15,6 @@ export class PointingBoundsBackgroundState<
 
 
   cursor = TLCursor.Move
   cursor = TLCursor.Move
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingCanvasState.ts

@@ -22,10 +22,6 @@ export class PointingCanvasState<
     }
     }
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingHandleState.ts

@@ -21,10 +21,6 @@ export class PointingHandleState<
     this.info = info
     this.info = info
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingMinimapState.ts

@@ -65,10 +65,6 @@ export class PointingMinimapState<
     }
     }
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = (info, e) => {
   onPointerMove: TLEvents<S>['pointer'] = (info, e) => {
     const newCameraPoint = this.getCameraPoint([e.clientX, e.clientY])
     const newCameraPoint = this.getCameraPoint([e.clientX, e.clientY])
     if (newCameraPoint) {
     if (newCameraPoint) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingResizeHandleState.ts

@@ -26,10 +26,6 @@ export class PointingResizeHandleState<
     this.app.cursors.reset()
     this.app.cursors.reset()
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingRotateHandleState.ts

@@ -31,10 +31,6 @@ export class PointingRotateHandleState<
     this.updateCursor()
     this.updateCursor()
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingSelectedShapeState.ts

@@ -29,10 +29,6 @@ export class PointingSelectedShapeState<
     this.pointedSelectedShape = undefined
     this.pointedSelectedShape = undefined
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingShapeBehindBoundsState.ts

@@ -19,10 +19,6 @@ export class PointingShapeBehindBoundsState<
     this.info = info
     this.info = info
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/PointingShapeState.ts

@@ -25,10 +25,6 @@ export class PointingShapeState<
     }
     }
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const { currentPoint, originPoint } = this.app.inputs
     const { currentPoint, originPoint } = this.app.inputs
     if (Vec.dist(currentPoint, originPoint) > 5) {
     if (Vec.dist(currentPoint, originPoint) > 5) {

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/ResizingState.ts

@@ -112,10 +112,6 @@ export class ResizingState<
     this.app.history.resume()
     this.app.history.resume()
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const {
     const {
       inputs: { altKey, shiftKey, ctrlKey, originPoint, currentPoint },
       inputs: { altKey, shiftKey, ctrlKey, originPoint, currentPoint },

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/RotatingState.ts

@@ -72,10 +72,6 @@ export class RotatingState<
     this.snapshot = {}
     this.snapshot = {}
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     const {
     const {
       selectedShapes,
       selectedShapes,

+ 0 - 4
tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts

@@ -137,10 +137,6 @@ export class TranslatingState<
     this.initialClonePoints = {}
     this.initialClonePoints = {}
   }
   }
 
 
-  onWheel: TLEvents<S>['wheel'] = (info, e) => {
-    this.onPointerMove(info, e)
-  }
-
   onPointerMove: TLEvents<S>['pointer'] = () => {
   onPointerMove: TLEvents<S>['pointer'] = () => {
     this.moveSelectedShapesToPointer()
     this.moveSelectedShapesToPointer()
   }
   }

+ 0 - 1
tldraw/packages/core/src/types/TLEventHandlers.ts

@@ -8,7 +8,6 @@ export interface TLEventHandlers<
   K extends TLEventMap = TLEventMap,
   K extends TLEventMap = TLEventMap,
   E extends TLEventInfo<S> = TLEventInfo<S>
   E extends TLEventInfo<S> = TLEventInfo<S>
 > {
 > {
-  onWheel: TLEvents<S, K, E>['wheel']
   onPointerDown: TLEvents<S, K, E>['pointer']
   onPointerDown: TLEvents<S, K, E>['pointer']
   onPointerUp: TLEvents<S, K, E>['pointer']
   onPointerUp: TLEvents<S, K, E>['pointer']
   onPointerMove: TLEvents<S, K, E>['pointer']
   onPointerMove: TLEvents<S, K, E>['pointer']

+ 0 - 1
tldraw/packages/core/src/types/TLEventMap.ts

@@ -12,7 +12,6 @@
 import type { AnyObject } from './types'
 import type { AnyObject } from './types'
 
 
 export interface TLEventMap {
 export interface TLEventMap {
-  wheel: AnyObject
   pointer: AnyObject
   pointer: AnyObject
   touch: AnyObject
   touch: AnyObject
   keyboard: AnyObject
   keyboard: AnyObject

+ 2 - 3
tldraw/packages/core/src/types/TLEvents.ts

@@ -8,11 +8,10 @@ export interface TLEvents<
   K extends TLEventMap = TLEventMap,
   K extends TLEventMap = TLEventMap,
   E extends TLEventInfo<S> = TLEventInfo<S>
   E extends TLEventInfo<S> = TLEventInfo<S>
 > {
 > {
-  wheel: (info: E & { delta: number[]; point: number[] }, event: K['wheel']) => void
   pinch: (
   pinch: (
     info: E & { delta: number[]; point: number[]; offset: number[] },
     info: E & { delta: number[]; point: number[]; offset: number[] },
-    event: K['wheel'] | K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
+    event: K['pointer'] | K['touch'] | K['keyboard'] | K['gesture']
   ) => void
   ) => void
-  pointer: (info: E, event: K['pointer'] | K['wheel']) => void
+  pointer: (info: E, event: K['pointer']) => void
   keyboard: (info: E, event: K['keyboard']) => void
   keyboard: (info: E, event: K['keyboard']) => void
 }
 }

+ 79 - 30
tldraw/packages/react/src/hooks/useGestureEvents.ts

@@ -2,7 +2,7 @@ import Vec from '@tldraw/vec'
 import type { Handler, WebKitGestureEvent } from '@use-gesture/core/types'
 import type { Handler, WebKitGestureEvent } from '@use-gesture/core/types'
 import { useGesture } from '@use-gesture/react'
 import { useGesture } from '@use-gesture/react'
 import * as React from 'react'
 import * as React from 'react'
-import { TLTargetType, TLViewport } from '@tldraw/core'
+import { isDarwin, TLTargetType, TLViewport } from '@tldraw/core'
 import { useRendererContext } from './useRendererContext'
 import { useRendererContext } from './useRendererContext'
 
 
 type PinchHandler = Handler<
 type PinchHandler = Handler<
@@ -13,72 +13,98 @@ type PinchHandler = Handler<
 export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
 export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
   const { viewport, inputs, callbacks } = useRendererContext()
   const { viewport, inputs, callbacks } = useRendererContext()
 
 
+  const rOriginPoint = React.useRef<number[] | undefined>(undefined)
+  const rDelta = React.useRef<number[]>([0, 0])
+
   const events = React.useMemo(() => {
   const events = React.useMemo(() => {
     const onWheel: Handler<'wheel', WheelEvent> = gesture => {
     const onWheel: Handler<'wheel', WheelEvent> = gesture => {
-      const { event, delta } = gesture
+      const { event } = gesture
       event.preventDefault()
       event.preventDefault()
-      if (inputs.state === 'pinching') return
-      if (Vec.isEqual(delta, [0, 0])) return
-      callbacks.onWheel?.(
-        {
-          type: TLTargetType.Canvas,
-          order: 0,
-          delta: gesture.delta,
-          point: inputs.currentPoint,
-        },
-        event
-      )
+
+      const [x, y, z] = normalizeWheel(event)
+
+      if (inputs.state === 'pinching') {
+        return
+      }
+
+      if ((event.altKey || event.ctrlKey || event.metaKey) && event.buttons === 0) {
+        const bounds = viewport.bounds
+        const point = inputs.currentScreenPoint ?? [bounds.width / 2, bounds.height / 2]
+        const delta = z / 100
+        const zoom = viewport.camera.zoom
+        viewport.onZoom(point, zoom - delta * zoom)
+        return
+      } else {
+        const delta = Vec.mul(
+          event.shiftKey && !isDarwin()
+            ? // shift+scroll = pan horizontally
+              [y, 0]
+            : // scroll = pan vertically (or in any direction on a trackpad)
+              [x, y],
+          0.8
+        )
+
+        if (Vec.isEqual(delta, [0, 0])) {
+          return
+        }
+
+        viewport.panCamera(delta)
+      }
     }
     }
 
 
-    const onPinchStart: PinchHandler = gesture => {
+    const onPinchStart: PinchHandler = ({ event, delta, offset, origin }) => {
       const elm = ref.current
       const elm = ref.current
-      const { event } = gesture
+      if (event instanceof WheelEvent) return
       if (!(event.target === elm || elm?.contains(event.target as Node))) return
       if (!(event.target === elm || elm?.contains(event.target as Node))) return
-      if (!['idle', 'panning'].includes(inputs.state)) return
       callbacks.onPinchStart?.(
       callbacks.onPinchStart?.(
         {
         {
           type: TLTargetType.Canvas,
           type: TLTargetType.Canvas,
           order: 0,
           order: 0,
-          delta: gesture.delta,
-          offset: gesture.offset,
-          point: Vec.sub(gesture.origin, inputs.containerOffset),
+          delta: [...delta, offset[0]],
+          offset: offset,
+          point: Vec.sub(origin, inputs.containerOffset),
         },
         },
         event
         event
       )
       )
+      rOriginPoint.current = origin
+      rDelta.current = [0, 0]
     }
     }
 
 
-    const onPinch: PinchHandler = gesture => {
+    const onPinch: PinchHandler = ({ event, offset, origin }) => {
       const elm = ref.current
       const elm = ref.current
-      const { event } = gesture
+      if (event instanceof WheelEvent) return
       if (!(event.target === elm || elm?.contains(event.target as Node))) return
       if (!(event.target === elm || elm?.contains(event.target as Node))) return
-      if (inputs.state !== 'pinching') return
+      const delta = Vec.sub(rOriginPoint.current, origin)
+      const trueDelta = Vec.sub(delta, rDelta.current)
       callbacks.onPinch?.(
       callbacks.onPinch?.(
         {
         {
           type: TLTargetType.Canvas,
           type: TLTargetType.Canvas,
           order: 0,
           order: 0,
-          delta: gesture.delta,
-          offset: gesture.offset,
-          point: Vec.sub(gesture.origin, inputs.containerOffset),
+          delta: [...trueDelta, offset[0]],
+          offset: offset,
+          point: Vec.sub(origin, inputs.containerOffset),
         },
         },
         event
         event
       )
       )
+      rDelta.current = delta
     }
     }
 
 
-    const onPinchEnd: PinchHandler = gesture => {
+    const onPinchEnd: PinchHandler = ({ event, delta, offset, origin }) => {
       const elm = ref.current
       const elm = ref.current
-      const { event } = gesture
+      if (event instanceof WheelEvent) return
       if (!(event.target === elm || elm?.contains(event.target as Node))) return
       if (!(event.target === elm || elm?.contains(event.target as Node))) return
       if (inputs.state !== 'pinching') return
       if (inputs.state !== 'pinching') return
       callbacks.onPinchEnd?.(
       callbacks.onPinchEnd?.(
         {
         {
           type: TLTargetType.Canvas,
           type: TLTargetType.Canvas,
           order: 0,
           order: 0,
-          delta: gesture.delta,
-          offset: gesture.offset,
-          point: Vec.sub(gesture.origin, inputs.containerOffset),
+          delta: [0, 0, offset[0]],
+          offset: offset,
+          point: Vec.sub(origin, inputs.containerOffset),
         },
         },
         event
         event
       )
       )
+      rDelta.current = [0, 0]
     }
     }
 
 
     return {
     return {
@@ -102,3 +128,26 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
     },
     },
   })
   })
 }
 }
+
+// Adapted from https://stackoverflow.com/a/13650579
+function normalizeWheel(event: WheelEvent) {
+  const MAX_ZOOM_STEP = 10
+  const { deltaY, deltaX } = event
+
+  let deltaZ = 0
+
+  if (event.ctrlKey || event.metaKey) {
+    const signY = Math.sign(event.deltaY)
+    const absDeltaY = Math.abs(event.deltaY)
+
+    let dy = deltaY
+
+    if (absDeltaY > MAX_ZOOM_STEP) {
+      dy = MAX_ZOOM_STEP * signY
+    }
+
+    deltaZ = dy
+  }
+
+  return [deltaX, deltaY, deltaZ]
+}

+ 0 - 1
tldraw/packages/react/src/types/TLReactCustomEvents.ts

@@ -1,7 +1,6 @@
 import type { TLReactEventMap } from './TLReactEventMap'
 import type { TLReactEventMap } from './TLReactEventMap'
 
 
 export interface TLReactCustomEvents {
 export interface TLReactCustomEvents {
-  wheel: (event: TLReactEventMap['wheel'] & { order?: number }) => void
   pinch: (event: TLReactEventMap['gesture'] & { order?: number }) => void
   pinch: (event: TLReactEventMap['gesture'] & { order?: number }) => void
   pointer: (event: React.PointerEvent & { order?: number }) => void
   pointer: (event: React.PointerEvent & { order?: number }) => void
   keyboard: (event: TLReactEventMap['keyboard'] & { order?: number }) => void
   keyboard: (event: TLReactEventMap['keyboard'] & { order?: number }) => void

+ 0 - 1
tldraw/packages/react/src/types/TLReactEventHandlers.ts

@@ -6,7 +6,6 @@ export interface TLReactEventHandlers<
   S extends TLReactShape = TLReactShape,
   S extends TLReactShape = TLReactShape,
   E extends TLEventInfo<S> = TLEventInfo<S>
   E extends TLEventInfo<S> = TLEventInfo<S>
 > {
 > {
-  onWheel: TLEvents<S, TLReactEventMap, E>['wheel']
   onPointerDown: TLEvents<S, TLReactEventMap, E>['pointer']
   onPointerDown: TLEvents<S, TLReactEventMap, E>['pointer']
   onPointerUp: TLEvents<S, TLReactEventMap, E>['pointer']
   onPointerUp: TLEvents<S, TLReactEventMap, E>['pointer']
   onPointerMove: TLEvents<S, TLReactEventMap, E>['pointer']
   onPointerMove: TLEvents<S, TLReactEventMap, E>['pointer']