فهرست منبع

fix: menu drifting issue

Peng Xiao 3 سال پیش
والد
کامیت
54ddc09f3c

+ 73 - 61
tldraw/apps/tldraw-logseq/src/components/ContextBar/ContextBar.tsx

@@ -4,18 +4,19 @@ import {
   TLContextBarComponent,
   useApp,
   getContextBarTranslation,
+  useRendererContext,
 } from '@tldraw/react'
 import { observer } from 'mobx-react-lite'
 import type { TextShape, PolygonShape, Shape } from '~lib/shapes'
 import { NumberInput } from '~components/inputs/NumberInput'
 import { ColorInput } from '~components/inputs/ColorInput'
 
-const _ContextBar: TLContextBarComponent<Shape> = ({
-  shapes,
-  offset,
-  scaledBounds,
-  // rotation,
-}) => {
+const _ContextBar: TLContextBarComponent<Shape> = ({ shapes, offsets }) => {
+  const {
+    viewport: {
+      camera: { zoom },
+    },
+  } = useRendererContext()
   const app = useApp()
   const rSize = React.useRef<[number, number] | null>(null)
   const rContextBar = React.useRef<HTMLDivElement>(null)
@@ -63,9 +64,18 @@ const _ContextBar: TLContextBarComponent<Shape> = ({
     const elm = rContextBar.current
     if (!elm) return
     const size = rSize.current ?? [0, 0]
-    const [x, y] = getContextBarTranslation(size, { ...offset, bottom: offset.bottom - 32 })
+    const vpOffsets = {
+      left: offsets.left / zoom,
+      right: offsets.right / zoom,
+      top: offsets.top / zoom,
+      bottom: offsets.bottom / zoom,
+      width: offsets.width / zoom,
+      height: offsets.height / zoom,
+    }
+
+    const [x, y] = getContextBarTranslation(size, { ...vpOffsets, bottom: vpOffsets.bottom - 32 })
     elm.style.setProperty('transform', `translateX(${x}px) translateY(${y}px)`)
-  }, [offset])
+  }, [offsets, zoom])
 
   if (!app) return null
 
