Adds provisional keyboard panning
This commit is contained in:
parent
e5408219de
commit
7da573ffdb
10 changed files with 79 additions and 40 deletions
|
@ -1,15 +1,16 @@
|
|||
import Cursor from './cursor'
|
||||
import { useCoopSelector } from 'state/coop/coop-state'
|
||||
import { useSelector } from 'state'
|
||||
|
||||
export default function Presence(): JSX.Element {
|
||||
const others = useCoopSelector((s) => s.data.others)
|
||||
const currentPageId = useSelector((s) => s.data.currentPageId)
|
||||
|
||||
return (
|
||||
<>
|
||||
{Object.values(others).map(({ connectionId, presence }) => {
|
||||
if (presence == null) {
|
||||
return null
|
||||
}
|
||||
if (presence === null) return null
|
||||
if (presence.pageId !== currentPageId) return null
|
||||
|
||||
return (
|
||||
<Cursor
|
||||
|
|
|
@ -2,12 +2,6 @@ import React from 'react'
|
|||
import styled from 'styles'
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
// const transition = {
|
||||
// type: 'spring',
|
||||
// mass: 2,
|
||||
// damping: 20,
|
||||
// }
|
||||
|
||||
export default function Cursor({
|
||||
color = 'dodgerblue',
|
||||
duration = 0,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
fastTranslate,
|
||||
} from 'state/hacks'
|
||||
import inputs from 'state/inputs'
|
||||
import Vec from 'utils/vec'
|
||||
|
||||
export default function useCanvasEvents(
|
||||
rCanvas: MutableRefObject<SVGGElement>
|
||||
|
@ -27,8 +28,14 @@ export default function useCanvasEvents(
|
|||
const handlePointerMove = useCallback((e: React.PointerEvent) => {
|
||||
if (!inputs.canAccept(e.pointerId)) return
|
||||
|
||||
const prev = inputs.pointer?.point
|
||||
const info = inputs.pointerMove(e)
|
||||
|
||||
if (prev && state.isIn('selecting') && inputs.keys[' ']) {
|
||||
state.send('KEYBOARD_PANNED_CAMERA', { delta: Vec.sub(prev, info.point) })
|
||||
return
|
||||
}
|
||||
|
||||
if (state.isIn('draw.editing')) {
|
||||
fastDrawUpdate(info)
|
||||
} else if (state.isIn('brushSelecting')) {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { useEffect } from 'react'
|
||||
import state from 'state'
|
||||
import inputs from 'state/inputs'
|
||||
import { MoveType } from 'types'
|
||||
import { getKeyboardEventInfo, metaKey } from 'utils'
|
||||
import { metaKey } from 'utils'
|
||||
|
||||
export default function useKeyboardEvents() {
|
||||
useEffect(() => {
|
||||
|
@ -24,7 +25,7 @@ export default function useKeyboardEvents() {
|
|||
e.preventDefault()
|
||||
}
|
||||
|
||||
const info = getKeyboardEventInfo(e)
|
||||
const info = inputs.keydown(e)
|
||||
|
||||
switch (e.key) {
|
||||
case 'ArrowUp': {
|
||||
|
@ -269,7 +270,7 @@ export default function useKeyboardEvents() {
|
|||
}
|
||||
|
||||
function handleKeyUp(e: KeyboardEvent) {
|
||||
const info = getKeyboardEventInfo(e)
|
||||
const info = inputs.keyup(e)
|
||||
|
||||
if (e.key === 'Shift') {
|
||||
state.send('RELEASED_SHIFT_KEY', info)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import React, { MutableRefObject, useCallback } from 'react'
|
||||
import state from 'state'
|
||||
import inputs from 'state/inputs'
|
||||
import Vec from 'utils/vec'
|
||||
|
||||
export default function useShapeEvents(
|
||||
id: string,
|
||||
|
@ -57,6 +58,20 @@ export default function useShapeEvents(
|
|||
(e: React.PointerEvent) => {
|
||||
if (!inputs.canAccept(e.pointerId)) return
|
||||
|
||||
const prev = inputs.pointer?.point
|
||||
const info = inputs.pointerMove(e)
|
||||
|
||||
if (prev && state.isIn('selecting') && inputs.keys[' ']) {
|
||||
if (!e.currentTarget.hasPointerCapture(e.pointerId)) {
|
||||
e.currentTarget.setPointerCapture(e.pointerId)
|
||||
}
|
||||
|
||||
state.send('KEYBOARD_PANNED_CAMERA', {
|
||||
delta: Vec.sub(prev, info.point),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (isParent) {
|
||||
state.send('MOVED_OVER_GROUP', inputs.pointerEnter(e, id))
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable prefer-const */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { Client, Room, createClient } from '@liveblocks/client'
|
||||
import coopState from './coop-state'
|
||||
import { CoopPresence } from 'types'
|
||||
|
@ -108,6 +106,7 @@ class CoopClient {
|
|||
bufferedYs: this.bufferedYs,
|
||||
times,
|
||||
duration,
|
||||
pageId,
|
||||
})
|
||||
|
||||
// Reset data for next update
|
||||
|
@ -118,6 +117,7 @@ class CoopClient {
|
|||
elapsed = 0
|
||||
}
|
||||
|
||||
// Add the new point and time
|
||||
this.bufferedXs.push(point[0])
|
||||
this.bufferedYs.push(point[1])
|
||||
this.bufferedTs.push(elapsed / 1000)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import { PointerInfo } from 'types'
|
||||
import { KeyboardInfo, PointerInfo } from 'types'
|
||||
import vec from 'utils/vec'
|
||||
import { isDarwin, getPoint } from 'utils'
|
||||
|
||||
|
@ -8,8 +8,12 @@ const DOUBLE_CLICK_DURATION = 250
|
|||
class Inputs {
|
||||
activePointerId?: number
|
||||
pointerUpTime = 0
|
||||
points: Record<string, PointerInfo> = {}
|
||||
|
||||
pointer: PointerInfo
|
||||
points: Record<string, PointerInfo> = {}
|
||||
|
||||
keyboard: KeyboardInfo
|
||||
keys: Record<string, boolean> = {}
|
||||
|
||||
touchStart(e: TouchEvent | React.TouchEvent, target: string) {
|
||||
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
||||
|
@ -190,6 +194,36 @@ class Inputs {
|
|||
resetDoubleClick() {
|
||||
this.pointerUpTime = 0
|
||||
}
|
||||
|
||||
keydown = (e: KeyboardEvent | React.KeyboardEvent): KeyboardInfo => {
|
||||
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
||||
|
||||
this.keys[e.key] = true
|
||||
|
||||
return {
|
||||
key: e.key,
|
||||
keys: Object.keys(this.keys),
|
||||
shiftKey,
|
||||
ctrlKey,
|
||||
metaKey: isDarwin() ? metaKey : ctrlKey,
|
||||
altKey,
|
||||
}
|
||||
}
|
||||
|
||||
keyup = (e: KeyboardEvent | React.KeyboardEvent): KeyboardInfo => {
|
||||
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
||||
|
||||
delete this.keys[e.key]
|
||||
|
||||
return {
|
||||
key: e.key,
|
||||
keys: Object.keys(this.keys),
|
||||
shiftKey,
|
||||
ctrlKey,
|
||||
metaKey: isDarwin() ? metaKey : ctrlKey,
|
||||
altKey,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Inputs()
|
||||
|
|
|
@ -173,8 +173,6 @@ const state = createState({
|
|||
// RT_CHANGED_STATUS: 'setRtStatus',
|
||||
// RT_DELETED_SHAPE: 'deleteRtShape',
|
||||
// RT_EDITED_SHAPE: 'editRtShape',
|
||||
// RT_MOVED_CURSOR: 'moveRtCursor',
|
||||
// MOVED_POINTER: { secretlyDo: 'sendRtCursorMove' },
|
||||
// Client
|
||||
RESIZED_WINDOW: 'resetPageState',
|
||||
RESET_DOCUMENT_STATE: 'resetDocumentState',
|
||||
|
@ -334,6 +332,7 @@ const state = createState({
|
|||
selecting: {
|
||||
onEnter: ['setActiveToolSelect', 'clearInputs'],
|
||||
on: {
|
||||
KEYBOARD_PANNED_CAMERA: 'panCamera',
|
||||
STARTED_PINCHING: {
|
||||
unless: 'isInSession',
|
||||
to: 'pinching.selectPinching',
|
||||
|
|
10
types.ts
10
types.ts
|
@ -44,6 +44,7 @@ export type CoopPresence = {
|
|||
bufferedYs: number[]
|
||||
times: number[]
|
||||
duration: number
|
||||
pageId: string
|
||||
}
|
||||
|
||||
export interface TLDocument {
|
||||
|
@ -286,6 +287,15 @@ export interface PointerInfo {
|
|||
altKey: boolean
|
||||
}
|
||||
|
||||
export interface KeyboardInfo {
|
||||
key: string
|
||||
keys: string[]
|
||||
shiftKey: boolean
|
||||
ctrlKey: boolean
|
||||
metaKey: boolean
|
||||
altKey: boolean
|
||||
}
|
||||
|
||||
export enum Edge {
|
||||
Top = 'top_edge',
|
||||
Right = 'right_edge',
|
||||
|
|
|
@ -1564,28 +1564,6 @@ export function metaKey(e: KeyboardEvent | React.KeyboardEvent): boolean {
|
|||
return isDarwin() ? e.metaKey : e.ctrlKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract info about a keyboard event.
|
||||
* @param e
|
||||
*/
|
||||
export function getKeyboardEventInfo(e: KeyboardEvent | React.KeyboardEvent): {
|
||||
key: string
|
||||
shiftKey: boolean
|
||||
ctrlKey: boolean
|
||||
metaKey: boolean
|
||||
altKey: boolean
|
||||
} {
|
||||
const { shiftKey, ctrlKey, metaKey, altKey } = e
|
||||
|
||||
return {
|
||||
key: e.key,
|
||||
shiftKey,
|
||||
ctrlKey,
|
||||
metaKey: isDarwin() ? metaKey : ctrlKey,
|
||||
altKey,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the closest point on a SVG path to an off-path point.
|
||||
* @param pathNode
|
||||
|
|
Loading…
Reference in a new issue