Bläddra i källkod

fix: scroll offset issue

Peng Xiao 3 år sedan
förälder
incheckning
cbc9b7ab50

+ 5 - 2
tldraw/.eslintrc

@@ -3,13 +3,16 @@
   "parser": "@typescript-eslint/parser",
   "plugins": ["@typescript-eslint"],
   "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
-  "ignorePatterns": ["*.js"],
+  "ignorePatterns": ["*.js", "*.jsx"],
   "overrides": [
     {
       // enable the rule specifically for TypeScript files
       "files": ["*.ts", "*.tsx"],
       "rules": {
-        "@typescript-eslint/explicit-module-boundary-types": [0]
+        "@typescript-eslint/explicit-module-boundary-types": "off",
+        "@typescript-eslint/explicit-function-return-type": "off",
+        "@typescript-eslint/no-explicit-any": "off",
+        "@typescript-eslint/camelcase": "off"
       }
     }
   ]

+ 15 - 17
tldraw/demo/src/App.jsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React from 'react'
 import { App as TldrawApp } from 'tldraw-logseq'
 
 const storingKey = 'playground.index'
@@ -13,33 +13,31 @@ const onLoad = () => {
 
 const documentModel = onLoad() ?? {
   currentPageId: 'page1',
-  selectedIds: ['yt1', 'yt2'],
+  selectedIds: ['p6bv7EfoQPIF1eZB1RRO6'],
   pages: [
     {
-      name: 'Page',
       id: 'page1',
+      name: 'Page',
       shapes: [
         {
-          id: 'yt1',
-          type: 'youtube',
-          parentId: 'page1',
-          point: [100, 100],
-          size: [160, 90],
-          embedId: '',
-        },
-        {
-          id: 'yt2',
-          type: 'youtube',
+          scale: [1, 1],
+          id: 'p6bv7EfoQPIF1eZB1RRO6',
+          type: 'logseq-portal',
           parentId: 'page1',
-          point: [300, 300],
-          size: [160, 90],
-          embedId: '',
+          point: [769.109375, 170.5546875],
+          size: [390.671875, 295.3671875],
+          stroke: '#000000',
+          fill: '#ffffff',
+          strokeWidth: 2,
+          opacity: 1,
+          pageId: '',
+          nonce: 1,
         },
       ],
       bindings: {},
+      nonce: 2,
     },
   ],
-  assets: [],
 }
 
 const list = ['foo', 'bar']

+ 9 - 1
tldraw/packages/core/src/lib/TLInputs.ts

@@ -1,3 +1,4 @@
+import Vec from '@tldraw/vec'
 import { action, makeObservable, observable } from 'mobx'
 import type { TLEventMap } from '~types'
 import { modKey } from '~utils'
@@ -25,12 +26,19 @@ export class TLInputs<K extends TLEventMap> {
 
   @observable state: 'pointing' | 'pinching' | 'idle' | 'panning' = 'idle'
 
+  // The canvas container offset
+  @observable containerOffset: [number, number] = [0, 0]
+
+  @action updateContainerOffset(containerOffset: [number, number]) {
+    Object.assign(this.containerOffset, containerOffset)
+  }
+
   @action private updateModifiers(
     event: K['gesture'] | K['pointer'] | K['keyboard'] | K['wheel'] | K['touch']
   ) {
     if ('clientX' in event) {
       this.previousScreenPoint = this.currentScreenPoint
-      this.currentScreenPoint = [event.clientX, event.clientY]
+      this.currentScreenPoint = Vec.add([event.clientX, event.clientY], this.containerOffset)
     }
     if ('shiftKey' in event) {
       this.shiftKey = event.shiftKey

+ 6 - 1
tldraw/packages/react/src/components/Canvas/Canvas.tsx

@@ -20,6 +20,7 @@ import {
   usePreventNavigation,
   useCursor,
   useZoom,
+  useApp,
 } from '~hooks'
 import { TLAsset, TLBinding, TLBounds, TLCursor, TLTheme } from '@tldraw/core'
 import { EMPTY_OBJECT, NOOP } from '~constants'
@@ -90,9 +91,13 @@ export const Canvas = observer(function Renderer<S extends TLReactShape>({
   const rContainer = React.useRef<HTMLDivElement>(null)
   const { viewport, components, meta } = useRendererContext()
   const { zoom } = viewport.camera
+  const app = useApp()
+  const onBoundsChange = React.useCallback((bounds: TLBounds) => {
+    app.inputs.updateContainerOffset([bounds.minX, bounds.minY])
+  }, [])
   useStylesheet(theme, id)
   usePreventNavigation(rContainer)
-  useResizeObserver(rContainer, viewport)
+  useResizeObserver(rContainer, viewport, onBoundsChange)
   useGestureEvents(rContainer)
   useCursor(rContainer, cursor, cursorRotation)
   useZoom(rContainer)

+ 25 - 5
tldraw/packages/react/src/hooks/useResizeObserver.ts

@@ -1,7 +1,26 @@
 import * as React from 'react'
 import type { TLViewport, TLBounds } from '@tldraw/core'
 
-export function useResizeObserver<T extends Element>(
+const getNearestScrollableContainer = (element: HTMLElement): HTMLElement | Document => {
+  let parent = element.parentElement
+  while (parent) {
+    if (parent === document.body) {
+      return document
+    }
+    const { overflowY } = window.getComputedStyle(parent)
+    const hasScrollableContent = parent.scrollHeight > parent.clientHeight
+    if (
+      hasScrollableContent &&
+      (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay')
+    ) {
+      return parent
+    }
+    parent = parent.parentElement
+  }
+  return document
+}
+
+export function useResizeObserver<T extends HTMLElement>(
   ref: React.RefObject<T>,
   viewport: TLViewport,
   onBoundsChange?: (bounds: TLBounds) => void
@@ -34,11 +53,12 @@ export function useResizeObserver<T extends Element>(
   }, [ref, onBoundsChange])
 
   React.useEffect(() => {
-    window.addEventListener('scroll', updateBounds)
-    window.addEventListener('resize', updateBounds)
+    const scrollingAnchor = ref.current ? getNearestScrollableContainer(ref.current) : document
+    scrollingAnchor.addEventListener('scroll', updateBounds)
+    scrollingAnchor.addEventListener('resize', updateBounds)
     return () => {
-      window.removeEventListener('scroll', updateBounds)
-      window.removeEventListener('resize', updateBounds)
+      scrollingAnchor.removeEventListener('scroll', updateBounds)
+      scrollingAnchor.removeEventListener('resize', updateBounds)
     }
   }, [])