Browse Source

Adjusts small example, makes inputs unique to each instance

main
Steve Ruiz 3 years ago
parent
commit
8154ed5a2a

+ 2
- 1
package.json View File

@@ -48,6 +48,7 @@
48 48
     "lerna": "^3.15.0",
49 49
     "react": "^17.0.2",
50 50
     "react-dom": "^17.0.2",
51
+    "resize-observer-polyfill": "^1.5.1",
51 52
     "ts-jest": "^27.0.5",
52 53
     "tslib": "^2.3.0",
53 54
     "typedoc": "^0.21.9",
@@ -114,4 +115,4 @@
114 115
       "\\+(.*)": "<rootDir>/packages/core/src/$1"
115 116
     }
116 117
   }
117
-}
118
+}

+ 6
- 2
packages/core/src/components/canvas/canvas.tsx View File

@@ -12,6 +12,7 @@ import { ErrorBoundary } from '+components/error-boundary'
12 12
 import { Brush } from '+components/brush'
13 13
 import { Defs } from '+components/defs'
14 14
 import { Page } from '+components/page'
15
+import { useResizeObserver } from '+hooks/useResizeObserver'
15 16
 
16 17
 function resetError() {
17 18
   void null
@@ -35,10 +36,13 @@ export function Canvas<T extends TLShape>({
35 36
   hideIndicators = false,
36 37
 }: CanvasProps<T>): JSX.Element {
37 38
   const rCanvas = React.useRef<SVGSVGElement>(null)
39
+  const rContainer = React.useRef<HTMLDivElement>(null)
38 40
 
39 41
   const rGroup = useCameraCss(pageState)
40 42
 
41
-  useZoomEvents()
43
+  useResizeObserver(rCanvas)
44
+
45
+  useZoomEvents(rCanvas)
42 46
 
43 47
   useSafariFocusOutFix()
44 48
 
@@ -47,7 +51,7 @@ export function Canvas<T extends TLShape>({
47 51
   const events = useCanvasEvents()
48 52
 
49 53
   return (
50
-    <div className="tl-container">
54
+    <div className="tl-container" ref={rContainer}>
51 55
       <svg id="canvas" className="tl-canvas" ref={rCanvas} {...events}>
52 56
         <ErrorBoundary FallbackComponent={ErrorFallback} onReset={resetError}>
53 57
           <Defs zoom={pageState.camera.zoom} />

+ 2
- 0
packages/core/src/components/renderer/renderer.tsx View File

@@ -10,6 +10,7 @@ import type {
10 10
   TLBinding,
11 11
 } from '../../types'
12 12
 import { Canvas } from '../canvas'
13
+import { Inputs } from '../../inputs'
13 14
 import { useTLTheme, TLContext, TLContextType } from '../../hooks'
14 15
 
15 16
 export interface RendererProps<T extends TLShape, M extends Record<string, unknown>>
@@ -87,6 +88,7 @@ export function Renderer<T extends TLShape, M extends Record<string, unknown>>({
87 88
     shapeUtils,
88 89
     rScreenBounds,
89 90
     rPageState,
91
+    inputs: new Inputs(),
90 92
   }))
91 93
 
92 94
   return (

+ 6
- 7
packages/core/src/hooks/useBoundsEvents.tsx View File

@@ -1,9 +1,8 @@
1 1
 import * as React from 'react'
2
-import { inputs } from '+inputs'
3 2
 import { useTLContext } from './useTLContext'
4 3
 
5 4
 export function useBoundsEvents() {
6
-  const { callbacks } = useTLContext()
5
+  const { callbacks, inputs } = useTLContext()
7 6
 
8 7
   const onPointerDown = React.useCallback(
9 8
     (e: React.PointerEvent) => {
@@ -15,7 +14,7 @@ export function useBoundsEvents() {
15 14
       callbacks.onPointBounds?.(info, e)
16 15
       callbacks.onPointerDown?.(info, e)
17 16
     },
18
-    [callbacks]
17
+    [callbacks, inputs]
19 18
   )
20 19
 
21 20
   const onPointerUp = React.useCallback(
@@ -36,7 +35,7 @@ export function useBoundsEvents() {
36 35
       callbacks.onReleaseBounds?.(info, e)
37 36
       callbacks.onPointerUp?.(info, e)
38 37
     },
39
-    [callbacks]
38
+    [callbacks, inputs]
40 39
   )
41 40
 
42 41
   const onPointerMove = React.useCallback(
@@ -49,21 +48,21 @@ export function useBoundsEvents() {
49 48
       const info = inputs.pointerMove(e, 'bounds')
50 49
       callbacks.onPointerMove?.(info, e)
51 50
     },
52
-    [callbacks]
51
+    [callbacks, inputs]
53 52
   )
54 53
 
55 54
   const onPointerEnter = React.useCallback(
56 55
     (e: React.PointerEvent) => {
57 56
       callbacks.onHoverBounds?.(inputs.pointerEnter(e, 'bounds'), e)
58 57
     },
59
-    [callbacks]
58
+    [callbacks, inputs]
60 59
   )
61 60
 
62 61
   const onPointerLeave = React.useCallback(
63 62
     (e: React.PointerEvent) => {
64 63
       callbacks.onUnhoverBounds?.(inputs.pointerEnter(e, 'bounds'), e)
65 64
     },
66
-    [callbacks]
65
+    [callbacks, inputs]
67 66
   )
68 67
 
69 68
   const onTouchStart = React.useCallback((e: React.TouchEvent) => {

+ 6
- 7
packages/core/src/hooks/useBoundsHandleEvents.tsx View File

@@ -1,10 +1,9 @@
1 1
 import * as React from 'react'
2
-import { inputs } from '+inputs'
3 2
 import type { TLBoundsEdge, TLBoundsCorner } from '+types'
4 3
 import { useTLContext } from './useTLContext'
5 4
 
6 5
 export function useBoundsHandleEvents(id: TLBoundsCorner | TLBoundsEdge | 'rotate') {
7
-  const { callbacks } = useTLContext()
6
+  const { callbacks, inputs } = useTLContext()
8 7
 
9 8
   const onPointerDown = React.useCallback(
10 9
     (e: React.PointerEvent) => {
@@ -16,7 +15,7 @@ export function useBoundsHandleEvents(id: TLBoundsCorner | TLBoundsEdge | 'rotat
16 15
       callbacks.onPointBoundsHandle?.(info, e)
17 16
       callbacks.onPointerDown?.(info, e)
18 17
     },
19
-    [callbacks, id]
18
+    [inputs, callbacks, id]
20 19
   )
21 20
 
22 21
   const onPointerUp = React.useCallback(
@@ -37,7 +36,7 @@ export function useBoundsHandleEvents(id: TLBoundsCorner | TLBoundsEdge | 'rotat
37 36
       callbacks.onReleaseBoundsHandle?.(info, e)
38 37
       callbacks.onPointerUp?.(info, e)
39 38
     },
40
-    [callbacks, id]
39
+    [inputs, callbacks, id]
41 40
   )
42 41
 
43 42
   const onPointerMove = React.useCallback(
@@ -48,21 +47,21 @@ export function useBoundsHandleEvents(id: TLBoundsCorner | TLBoundsEdge | 'rotat
48 47
       const info = inputs.pointerMove(e, id)
49 48
       callbacks.onPointerMove?.(info, e)
50 49
     },
51
-    [callbacks, id]
50
+    [inputs, callbacks, id]
52 51
   )
53 52
 
54 53
   const onPointerEnter = React.useCallback(
55 54
     (e: React.PointerEvent) => {
56 55
       callbacks.onHoverBoundsHandle?.(inputs.pointerEnter(e, id), e)
57 56
     },
58
-    [callbacks, id]
57
+    [inputs, callbacks, id]
59 58
   )
60 59
 
61 60
   const onPointerLeave = React.useCallback(
62 61
     (e: React.PointerEvent) => {
63 62
       callbacks.onUnhoverBoundsHandle?.(inputs.pointerEnter(e, id), e)
64 63
     },
65
-    [callbacks, id]
64
+    [inputs, callbacks, id]
66 65
   )
67 66
 
68 67
   const onTouchStart = React.useCallback((e: React.TouchEvent) => {

+ 4
- 5
packages/core/src/hooks/useCanvasEvents.tsx View File

@@ -1,9 +1,8 @@
1 1
 import * as React from 'react'
2 2
 import { useTLContext } from './useTLContext'
3
-import { inputs } from '+inputs'
4 3
 
5 4
 export function useCanvasEvents() {
6
-  const { callbacks } = useTLContext()
5
+  const { callbacks, inputs } = useTLContext()
7 6
 
8 7
   const onPointerDown = React.useCallback(
9 8
     (e: React.PointerEvent) => {
@@ -16,7 +15,7 @@ export function useCanvasEvents() {
16 15
         callbacks.onPointerDown?.(info, e)
17 16
       }
18 17
     },
19
-    [callbacks]
18
+    [callbacks, inputs]
20 19
   )
21 20
 
22 21
   const onPointerMove = React.useCallback(
@@ -28,7 +27,7 @@ export function useCanvasEvents() {
28 27
       const info = inputs.pointerMove(e, 'canvas')
29 28
       callbacks.onPointerMove?.(info, e)
30 29
     },
31
-    [callbacks]
30
+    [callbacks, inputs]
32 31
   )
33 32
 
34 33
   const onPointerUp = React.useCallback(
@@ -47,7 +46,7 @@ export function useCanvasEvents() {
47 46
       callbacks.onReleaseCanvas?.(info, e)
48 47
       callbacks.onPointerUp?.(info, e)
49 48
     },
50
-    [callbacks]
49
+    [callbacks, inputs]
51 50
   )
52 51
 
53 52
   return {

+ 6
- 7
packages/core/src/hooks/useHandleEvents.tsx View File

@@ -1,9 +1,8 @@
1 1
 import * as React from 'react'
2
-import { inputs } from '+inputs'
3 2
 import { useTLContext } from './useTLContext'
4 3
 
5 4
 export function useHandleEvents(id: string) {
6
-  const { callbacks } = useTLContext()
5
+  const { inputs, callbacks } = useTLContext()
7 6
 
8 7
   const onPointerDown = React.useCallback(
9 8
     (e: React.PointerEvent) => {
@@ -15,7 +14,7 @@ export function useHandleEvents(id: string) {
15 14
       callbacks.onPointHandle?.(info, e)
16 15
       callbacks.onPointerDown?.(info, e)
17 16
     },
18
-    [callbacks, id]
17
+    [inputs, callbacks, id]
19 18
   )
20 19
 
21 20
   const onPointerUp = React.useCallback(
@@ -36,7 +35,7 @@ export function useHandleEvents(id: string) {
36 35
       }
37 36
       callbacks.onPointerUp?.(info, e)
38 37
     },
39
-    [callbacks]
38
+    [inputs, callbacks]
40 39
   )
41 40
 
42 41
   const onPointerMove = React.useCallback(
@@ -48,7 +47,7 @@ export function useHandleEvents(id: string) {
48 47
       const info = inputs.pointerMove(e, id)
49 48
       callbacks.onPointerMove?.(info, e)
50 49
     },
51
-    [callbacks, id]
50
+    [inputs, callbacks, id]
52 51
   )
53 52
 
54 53
   const onPointerEnter = React.useCallback(
@@ -56,7 +55,7 @@ export function useHandleEvents(id: string) {
56 55
       const info = inputs.pointerEnter(e, id)
57 56
       callbacks.onHoverHandle?.(info, e)
58 57
     },
59
-    [callbacks, id]
58
+    [inputs, callbacks, id]
60 59
   )
61 60
 
62 61
   const onPointerLeave = React.useCallback(
@@ -64,7 +63,7 @@ export function useHandleEvents(id: string) {
64 63
       const info = inputs.pointerEnter(e, id)
65 64
       callbacks.onUnhoverHandle?.(info, e)
66 65
     },
67
-    [callbacks, id]
66
+    [inputs, callbacks, id]
68 67
   )
69 68
 
70 69
   const onTouchStart = React.useCallback((e: React.TouchEvent) => {

+ 41
- 0
packages/core/src/hooks/useResizeObserver.ts View File

@@ -0,0 +1,41 @@
1
+import { useTLContext } from '+hooks'
2
+import * as React from 'react'
3
+
4
+export function useResizeObserver<T extends HTMLElement | SVGElement>(ref: React.RefObject<T>) {
5
+  const { inputs } = useTLContext()
6
+
7
+  React.useEffect(() => {
8
+    function handleScroll() {
9
+      const rect = ref.current?.getBoundingClientRect()
10
+      if (rect) {
11
+        inputs.offset = [rect.left, rect.top]
12
+      }
13
+    }
14
+
15
+    window.addEventListener('scroll', handleScroll)
16
+    return () => {
17
+      window.removeEventListener('scroll', handleScroll)
18
+    }
19
+  }, [inputs])
20
+
21
+  React.useEffect(() => {
22
+    const resizeObserver = new ResizeObserver((entries) => {
23
+      if (inputs.isPinching) return
24
+
25
+      if (entries[0].contentRect) {
26
+        const rect = ref.current?.getBoundingClientRect()
27
+        if (rect) {
28
+          inputs.offset = [rect.left, rect.top]
29
+        }
30
+      }
31
+    })
32
+
33
+    if (ref.current) {
34
+      resizeObserver.observe(ref.current)
35
+    }
36
+
37
+    return () => {
38
+      resizeObserver.disconnect()
39
+    }
40
+  }, [ref, inputs])
41
+}

+ 6
- 7
packages/core/src/hooks/useShapeEvents.tsx View File

@@ -1,10 +1,9 @@
1 1
 import * as React from 'react'
2
-import { inputs } from '+inputs'
3 2
 import { Utils } from '+utils'
4 3
 import { TLContext } from '+hooks'
5 4
 
6 5
 export function useShapeEvents(id: string, disable = false) {
7
-  const { rPageState, rScreenBounds, callbacks } = React.useContext(TLContext)
6
+  const { rPageState, rScreenBounds, callbacks, inputs } = React.useContext(TLContext)
8 7
 
9 8
   const onPointerDown = React.useCallback(
10 9
     (e: React.PointerEvent) => {
@@ -38,7 +37,7 @@ export function useShapeEvents(id: string, disable = false) {
38 37
       callbacks.onPointShape?.(info, e)
39 38
       callbacks.onPointerDown?.(info, e)
40 39
     },
41
-    [callbacks, id, disable]
40
+    [inputs, callbacks, id, disable]
42 41
   )
43 42
 
44 43
   const onPointerUp = React.useCallback(
@@ -60,7 +59,7 @@ export function useShapeEvents(id: string, disable = false) {
60 59
       callbacks.onReleaseShape?.(info, e)
61 60
       callbacks.onPointerUp?.(info, e)
62 61
     },
63
-    [callbacks, id, disable]
62
+    [inputs, callbacks, id, disable]
64 63
   )
65 64
 
66 65
   const onPointerMove = React.useCallback(
@@ -77,7 +76,7 @@ export function useShapeEvents(id: string, disable = false) {
77 76
 
78 77
       callbacks.onPointerMove?.(info, e)
79 78
     },
80
-    [callbacks, id, disable]
79
+    [inputs, callbacks, id, disable]
81 80
   )
82 81
 
83 82
   const onPointerEnter = React.useCallback(
@@ -86,7 +85,7 @@ export function useShapeEvents(id: string, disable = false) {
86 85
       const info = inputs.pointerEnter(e, id)
87 86
       callbacks.onHoverShape?.(info, e)
88 87
     },
89
-    [callbacks, id, disable]
88
+    [inputs, callbacks, id, disable]
90 89
   )
91 90
 
92 91
   const onPointerLeave = React.useCallback(
@@ -95,7 +94,7 @@ export function useShapeEvents(id: string, disable = false) {
95 94
       const info = inputs.pointerEnter(e, id)
96 95
       callbacks.onUnhoverShape?.(info, e)
97 96
     },
98
-    [callbacks, id, disable]
97
+    [inputs, callbacks, id, disable]
99 98
   )
100 99
 
101 100
   const onTouchStart = React.useCallback((e: React.TouchEvent) => {

+ 1
- 2
packages/core/src/hooks/useStyle.tsx View File

@@ -185,14 +185,13 @@ const tlcss = css`
185 185
     pointer-events: none;
186 186
   }
187 187
   .tl-canvas {
188
-    position: fixed;
188
+    position: absolute;
189 189
     overflow: hidden;
190 190
     top: 0px;
191 191
     left: 0px;
192 192
     width: 100%;
193 193
     height: 100%;
194 194
     touch-action: none;
195
-    z-index: 100;
196 195
     pointer-events: all;
197 196
   }
198 197
   .tl-container {

+ 2
- 0
packages/core/src/hooks/useTLContext.tsx View File

@@ -1,4 +1,5 @@
1 1
 import * as React from 'react'
2
+import type { Inputs } from '+inputs'
2 3
 import type { TLCallbacks, TLShape, TLBounds, TLPageState, TLShapeUtils } from '+types'
3 4
 
4 5
 export interface TLContextType {
@@ -7,6 +8,7 @@ export interface TLContextType {
7 8
   shapeUtils: TLShapeUtils<TLShape>
8 9
   rPageState: React.MutableRefObject<TLPageState>
9 10
   rScreenBounds: React.MutableRefObject<TLBounds | null>
11
+  inputs: Inputs
10 12
 }
11 13
 
12 14
 export const TLContext = React.createContext<TLContextType>({} as TLContextType)

+ 20
- 15
packages/core/src/hooks/useZoomEvents.ts View File

@@ -1,20 +1,22 @@
1 1
 /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2
-import { useRef } from 'react'
2
+import * as React from 'react'
3 3
 import { useTLContext } from './useTLContext'
4 4
 import { Vec } from '+utils'
5 5
 import { useWheel, usePinch } from 'react-use-gesture'
6
-import { inputs } from '+inputs'
7 6
 
8 7
 // Capture zoom gestures (pinches, wheels and pans)
9
-export function useZoomEvents() {
10
-  const rPinchDa = useRef<number[] | undefined>(undefined)
11
-  const rOriginPoint = useRef<number[] | undefined>(undefined)
12
-  const rPinchPoint = useRef<number[] | undefined>(undefined)
8
+export function useZoomEvents<T extends HTMLElement | SVGElement>(ref: React.RefObject<T>) {
9
+  const rPinchDa = React.useRef<number[] | undefined>(undefined)
10
+  const rOriginPoint = React.useRef<number[] | undefined>(undefined)
11
+  const rPinchPoint = React.useRef<number[] | undefined>(undefined)
13 12
 
14
-  const { callbacks } = useTLContext()
13
+  const { inputs, callbacks } = useTLContext()
15 14
 
16 15
   useWheel(
17 16
     ({ event: e, delta }) => {
17
+      const elm = ref.current
18
+      if (!(e.target === elm || elm?.contains(e.target as Node))) return
19
+
18 20
       e.preventDefault()
19 21
 
20 22
       if (Vec.isEqual(delta, [0, 0])) return
@@ -24,15 +26,20 @@ export function useZoomEvents() {
24 26
       callbacks.onPan?.(info, e)
25 27
     },
26 28
     {
27
-      domTarget: typeof document === 'undefined' ? undefined : document.body,
29
+      domTarget: window,
28 30
       eventOptions: { passive: false },
29 31
     }
30 32
   )
31 33
 
32 34
   usePinch(
33 35
     ({ pinching, da, origin, event: e }) => {
36
+      const elm = ref.current
37
+      if (!(e.target === elm || elm?.contains(e.target as Node))) return
38
+
39
+      const info = inputs.pinch(origin, origin)
40
+
34 41
       if (!pinching) {
35
-        const info = inputs.pinch(origin, origin)
42
+        inputs.isPinching = false
36 43
         callbacks.onPinchEnd?.(
37 44
           info,
38 45
           e as React.WheelEvent<Element> | WheelEvent | React.TouchEvent<Element> | TouchEvent
@@ -44,14 +51,14 @@ export function useZoomEvents() {
44 51
       }
45 52
 
46 53
       if (rPinchPoint.current === undefined) {
47
-        const info = inputs.pinch(origin, origin)
54
+        inputs.isPinching = true
48 55
         callbacks.onPinchStart?.(
49 56
           info,
50 57
           e as React.WheelEvent<Element> | WheelEvent | React.TouchEvent<Element> | TouchEvent
51 58
         )
52 59
         rPinchDa.current = da
53
-        rPinchPoint.current = origin
54
-        rOriginPoint.current = origin
60
+        rPinchPoint.current = info.point
61
+        rOriginPoint.current = info.point
55 62
       }
56 63
 
57 64
       if (!rPinchDa.current) throw Error('No pinch direction!')
@@ -59,8 +66,6 @@ export function useZoomEvents() {
59 66
 
60 67
       const [distanceDelta] = Vec.sub(rPinchDa.current, da)
61 68
 
62
-      const info = inputs.pinch(rPinchPoint.current, origin)
63
-
64 69
       callbacks.onPinch?.(
65 70
         {
66 71
           ...info,
@@ -75,7 +80,7 @@ export function useZoomEvents() {
75 80
       rPinchPoint.current = origin
76 81
     },
77 82
     {
78
-      domTarget: typeof document === 'undefined' ? undefined : document.body,
83
+      domTarget: window,
79 84
       eventOptions: { passive: false },
80 85
     }
81 86
   )

+ 18
- 11
packages/core/src/inputs.ts View File

@@ -4,10 +4,13 @@ import { Vec, Utils } from './utils'
4 4
 
5 5
 const DOUBLE_CLICK_DURATION = 250
6 6
 
7
-class Inputs {
7
+export class Inputs {
8 8
   pointer?: TLPointerInfo<string>
9 9
   keyboard?: TLKeyboardInfo
10 10
   keys: Record<string, boolean> = {}
11
+  isPinching = false
12
+
13
+  offset = [0, 0]
11 14
 
12 15
   pointerUpTime = 0
13 16
 
@@ -69,7 +72,7 @@ class Inputs {
69 72
   pointerDown<T extends string>(e: PointerEvent | React.PointerEvent, target: T): TLPointerInfo<T> {
70 73
     const { shiftKey, ctrlKey, metaKey, altKey } = e
71 74
 
72
-    const point = Inputs.getPoint(e)
75
+    const point = Inputs.getPoint(e, this.offset)
73 76
 
74 77
     const info: TLPointerInfo<T> = {
75 78
       target,
@@ -95,7 +98,7 @@ class Inputs {
95 98
   ): TLPointerInfo<T> {
96 99
     const { shiftKey, ctrlKey, metaKey, altKey } = e
97 100
 
98
-    const point = Inputs.getPoint(e)
101
+    const point = Inputs.getPoint(e, this.offset)
99 102
 
100 103
     const info: TLPointerInfo<T> = {
101 104
       target,
@@ -120,7 +123,7 @@ class Inputs {
120 123
 
121 124
     const prev = this.pointer
122 125
 
123
-    const point = Inputs.getPoint(e)
126
+    const point = Inputs.getPoint(e, this.offset)
124 127
 
125 128
     const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
126 129
 
@@ -148,7 +151,7 @@ class Inputs {
148 151
 
149 152
     const prev = this.pointer
150 153
 
151
-    const point = Inputs.getPoint(e)
154
+    const point = Inputs.getPoint(e, this.offset)
152 155
 
153 156
     const delta = prev?.point ? Vec.sub(point, prev.point) : [0, 0]
154 157
 
@@ -182,7 +185,7 @@ class Inputs {
182 185
       origin: this.pointer?.origin || [0, 0],
183 186
       delta: [0, 0],
184 187
       pressure: 0.5,
185
-      point: Inputs.getPoint(e),
188
+      point: Inputs.getPoint(e, this.offset),
186 189
       shiftKey,
187 190
       ctrlKey,
188 191
       metaKey,
@@ -203,7 +206,7 @@ class Inputs {
203 206
 
204 207
     const prev = this.pointer
205 208
 
206
-    const point = Inputs.getPoint(e)
209
+    const point = Inputs.getPoint(e, this.offset)
207 210
 
208 211
     const info: TLPointerInfo<'wheel'> = {
209 212
       ...prev,
@@ -281,9 +284,9 @@ class Inputs {
281 284
     const info: TLPointerInfo<'pinch'> = {
282 285
       pointerId: 0,
283 286
       target: 'pinch',
284
-      origin: prev?.origin || Vec.round(point),
287
+      origin: prev?.origin || Vec.sub(Vec.round(point), this.offset),
285 288
       delta: delta,
286
-      point: Vec.round(point),
289
+      point: Vec.sub(Vec.round(point), this.offset),
287 290
       pressure: 0.5,
288 291
       shiftKey,
289 292
       ctrlKey,
@@ -304,9 +307,13 @@ class Inputs {
304 307
   }
305 308
 
306 309
   static getPoint(
307
-    e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent
310
+    e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent,
311
+    offset = [0, 0]
308 312
   ): number[] {
309
-    return [Number(e.clientX.toPrecision(5)), Number(e.clientY.toPrecision(5))]
313
+    return [
314
+      Number(e.clientX.toPrecision(5)) - offset[0],
315
+      Number(e.clientY.toPrecision(5)) - offset[1],
316
+    ]
310 317
   }
311 318
 
312 319
   static getPressure(e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent) {

+ 2
- 0
packages/core/src/test/context-wrapper.tsx View File

@@ -3,6 +3,7 @@ import type { TLPageState, TLBounds } from '../types'
3 3
 import { mockDocument } from './mockDocument'
4 4
 import { mockUtils } from './mockUtils'
5 5
 import { useTLTheme, TLContext } from '../hooks'
6
+import { Inputs } from '+inputs'
6 7
 
7 8
 export const ContextWrapper: React.FC = ({ children }) => {
8 9
   useTLTheme()
@@ -14,6 +15,7 @@ export const ContextWrapper: React.FC = ({ children }) => {
14 15
     shapeUtils: mockUtils,
15 16
     rScreenBounds,
16 17
     rPageState,
18
+    inputs: new Inputs(),
17 19
   }))
18 20
 
19 21
   return <TLContext.Provider value={context}>{children}</TLContext.Provider>

+ 4
- 0
packages/dev/esbuild.config.mjs View File

@@ -9,6 +9,10 @@ if (!fs.existsSync('./dist')) {
9 9
   fs.mkdirSync('./dist')
10 10
 }
11 11
 
12
+fs.copyFile('./src/styles.css', './dist/styles.css', (err) => {
13
+  if (err) throw err
14
+})
15
+
12 16
 fs.copyFile('./src/index.html', './dist/index.html', (err) => {
13 17
   if (err) throw err
14 18
 })

+ 2
- 1
packages/dev/src/app.tsx View File

@@ -2,7 +2,8 @@ import * as React from 'react'
2 2
 import Basic from './basic'
3 3
 import Controlled from './controlled'
4 4
 import Imperative from './imperative'
5
+import Small from './small'
5 6
 
6 7
 export default function App(): JSX.Element {
7
-  return <Basic />
8
+  return <Small />
8 9
 }

+ 2
- 1
packages/dev/src/index.html View File

@@ -2,7 +2,8 @@
2 2
 <html lang="en">
3 3
   <head>
4 4
     <meta charset="utf-8" />
5
-    <link rel="icon" href="/favicon.ico" />
5
+    <link rel="icon" href="favicon.ico" />
6
+    <link rel="stylesheet" href="styles.css" />
6 7
     <meta name="viewport" content="width=device-width, initial-scale=1" />
7 8
     <title>tldraw</title>
8 9
   </head>

+ 30
- 0
packages/dev/src/small.tsx View File

@@ -0,0 +1,30 @@
1
+import * as React from 'react'
2
+import Editor from './components/editor'
3
+
4
+export default function BasicUsage(): JSX.Element {
5
+  return (
6
+    <div>
7
+      <div
8
+        style={{
9
+          position: 'relative',
10
+          margin: '5%',
11
+          width: 'calc(100% - 100px)',
12
+          height: '500px',
13
+        }}
14
+      >
15
+        <Editor id="small1" />
16
+      </div>
17
+
18
+      <div
19
+        style={{
20
+          position: 'relative',
21
+          margin: '5%',
22
+          width: 'calc(100% - 100px)',
23
+          height: '500px',
24
+        }}
25
+      >
26
+        <Editor id="small2" />
27
+      </div>
28
+    </div>
29
+  )
30
+}

+ 8
- 0
packages/dev/src/styles.css View File

@@ -0,0 +1,8 @@
1
+html,
2
+* {
3
+  box-sizing: border-box;
4
+}
5
+
6
+body {
7
+  overscroll-behavior: none;
8
+}

+ 1
- 1
packages/tldraw/src/components/shared/dialog.tsx View File

@@ -5,7 +5,7 @@ import styled from '~styles'
5 5
 /* -------------------------------------------------- */
6 6
 
7 7
 export const DialogContent = styled('div', {
8
-  position: 'fixed',
8
+  position: 'absolute',
9 9
   top: '50%',
10 10
   left: '50%',
11 11
   transform: 'translate(-50%, -50%)',

+ 8
- 7
packages/tldraw/src/components/tldraw/tldraw.tsx View File

@@ -227,17 +227,16 @@ const MenuButtons = styled('div', {
227 227
   gap: 8,
228 228
 })
229 229
 
230
-const Layout = styled('main', {
231
-  position: 'fixed',
230
+const Layout = styled('div', {
232 231
   overflow: 'hidden',
233
-  top: 0,
234
-  left: 0,
235
-  bottom: 0,
236
-  right: 0,
232
+  position: 'absolute',
237 233
   height: '100%',
238 234
   width: '100%',
235
+  top: 0,
236
+  right: 0,
237
+  bottom: 0,
238
+  left: 0,
239 239
   padding: '8px 8px 0 8px',
240
-  zIndex: 200,
241 240
   display: 'flex',
242 241
   alignItems: 'flex-start',
243 242
   justifyContent: 'flex-start',
@@ -253,5 +252,7 @@ const Layout = styled('main', {
253 252
     position: 'absolute',
254 253
     top: 0,
255 254
     left: 0,
255
+    width: '100%',
256
+    height: '100%',
256 257
   },
257 258
 })

+ 1
- 1
packages/tldraw/src/components/tools-panel/tools-panel.tsx View File

@@ -139,7 +139,7 @@ export const ToolsPanel = React.memo((): JSX.Element => {
139 139
 })
140 140
 
141 141
 const ToolsPanelContainer = styled('div', {
142
-  position: 'fixed',
142
+  position: 'absolute',
143 143
   bottom: 0,
144 144
   left: 0,
145 145
   right: 0,

+ 5
- 5
packages/tldraw/src/state/tlstate.ts View File

@@ -2231,11 +2231,11 @@ export class TLDrawState extends StateManager<Data> {
2231 2231
   }
2232 2232
 
2233 2233
   onPinchEnd: TLPinchEventHandler = () => {
2234
-    if (this.state.settings.isZoomSnap) {
2235
-      const i = Math.round((this.pageState.camera.zoom * 100) / 25)
2236
-      const nextZoom = TLDR.getCameraZoom(i * 0.25)
2237
-      this.zoomTo(nextZoom, inputs.pointer?.point)
2238
-    }
2234
+    // if (this.state.settings.isZoomSnap) {
2235
+    //   const i = Math.round((this.pageState.camera.zoom * 100) / 25)
2236
+    //   const nextZoom = TLDR.getCameraZoom(i * 0.25)
2237
+    //   this.zoomTo(nextZoom, inputs.pointer?.point)
2238
+    // }
2239 2239
     this.setStatus(this.appState.status.previous)
2240 2240
   }
2241 2241
 

+ 2
- 1
setupTests.ts View File

@@ -1,2 +1,3 @@
1 1
 import '@testing-library/jest-dom/extend-expect'
2
-import "fake-indexeddb/auto"
2
+import 'fake-indexeddb/auto'
3
+global.ResizeObserver = require('resize-observer-polyfill')

+ 5
- 0
yarn.lock View File

@@ -11417,6 +11417,11 @@ require_optional@^1.0.1:
11417 11417
     resolve-from "^2.0.0"
11418 11418
     semver "^5.1.0"
11419 11419
 
11420
+resize-observer-polyfill@^1.5.1:
11421
+  version "1.5.1"
11422
+  resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
11423
+  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
11424
+
11420 11425
 resolve-cwd@^2.0.0:
11421 11426
   version "2.0.0"
11422 11427
   resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"

Loading…
Cancel
Save