@@ -79,65 +89,67 @@ const _ContextBar: TLContextBarComponent<Shape> = ({
   return (
     <HTMLContainer centered>
       <div ref={rContextBar} className="contextbar">
-        {ShapeContent ? (
-          <ShapeContent />
-        ) : (
-          <>
-            <ColorInput label="Stroke" value={shapes[0].props.stroke} onChange={updateStroke} />
-            <ColorInput label="Fill" value={shapes[0].props.fill} onChange={updateFill} />
-            <NumberInput
-              label="Width"
-              value={Math.max(...shapes.map(shape => shape.props.strokeWidth))}
-              onChange={updateStrokeWidth}
-              style={{ width: 48 }}
-            />
-            {sidesShapes.length > 0 && (
+        <div style={{ transform: `scale(var(--tl-scale))` }}>
+          {ShapeContent ? (
+            <ShapeContent />
+          ) : (
+            <>
+              <ColorInput label="Stroke" value={shapes[0].props.stroke} onChange={updateStroke} />
+              <ColorInput label="Fill" value={shapes[0].props.fill} onChange={updateFill} />
               <NumberInput
-                label="Sides"
-                value={Math.max(...sidesShapes.map(shape => shape.props.sides))}
-                onChange={updateSides}
-                style={{ width: 40 }}
+                label="Width"
+                value={Math.max(...shapes.map(shape => shape.props.strokeWidth))}
+                onChange={updateStrokeWidth}
+                style={{ width: 48 }}
               />
-            )}
-            {sidesShapes.length > 0 && (
-              <NumberInput
-                label="Ratio"
-                value={Math.max(...sidesShapes.map(shape => shape.props.ratio))}
-                onChange={updateRatio}
-                step={0.1}
-                min={0}
-                max={2}
-                style={{ width: 40 }}
-              />
-            )}
-            <NumberInput
-              label="Opacity"
-              value={Math.max(...shapes.map(shape => shape.props.opacity))}
-              onChange={updateOpacity}
-              step={0.1}
-              style={{ width: 48 }}
-            />
-            {textShapes.length > 0 ? (
-              <>
+              {sidesShapes.length > 0 && (
                 <NumberInput
-                  label="Size"
-                  value={Math.max(...textShapes.map(shape => shape.props.fontSize))}
-                  onChange={updateFontSize}
-                  style={{ width: 48 }}
+                  label="Sides"
+                  value={Math.max(...sidesShapes.map(shape => shape.props.sides))}
+                  onChange={updateSides}
+                  style={{ width: 40 }}
                 />
+              )}
+              {sidesShapes.length > 0 && (
                 <NumberInput
-                  label=" Weight"
-                  value={Math.max(...textShapes.map(shape => shape.props.fontWeight))}
-                  onChange={updateFontWeight}
-                  style={{ width: 48 }}
+                  label="Ratio"
+                  value={Math.max(...sidesShapes.map(shape => shape.props.ratio))}
+                  onChange={updateRatio}
+                  step={0.1}
+                  min={0}
+                  max={2}
+                  style={{ width: 40 }}
                 />
-              </>
-            ) : null}
-          </>
-        )}
-        <a className="shape-link" onClick={() => app.pubEvent('whiteboard-link', shapes)}>
-          Link
-        </a>
+              )}
+              <NumberInput
+                label="Opacity"
+                value={Math.max(...shapes.map(shape => shape.props.opacity))}
+                onChange={updateOpacity}
+                step={0.1}
+                style={{ width: 48 }}
+              />
+              {textShapes.length > 0 ? (
+                <>
+                  <NumberInput
+                    label="Size"
+                    value={Math.max(...textShapes.map(shape => shape.props.fontSize))}
+                    onChange={updateFontSize}
+                    style={{ width: 48 }}
+                  />
+                  <NumberInput
+                    label=" Weight"
+                    value={Math.max(...textShapes.map(shape => shape.props.fontWeight))}
+                    onChange={updateFontWeight}
+                    style={{ width: 48 }}
+                  />
+                </>
+              ) : null}
+            </>
+          )}
+          <a className="shape-link" onClick={() => app.pubEvent('whiteboard-link', shapes)}>
+            Link
+          </a>
+        </div>
       </div>
     </HTMLContainer>
   )

+ 2 - 0
tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx

@@ -10,6 +10,7 @@ const printPoint = (point: number[]) => {
 export const DevTools = observer(() => {
   const {
     viewport: {
+      bounds,
       camera: { point, zoom },
     },
     inputs,
@@ -40,6 +41,7 @@ export const DevTools = observer(() => {
     ['MP', printPoint(inputs.currentPoint)],
     ['MS', printPoint(inputs.currentScreenPoint)],
     ['VP', printPoint(point)],
+    ['VBR', printPoint([bounds.maxX, bounds.maxY])],
   ]
     .map(p => p.join(''))
     .join('|')

+ 2 - 2
tldraw/packages/core/src/utils/BoundsUtils.ts

@@ -196,7 +196,7 @@ export class BoundsUtils {
         width: bounds.width * n,
         height: bounds.height * n,
       },
-      center
+      [center[0] * n, center[1] * n]
     )
   }
 
@@ -211,7 +211,7 @@ export class BoundsUtils {
         width: bounds.width / n,
         height: bounds.height / n,
       },
-      center
+      [center[0] / n, center[1] / n]
     )
   }
 

+ 2 - 4
tldraw/packages/react/src/components/Container/Container.tsx

@@ -16,7 +16,6 @@ interface ContainerProps extends React.HTMLProps<HTMLDivElement> {
 export const Container = observer<ContainerProps>(function Container({
   id,
   bounds,
-  scale,
   zIndex,
   rotation = 0,
   className = '',
@@ -30,9 +29,8 @@ export const Container = observer<ContainerProps>(function Container({
     elm.style.transform = `translate(
         calc(${bounds.minX}px - var(--tl-padding)),
         calc(${bounds.minY}px - var(--tl-padding)))
-        rotate(${rotation + (bounds.rotation || 0)}rad)
-      ${scale ? `scale(${scale[0]}, ${scale[1]})` : ''}`
-  }, [bounds.minX, bounds.minY, rotation, bounds.rotation, scale])
+        rotate(${rotation + (bounds.rotation || 0)}rad)`
+  }, [bounds.minX, bounds.minY, rotation, bounds.rotation])
 
   React.useLayoutEffect(() => {
     const elm = rBounds.current!

+ 5 - 3
tldraw/packages/react/src/components/ContextBarContainer/ContextBarContainer.tsx

@@ -35,11 +35,12 @@ export const ContextBarContainer = observer(function ContextBar<S extends TLReac
   const rotatedBounds = BoundsUtils.getRotatedBounds(bounds, rotation)
   const scaledBounds = BoundsUtils.multiplyBounds(rotatedBounds, zoom)
 
-  useCounterScaledPosition(rBounds, scaledBounds, zoom, 10003)
+  useCounterScaledPosition(rBounds, bounds, rotation, 10003)
 
   if (!ContextBar) throw Error('Expected a ContextBar component.')
 
-  const screenBounds = BoundsUtils.translateBounds(scaledBounds, [x, y])
+  const screenBounds = BoundsUtils.translateBounds(scaledBounds, [x * zoom, y * zoom])
+
   const offsets: TLOffset = {
     left: screenBounds.minX,
     right: vpBounds.width - screenBounds.maxX,
@@ -48,6 +49,7 @@ export const ContextBarContainer = observer(function ContextBar<S extends TLReac
     width: screenBounds.width,
     height: screenBounds.height,
   }
+
   const inView =
     BoundsUtils.boundsContain(vpBounds, screenBounds) ||
     BoundsUtils.boundsCollide(vpBounds, screenBounds)
@@ -76,7 +78,7 @@ export const ContextBarContainer = observer(function ContextBar<S extends TLReac
       <ContextBar
         shapes={shapes}
         bounds={bounds}
-        offset={offsets}
+        offsets={offsets}
         scaledBounds={scaledBounds}
         rotation={rotation}
       />

+ 1 - 1
tldraw/packages/react/src/components/SelectionDetailContainer/SelectionDetailContainer.tsx

@@ -30,7 +30,7 @@ export const SelectionDetailContainer = observer(function SelectionDetail<S exte
 
   const rBounds = React.useRef<HTMLDivElement>(null)
   const scaledBounds = BoundsUtils.multiplyBounds(bounds, zoom)
-  useCounterScaledPosition(rBounds, scaledBounds, zoom, 10003)
+  useCounterScaledPosition(rBounds, bounds, rotation, 10003)
 
   if (!SelectionDetail) throw Error('Expected a SelectionDetail component.')
 

+ 2 - 5
tldraw/packages/react/src/components/ui/SelectionDetail/SelectionDetail.tsx

@@ -11,7 +11,6 @@ import Vec from '@tldraw/vec'
 export const SelectionDetail = observer(function SelectionDetail<S extends TLReactShape>({
   bounds,
   shapes,
-  scaledBounds,
   detail = 'size',
   rotation = 0,
 }: TLSelectionDetailProps<S>) {
@@ -26,10 +25,8 @@ export const SelectionDetail = observer(function SelectionDetail<S extends TLRea
         className="tl-bounds-detail"
         style={{
           transform: isFlipped
-            ? `rotate(${Math.PI + selectionRotation}rad) translateY(${
-                scaledBounds.height / 2 + 32
-              }px)`
-            : `rotate(${selectionRotation}rad) translateY(${scaledBounds.height / 2 + 24}px)`,
+            ? `rotate(${Math.PI + selectionRotation}rad) translateY(${bounds.height / 2 + 32}px)`
+            : `rotate(${selectionRotation}rad) translateY(${bounds.height / 2 + 24}px)`,
           padding: '2px 3px',
           borderRadius: '1px',
         }}

+ 0 - 44
tldraw/packages/react/src/hooks/individual-transforms/useCounterScaledPosition.tsx

@@ -1,44 +0,0 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-import * as React from 'react'
-import type { TLBounds } from '@tldraw/core'
-
-export function useCounterScaledPosition(
-  ref: React.RefObject<HTMLElement>,
-  bounds: TLBounds,
-  camera: { point: number[]; zoom: number },
-  zIndex: number
-) {
-  const {
-    point: [x, y],
-    zoom,
-  } = camera
-
-  const rWidth = React.useRef(0)
-  const rHeight = React.useRef(0)
-
-  React.useLayoutEffect(() => {
-    const elm = ref.current!
-    rWidth.current = (bounds.width + 128 * (1 / zoom)) * zoom
-    rHeight.current = (bounds.height + 128 * (1 / zoom)) * zoom
-    elm.style.setProperty('width', `${rWidth.current}px`)
-    elm.style.setProperty('height', `${rHeight.current}px`)
-    if (zIndex !== undefined) {
-      elm.style.setProperty('z-index', zIndex?.toString())
-    }
-  }, [bounds.width, bounds.height, zIndex, zoom])
-
-  React.useLayoutEffect(() => {
-    const elm = ref.current!
-    let transform = `
-      translate(
-        ${(x + bounds.minX - 64 * (1 / zoom)) * zoom}px,
-        ${(y + bounds.minY - 64 * (1 / zoom)) * zoom}px
-      )`
-    if (bounds.rotation !== 0) {
-      transform += `translate(${rWidth.current / 2}px, ${rHeight.current / 2}px)
-      rotate(${bounds.rotation || 0}rad)
-      translate(${-rWidth.current / 2}px, ${-rHeight.current / 2}px)`
-    }
-    elm.style.setProperty('transform', transform)
-  }, [bounds.minX, bounds.minY, bounds.rotation, x, y, zoom])
-}

+ 0 - 52
tldraw/packages/react/src/hooks/individual-transforms/usePosition.tsx

@@ -1,52 +0,0 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-import * as React from 'react'
-import type { TLBounds } from '@tldraw/core'
-import { useRendererContext } from '~hooks'
-
-export function usePosition(ref: React.RefObject<HTMLElement>, bounds: TLBounds, zIndex: number) {
-  const {
-    viewport: {
-      camera: {
-        point: [x, y],
-        zoom,
-      },
-    },
-  } = useRendererContext()
-
-  const rWidth = React.useRef(0)
-  const rHeight = React.useRef(0)
-
-  React.useLayoutEffect(() => {
-    const elm = ref.current!
-    rWidth.current = bounds.width + 128 * (1 / zoom)
-    rHeight.current = bounds.height + 128 * (1 / zoom)
-
-    elm.style.setProperty('width', `${rWidth.current}px`)
-    elm.style.setProperty('height', `${rHeight.current}px`)
-
-    if (zIndex !== undefined) {
-      elm.style.setProperty('z-index', zIndex?.toString())
-    }
-  }, [bounds.width, bounds.height, zIndex, zoom])
-
-  React.useLayoutEffect(() => {
-    const elm = ref.current!
-
-    let transform = `
-      scale(${zoom})
-      translate3d(
-        ${x + bounds.minX - 64 * (1 / zoom)}px,
-        ${y + bounds.minY - 64 * (1 / zoom)}px,
-        0
-      )`
-
-    if (bounds.rotation !== 0) {
-      transform += `translate3d(${rWidth.current / 2}px, ${rHeight.current / 2}px,
-      0)
-      rotate(${bounds.rotation || 0}rad)
-      translate(${-rWidth.current / 2}px, ${-rHeight.current / 2}px)`
-    }
-
-    elm.style.setProperty('transform', transform)
-  }, [bounds.minX, bounds.minY, bounds.rotation, x, y, zoom])
-}

+ 12 - 21
tldraw/packages/react/src/hooks/useCounterScaledPosition.tsx

@@ -1,37 +1,28 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import * as React from 'react'
 import type { TLBounds } from '@tldraw/core'
 
 export function useCounterScaledPosition(
   ref: React.RefObject<HTMLElement>,
   bounds: TLBounds,
-  zoom: number,
+  rotation: number,
   zIndex: number
 ) {
   React.useLayoutEffect(() => {
-    const elm = ref.current
-    if (!elm) return
-
-    elm.style.setProperty(
-      'transform',
-      `translate(
-          calc(${bounds.minX - 64}px),
-          calc(${bounds.minY - 64}px)
-        )
-        scale(var(--tl-scale))`
-    )
-  }, [bounds.minX, bounds.minY])
+    const elm = ref.current!
+    elm.style.transform = `translate(
+        calc(${bounds.minX}px - var(--tl-padding)),
+        calc(${bounds.minY}px - var(--tl-padding)))`
+  }, [bounds.minX, bounds.minY, rotation, bounds.rotation])
 
   React.useLayoutEffect(() => {
-    const elm = ref.current
-    if (!elm) return
-
-    elm.style.setProperty('width', `calc(${Math.floor(bounds.width)}px + 64px * 2)`)
-    elm.style.setProperty('height', `calc(${Math.floor(bounds.height)}px + 64px * 2)`)
+    const elm = ref.current!
+    elm.style.width = `calc(${Math.floor(bounds.width)}px + (var(--tl-padding) * 2))`
+    elm.style.height = `calc(${Math.floor(bounds.height)}px + (var(--tl-padding) * 2))`
   }, [bounds.width, bounds.height])
 
   React.useLayoutEffect(() => {
-    const elm = ref.current
-    if (!elm) return
-    elm.style.setProperty('z-index', zIndex.toString())
+    const elm = ref.current!
+    if (zIndex !== undefined) elm.style.zIndex = zIndex.toString()
   }, [zIndex])
 }

+ 1 - 1
tldraw/packages/react/src/hooks/useStylesheet.ts

@@ -115,7 +115,7 @@ const tlcss = css`
     --tl-cursor: inherit;
     --tl-zoom: 1;
     --tl-scale: calc(1 / var(--tl-zoom));
-    --tl-padding: calc(64px * var(--tl-scale));
+    --tl-padding: 64px;
     --tl-shadow-color: 0deg 0% 0%;
     --tl-shadow-elevation-low: 0px 0.4px 0.5px hsl(var(--tl-shadow-color) / 0.04),
       0px 0.6px 0.8px -0.7px hsl(var(--tl-shadow-color) / 0.06),

+ 1 - 1
tldraw/packages/react/src/types/component-props.ts

@@ -22,7 +22,7 @@ export type TLContextBarProps<S extends TLReactShape = TLReactShape> = {
   bounds: TLBounds
   scaledBounds: TLBounds
   rotation: number
-  offset: TLOffset
+  offsets: TLOffset
 }
 
 export type TLContextBarComponent<S extends TLReactShape = TLReactShape> = (