kopia lustrzana https://github.com/Tldraw/Tldraw
165 wiersze
4.1 KiB
TypeScript
165 wiersze
4.1 KiB
TypeScript
import React, { useMemo } from 'react'
|
|
import { RIGHT_MOUSE_BUTTON } from '../constants'
|
|
import {
|
|
preventDefault,
|
|
releasePointerCapture,
|
|
setPointerCapture,
|
|
stopEventPropagation,
|
|
} from '../utils/dom'
|
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
import { useEditor } from './useEditor'
|
|
|
|
export function useCanvasEvents() {
|
|
const editor = useEditor()
|
|
|
|
const events = useMemo(
|
|
function canvasEvents() {
|
|
// Track the last screen point
|
|
let lastX: number, lastY: number
|
|
|
|
function onPointerDown(e: React.PointerEvent) {
|
|
if ((e as any).isKilled) return
|
|
|
|
if (e.button === RIGHT_MOUSE_BUTTON) {
|
|
editor.dispatch({
|
|
type: 'pointer',
|
|
target: 'canvas',
|
|
name: 'right_click',
|
|
...getPointerInfo(e),
|
|
})
|
|
return
|
|
}
|
|
|
|
if (e.button !== 0 && e.button !== 1 && e.button !== 5) return
|
|
|
|
setPointerCapture(e.currentTarget, e)
|
|
|
|
editor.dispatch({
|
|
type: 'pointer',
|
|
target: 'canvas',
|
|
name: 'pointer_down',
|
|
...getPointerInfo(e),
|
|
})
|
|
|
|
if (editor.getOpenMenus().length > 0) {
|
|
editor.updateInstanceState({
|
|
openMenus: [],
|
|
})
|
|
|
|
document.body.click()
|
|
editor.getContainer().focus()
|
|
}
|
|
}
|
|
|
|
function onPointerMove(e: React.PointerEvent) {
|
|
if ((e as any).isKilled) return
|
|
|
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
lastX = e.clientX
|
|
lastY = e.clientY
|
|
|
|
editor.dispatch({
|
|
type: 'pointer',
|
|
target: 'canvas',
|
|
name: 'pointer_move',
|
|
...getPointerInfo(e),
|
|
})
|
|
}
|
|
|
|
function onPointerUp(e: React.PointerEvent) {
|
|
if ((e as any).isKilled) return
|
|
if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return
|
|
lastX = e.clientX
|
|
lastY = e.clientY
|
|
|
|
releasePointerCapture(e.currentTarget, e)
|
|
|
|
editor.dispatch({
|
|
type: 'pointer',
|
|
target: 'canvas',
|
|
name: 'pointer_up',
|
|
...getPointerInfo(e),
|
|
})
|
|
}
|
|
|
|
function onPointerEnter(e: React.PointerEvent) {
|
|
if ((e as any).isKilled) return
|
|
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
|
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })
|
|
}
|
|
|
|
function onPointerLeave(e: React.PointerEvent) {
|
|
if ((e as any).isKilled) return
|
|
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
|
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })
|
|
}
|
|
|
|
function onTouchStart(e: React.TouchEvent) {
|
|
;(e as any).isKilled = true
|
|
// todo: investigate whether this effects keyboard shortcuts
|
|
// god damn it, but necessary for long presses to open the context menu
|
|
document.body.click()
|
|
preventDefault(e)
|
|
}
|
|
|
|
function onTouchEnd(e: React.TouchEvent) {
|
|
;(e as any).isKilled = true
|
|
if (
|
|
(e.target as HTMLElement).tagName !== 'A' &&
|
|
(e.target as HTMLElement).tagName !== 'TEXTAREA' &&
|
|
// When in EditingShape state, we are actually clicking on a 'DIV'
|
|
// not A/TEXTAREA element yet. So, to preserve cursor position
|
|
// for edit mode on mobile we need to not preventDefault.
|
|
// TODO: Find out if we still need this preventDefault in general though.
|
|
!(
|
|
editor.getEditingShape() &&
|
|
(e.target as HTMLElement).className.includes('tl-text-content')
|
|
)
|
|
) {
|
|
preventDefault(e)
|
|
}
|
|
}
|
|
|
|
function onDragOver(e: React.DragEvent<Element>) {
|
|
preventDefault(e)
|
|
}
|
|
|
|
async function onDrop(e: React.DragEvent<Element>) {
|
|
preventDefault(e)
|
|
if (!e.dataTransfer?.files?.length) return
|
|
|
|
const files = Array.from(e.dataTransfer.files)
|
|
|
|
await editor.putExternalContent({
|
|
type: 'files',
|
|
files,
|
|
point: editor.screenToPage({ x: e.clientX, y: e.clientY }),
|
|
ignoreParent: false,
|
|
})
|
|
}
|
|
|
|
function onClick(e: React.MouseEvent) {
|
|
stopEventPropagation(e)
|
|
}
|
|
|
|
return {
|
|
onPointerDown,
|
|
onPointerMove,
|
|
onPointerUp,
|
|
onPointerEnter,
|
|
onPointerLeave,
|
|
onDragOver,
|
|
onDrop,
|
|
onTouchStart,
|
|
onTouchEnd,
|
|
onClick,
|
|
}
|
|
},
|
|
[editor]
|
|
)
|
|
|
|
return events
|
|
}
|