Przeglądaj źródła

fix: bring back shape rotation

Peng Xiao 3 lat temu
rodzic
commit
d0ddbf19a2

+ 1 - 1
src/main/frontend/extensions/tldraw.cljs

@@ -67,7 +67,7 @@
              (do (. api selectShapes block-id)
                  (. api zoomToSelection)))))
        nil) [name block-id tln])
-    (when (and name (not-empty (gobj/get data "currentPageId")))
+    (when (and (not-empty name) (not-empty (gobj/get data "currentPageId")))
       [:div.draw.tldraw.whiteboard.relative.w-full.h-full
        {:style {:overscroll-behavior "none"}
         :on-blur #(state/set-block-component-editing-mode! false)

+ 6 - 3
tldraw/apps/tldraw-logseq/src/app.tsx

@@ -17,12 +17,15 @@ import { useQuickAdd } from '~hooks/useQuickAdd'
 import { LogseqContext, LogseqContextValue } from '~lib/logseq-context'
 import { Shape, shapes } from '~lib/shapes'
 import {
+  BoxTool,
+  EllipseTool,
   HighlighterTool,
   HTMLTool,
   LineTool,
   LogseqPortalTool,
   NuEraseTool,
   PencilTool,
+  PolygonTool,
   TextTool,
   YouTubeTool,
 } from '~lib/tools'
@@ -32,10 +35,10 @@ const components: TLReactComponents<Shape> = {
 }
 
 const tools: TLReactToolConstructor<Shape>[] = [
-  // BoxTool,
+  BoxTool,
   // DotTool,
-  // EllipseTool,
-  // PolygonTool,
+  EllipseTool,
+  PolygonTool,
   NuEraseTool,
   HighlighterTool,
   LineTool,

+ 33 - 68
tldraw/apps/tldraw-logseq/src/components/PrimaryTools/PrimaryTools.tsx

@@ -1,10 +1,16 @@
+import { TLSelectTool } from '@tldraw/core'
 import { useApp } from '@tldraw/react'
 import { observer } from 'mobx-react-lite'
 import * as React from 'react'
 import { Button } from '~components/Button'
 import { LogseqIcon, TablerIcon } from '~components/icons'
 
-export const PrimaryTools = observer(function PrimaryTools() {
+interface ToolButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+  id: string
+  icon: string | React.ReactNode
+}
+
+const ToolButton = observer(({ id, icon, title, ...props }: ToolButtonProps) => {
   const app = useApp()
 
   const handleToolClick = React.useCallback(
@@ -15,79 +21,38 @@ export const PrimaryTools = observer(function PrimaryTools() {
     [app]
   )
 
-  const handleToolDoubleClick = React.useCallback(
-    (e: React.MouseEvent<HTMLButtonElement>) => {
-      const tool = e.currentTarget.dataset.tool
-      if (tool) app.selectTool(tool)
-      app.settings.update({ isToolLocked: true })
-    },
-    [app]
+  // Tool must exist
+  const Tool = app.Tools?.find(T => T.id === id) ?? TLSelectTool
+
+  const shortcut = ((Tool as any)['shortcut'] as string[])?.[0]
+
+  const titleWithShortcut = shortcut ? `${title} (${shortcut})` : title
+  return (
+    <Button
+      {...props}
+      title={titleWithShortcut}
+      data-tool={id}
+      data-selected={id === app.selectedTool.id}
+      onClick={handleToolClick}
+    >
+      {typeof icon === 'string' ? <TablerIcon name={icon} /> : icon}
+    </Button>
   )
+})
 
-  const selectedToolId = app.selectedTool.id
+export const PrimaryTools = observer(function PrimaryTools() {
+  const app = useApp()
 
   return (
     <div className="tl-primary-tools">
       <div className="tl-tools-floating-panel" data-tool-locked={app.settings.isToolLocked}>
-        <Button
-          title="Select tool"
-          data-tool="select"
-          data-selected={selectedToolId === 'select'}
-          onClick={handleToolClick}
-        >
-          <TablerIcon name="select-cursor" />
-        </Button>
-        <Button
-          title="Draw tool"
-          data-tool="pencil"
-          data-selected={selectedToolId === 'pencil'}
-          onClick={handleToolClick}
-        >
-          <TablerIcon name="ballpen" />
-        </Button>
-        <Button
-          title="Highlight tool"
-          data-tool="highlighter"
-          data-selected={selectedToolId === 'highlighter'}
-          onClick={handleToolClick}
-        >
-          <TablerIcon name="highlight" />
-        </Button>
-        <Button
-          title="Eraser tool"
-          data-tool="erase"
-          data-selected={selectedToolId === 'erase'}
-          onClick={handleToolClick}
-        >
-          <TablerIcon name="eraser" />
-        </Button>
-        <Button
-          title="Line tool"
-          data-tool="line"
-          data-selected={selectedToolId === 'line'}
-          onClick={handleToolClick}
-          onDoubleClick={handleToolDoubleClick}
-        >
-          <TablerIcon name="connector" />
-        </Button>
-        <Button
-          title="Text tool"
-          data-tool="text"
-          data-selected={selectedToolId === 'text'}
-          onClick={handleToolClick}
-          onDoubleClick={handleToolDoubleClick}
-        >
-          <TablerIcon name="text" />
-        </Button>
-        <Button
-          title="Logseq Portal tool"
-          data-tool="logseq-portal"
-          data-selected={selectedToolId === 'logseq-portal'}
-          onClick={handleToolClick}
-          onDoubleClick={handleToolDoubleClick}
-        >
-          <LogseqIcon />
-        </Button>
+        <ToolButton title="Select" id="select" icon="select-cursor" />
+        <ToolButton title="Draw" id="pencil" icon="ballpen" />
+        <ToolButton title="Highlight" id="highlighter" icon="highlight" />
+        <ToolButton title="Eraser" id="erase" icon="eraser" />
+        <ToolButton title="Connector" id="line" icon="connector" />
+        <ToolButton title="Text" id="text" icon="text" />
+        <ToolButton title="Logseq Portal" id="logseq-portal" icon={<LogseqIcon />} />
       </div>
     </div>
   )

+ 0 - 10
tldraw/apps/tldraw-logseq/src/lib/shapes/ImageShape.tsx

@@ -12,16 +12,6 @@ export interface ImageShapeProps extends TLImageShapeProps, CustomStyleProps {
   opacity: number
 }
 
-declare global {
-  interface Window {
-    logseq?: {
-      api?: {
-        make_asset_url?: (url: string) => string
-      }
-    }
-  }
-}
-
 export class ImageShape extends TLImageShape<ImageShapeProps> {
   static id = 'image'
 

+ 3 - 7
tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx

@@ -300,12 +300,8 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
         finishCreating(uuid)
         // wait until the editor is mounted
         setTimeout(() => {
-          // @ts-expect-error ???
-          const logseqApi = window.logseq?.api as any
-          if (logseqApi) {
-            app.setEditingShape(this)
-            logseqApi.edit_block(uuid)
-          }
+          app.setEditingShape(this)
+          window.logseq?.api?.edit_block?.(uuid)
         })
       }
       return uuid
@@ -559,7 +555,7 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
                   setPrefixIcon(actionIcon)
                   setFocusedOptionIdx(index)
                 }}
-                // we have to use mousedown && stop propagation, otherwise some 
+                // we have to use mousedown && stop propagation, otherwise some
                 // default behavior of clicking the rendered elements will happen
                 onMouseDown={e => {
                   if (onChosen()) {

+ 1 - 1
tldraw/apps/tldraw-logseq/src/lib/shapes/PolygonShape.tsx

@@ -18,7 +18,7 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
     type: 'polygon',
     point: [0, 0],
     size: [100, 100],
-    sides: 5,
+    sides: 3,
     ratio: 1,
     isFlippedY: false,
     stroke: '#000000',

+ 11 - 0
tldraw/apps/tldraw-logseq/src/lib/shapes/index.ts

@@ -54,3 +54,14 @@ export const shapes: TLReactShapeConstructor<Shape>[] = [
   HTMLShape,
   LogseqPortalShape,
 ]
+
+declare global {
+  interface Window {
+    logseq?: {
+      api?: {
+        make_asset_url?: (url: string) => string
+        edit_block?: (uuid: string) => void
+      }
+    }
+  }
+}

+ 12 - 7
tldraw/packages/core/src/lib/TLApp/TLApp.ts

@@ -4,6 +4,7 @@
 import { Vec } from '@tldraw/vec'
 import { action, computed, makeObservable, observable, transaction } from 'mobx'
 import { GRID_SIZE } from '~constants'
+
 import {
   TLInputs,
   TLPage,
@@ -11,9 +12,8 @@ import {
   TLSelectTool,
   TLShape,
   TLShapeConstructor,
-  TLShapeModel,
-  TLToolConstructor,
-  TLViewport,
+  TLShapeModel, TLToolConstructor,
+  TLViewport
 } from '~lib'
 import { TLApi } from '~lib/TLApi'
 import { TLCursors } from '~lib/TLCursors'
@@ -27,7 +27,7 @@ import type {
   TLStateEvents,
   TLSubscription,
   TLSubscriptionEventInfo,
-  TLSubscriptionEventName,
+  TLSubscriptionEventName
 } from '~types'
 import { BoundsUtils, KeyUtils } from '~utils'
 import { TLHistory } from '../TLHistory'
@@ -82,6 +82,8 @@ export class TLApp<
   readonly viewport = new TLViewport()
   readonly settings = new TLSettings()
 
+  Tools: TLToolConstructor<S, K>[] = []
+
   dispose() {
     super.dispose()
     this.keybindingRegistered = false
@@ -457,7 +459,10 @@ export class TLApp<
 
   selectTool = this.transition
 
-  registerTools = this.registerStates
+  registerTools(tools: TLToolConstructor<S, K>[]) {
+    this.Tools = tools
+    return this.registerStates(tools)
+  }
 
   /* ------------------ Editing Shape ----------------- */
 
@@ -673,7 +678,7 @@ export class TLApp<
     const { selectedShapesArray } = this
     return (
       this.isIn('select') &&
-      !this.isInAny('select.translating', 'select.pinching') &&
+      !this.isInAny('select.translating', 'select.pinching', 'select.rotating') &&
       ((selectedShapesArray.length === 1 && !selectedShapesArray[0]?.hideSelection) ||
         selectedShapesArray.length > 1)
     )
@@ -718,7 +723,7 @@ export class TLApp<
         'select.pointingResizeHandle'
       ) &&
       selectedShapesArray.length > 0 &&
-      !selectedShapesArray.every(shape => shape.hideRotateHandle)
+      !selectedShapesArray.some(shape => shape.hideRotateHandle)
     )
   }
 

+ 32 - 2
tldraw/packages/react/src/components/ui/SelectionForeground/SelectionForeground.tsx

@@ -1,14 +1,16 @@
-import { TLResizeCorner, TLResizeEdge } from '@tldraw/core'
+import { TLResizeCorner, TLResizeEdge, TLRotateCorner } from '@tldraw/core'
 import { observer } from 'mobx-react-lite'
 import { SVGContainer } from '~components'
 import type { TLReactShape } from '~lib'
 import type { TLSelectionComponentProps } from '~types'
-import { CornerHandle, EdgeHandle } from './handles'
+import { CornerHandle, EdgeHandle, RotateHandle } from './handles'
+import { RotateCornerHandle } from './handles/RotateCornerHandle'
 
 export const SelectionForeground = observer(function SelectionForeground<S extends TLReactShape>({
   bounds,
   zoom,
   showResizeHandles,
+  showRotateHandles,
   shapes,
 }: TLSelectionComponentProps<S>) {
   const { width, height } = bounds
@@ -66,6 +68,34 @@ export const SelectionForeground = observer(function SelectionForeground<S exten
         disabled={!canResize[0]}
         isHidden={!showResizeHandles}
       />
+      <RotateCornerHandle
+        cx={0}
+        cy={0}
+        targetSize={targetSize}
+        corner={TLRotateCorner.TopLeft}
+        isHidden={!showRotateHandles}
+      />
+      <RotateCornerHandle
+        cx={width + targetSize * 2}
+        cy={0}
+        targetSize={targetSize}
+        corner={TLRotateCorner.TopRight}
+        isHidden={!showRotateHandles}
+      />
+      <RotateCornerHandle
+        cx={width + targetSize * 2}
+        cy={height + targetSize * 2}
+        targetSize={targetSize}
+        corner={TLRotateCorner.BottomRight}
+        isHidden={!showRotateHandles}
+      />
+      <RotateCornerHandle
+        cx={0}
+        cy={height + targetSize * 2}
+        targetSize={targetSize}
+        corner={TLRotateCorner.BottomLeft}
+        isHidden={!showRotateHandles}
+      />
       {canResize?.every(r => r) && (
         <>
           <CornerHandle

+ 0 - 0
tldraw/packages/react/src/components/ui/SelectionForeground/handles/RotateCornerHandle.tsx.tsx → tldraw/packages/react/src/components/ui/SelectionForeground/handles/RotateCornerHandle.tsx


+ 1 - 1
tldraw/packages/react/src/lib/TLReactApp.ts

@@ -1,5 +1,5 @@
 import { TLApp } from '@tldraw/core'
-import type { TLReactShape } from './TLReactShape'
 import type { TLReactEventMap } from '~types'
+import type { TLReactShape } from './TLReactShape'
 
 export class TLReactApp<S extends TLReactShape = TLReactShape> extends TLApp<S, TLReactEventMap> {}