@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
545 lines (544 loc) • 16 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
import { atom, computed, unsafe__withoutCapture } from "@tldraw/state";
import { AtomSet } from "@tldraw/store";
import { TLINSTANCE_ID, TLPOINTER_ID } from "@tldraw/tlschema";
import { INTERNAL_POINTER_IDS } from "../../../constants.mjs";
import { Vec } from "../../../primitives/Vec.mjs";
import { isAccelKey } from "../../../utils/keyboard.mjs";
class InputsManager {
constructor(editor) {
this.editor = editor;
}
editor;
_originPagePoint = atom("originPagePoint", new Vec());
/**
* The most recent pointer down's position in the current page space.
*/
getOriginPagePoint() {
return this._originPagePoint.get();
}
/**
* @deprecated Use `getOriginPagePoint()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get originPagePoint() {
return this.getOriginPagePoint();
}
_originScreenPoint = atom("originScreenPoint", new Vec());
/**
* The most recent pointer down's position in screen space.
*/
getOriginScreenPoint() {
return this._originScreenPoint.get();
}
/**
* @deprecated Use `getOriginScreenPoint()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get originScreenPoint() {
return this.getOriginScreenPoint();
}
_previousPagePoint = atom("previousPagePoint", new Vec());
/**
* The previous pointer position in the current page space.
*/
getPreviousPagePoint() {
return this._previousPagePoint.get();
}
/**
* @deprecated Use `getPreviousPagePoint()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get previousPagePoint() {
return this.getPreviousPagePoint();
}
_previousScreenPoint = atom("previousScreenPoint", new Vec());
/**
* The previous pointer position in screen space.
*/
getPreviousScreenPoint() {
return this._previousScreenPoint.get();
}
/**
* @deprecated Use `getPreviousScreenPoint()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get previousScreenPoint() {
return this.getPreviousScreenPoint();
}
_currentPagePoint = atom("currentPagePoint", new Vec());
/**
* The most recent pointer position in the current page space.
*/
getCurrentPagePoint() {
return this._currentPagePoint.get();
}
/**
* @deprecated Use `getCurrentPagePoint()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get currentPagePoint() {
return this.getCurrentPagePoint();
}
_currentScreenPoint = atom("currentScreenPoint", new Vec());
/**
* The most recent pointer position in screen space.
*/
getCurrentScreenPoint() {
return this._currentScreenPoint.get();
}
/**
* @deprecated Use `getCurrentScreenPoint()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get currentScreenPoint() {
return this.getCurrentScreenPoint();
}
_pointerVelocity = atom("pointerVelocity", new Vec());
/**
* Velocity of mouse pointer, in pixels per millisecond.
*/
getPointerVelocity() {
return this._pointerVelocity.get();
}
/**
* @deprecated Use `getPointerVelocity()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get pointerVelocity() {
return this.getPointerVelocity();
}
/**
* Normally you shouldn't need to set the pointer velocity directly, this is set by the tick manager.
* However, this is currently used in tests to fake pointer velocity.
* @param pointerVelocity - The pointer velocity.
* @internal
*/
setPointerVelocity(pointerVelocity) {
this._pointerVelocity.set(pointerVelocity);
}
/**
* A set containing the currently pressed keys.
*/
keys = new AtomSet("keys");
/**
* A set containing the currently pressed buttons.
*/
buttons = new AtomSet("buttons");
_isPen = atom("isPen", false);
/**
* Whether the input is from a pen.
*/
getIsPen() {
return this._isPen.get();
}
/**
* @deprecated Use `getIsPen()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isPen() {
return this.getIsPen();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isPen(isPen) {
this.setIsPen(isPen);
}
/**
* @param isPen - Whether the input is from a pen.
*/
setIsPen(isPen) {
this._isPen.set(isPen);
}
_shiftKey = atom("shiftKey", false);
/**
* Whether the shift key is currently pressed.
*/
getShiftKey() {
return this._shiftKey.get();
}
/**
* @deprecated Use `getShiftKey()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get shiftKey() {
return this.getShiftKey();
}
// eslint-disable-next-line tldraw/no-setter-getter
set shiftKey(shiftKey) {
this.setShiftKey(shiftKey);
}
/**
* @param shiftKey - Whether the shift key is pressed.
* @internal
*/
setShiftKey(shiftKey) {
this._shiftKey.set(shiftKey);
}
_metaKey = atom("metaKey", false);
/**
* Whether the meta key is currently pressed.
*/
getMetaKey() {
return this._metaKey.get();
}
/**
* @deprecated Use `getMetaKey()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get metaKey() {
return this.getMetaKey();
}
// eslint-disable-next-line tldraw/no-setter-getter
set metaKey(metaKey) {
this.setMetaKey(metaKey);
}
/**
* @param metaKey - Whether the meta key is pressed.
* @internal
*/
setMetaKey(metaKey) {
this._metaKey.set(metaKey);
}
_ctrlKey = atom("ctrlKey", false);
/**
* Whether the ctrl or command key is currently pressed.
*/
getCtrlKey() {
return this._ctrlKey.get();
}
/**
* @deprecated Use `getCtrlKey()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get ctrlKey() {
return this.getCtrlKey();
}
// eslint-disable-next-line tldraw/no-setter-getter
set ctrlKey(ctrlKey) {
this.setCtrlKey(ctrlKey);
}
/**
* @param ctrlKey - Whether the ctrl key is pressed.
* @internal
*/
setCtrlKey(ctrlKey) {
this._ctrlKey.set(ctrlKey);
}
_altKey = atom("altKey", false);
/**
* Whether the alt or option key is currently pressed.
*/
getAltKey() {
return this._altKey.get();
}
/**
* @deprecated Use `getAltKey()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get altKey() {
return this.getAltKey();
}
// eslint-disable-next-line tldraw/no-setter-getter
set altKey(altKey) {
this.setAltKey(altKey);
}
/**
* @param altKey - Whether the alt key is pressed.
* @internal
*/
setAltKey(altKey) {
this._altKey.set(altKey);
}
/**
* Is the accelerator key (cmd on mac, ctrl elsewhere) currently pressed.
*/
getAccelKey() {
return isAccelKey({ metaKey: this.getMetaKey(), ctrlKey: this.getCtrlKey() });
}
/**
* @deprecated Use `getAccelKey()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get accelKey() {
return this.getAccelKey();
}
_isDragging = atom("isDragging", false);
/**
* Whether the user is dragging.
*/
getIsDragging() {
return this._isDragging.get();
}
/**
* Soon to be deprecated, use `getIsDragging()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isDragging() {
return this.getIsDragging();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isDragging(isDragging) {
this.setIsDragging(isDragging);
}
/**
* @param isDragging - Whether the user is dragging.
*/
setIsDragging(isDragging) {
this._isDragging.set(isDragging);
}
_isPointing = atom("isPointing", false);
/**
* Whether the user is pointing.
*/
getIsPointing() {
return this._isPointing.get();
}
/**
* @deprecated Use `getIsPointing()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isPointing() {
return this.getIsPointing();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isPointing(isPointing) {
this.setIsPointing(isPointing);
}
/**
* @param isPointing - Whether the user is pointing.
* @internal
*/
setIsPointing(isPointing) {
this._isPointing.set(isPointing);
}
_isRightPointing = atom("isRightPointing", false);
/**
* Whether the user is right-click pointing (before drag threshold).
*/
getIsRightPointing() {
return this._isRightPointing.get();
}
/** @internal */
setIsRightPointing(isRightPointing) {
this._isRightPointing.set(isRightPointing);
}
_isPinching = atom("isPinching", false);
/**
* Whether the user is pinching.
*/
getIsPinching() {
return this._isPinching.get();
}
/**
* @deprecated Use `getIsPinching()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isPinching() {
return this.getIsPinching();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isPinching(isPinching) {
this.setIsPinching(isPinching);
}
/**
* @param isPinching - Whether the user is pinching.
* @internal
*/
setIsPinching(isPinching) {
this._isPinching.set(isPinching);
}
_isEditing = atom("isEditing", false);
/**
* Whether the user is editing.
*/
getIsEditing() {
return this._isEditing.get();
}
/**
* @deprecated Use `getIsEditing()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isEditing() {
return this.getIsEditing();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isEditing(isEditing) {
this.setIsEditing(isEditing);
}
/**
* @param isEditing - Whether the user is editing.
*/
setIsEditing(isEditing) {
this._isEditing.set(isEditing);
}
_isPanning = atom("isPanning", false);
/**
* Whether the user is panning.
*/
getIsPanning() {
return this._isPanning.get();
}
/**
* @deprecated Use `getIsPanning()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isPanning() {
return this.getIsPanning();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isPanning(isPanning) {
this.setIsPanning(isPanning);
}
/**
* @param isPanning - Whether the user is panning.
* @internal
*/
setIsPanning(isPanning) {
this._isPanning.set(isPanning);
}
_isSpacebarPanning = atom("isSpacebarPanning", false);
/**
* Whether the user is spacebar panning.
*/
getIsSpacebarPanning() {
return this._isSpacebarPanning.get();
}
/**
* @deprecated Use `getIsSpacebarPanning()` instead.
*/
// eslint-disable-next-line tldraw/no-setter-getter
get isSpacebarPanning() {
return this.getIsSpacebarPanning();
}
// eslint-disable-next-line tldraw/no-setter-getter
set isSpacebarPanning(isSpacebarPanning) {
this.setIsSpacebarPanning(isSpacebarPanning);
}
/**
* @param isSpacebarPanning - Whether the user is spacebar panning.
* @internal
*/
setIsSpacebarPanning(isSpacebarPanning) {
this._isSpacebarPanning.set(isSpacebarPanning);
}
_getHasCollaborators() {
return this.editor.getCollaborators().length > 0;
}
/**
* The previous point used for velocity calculation (updated each tick, not each pointer event).
* @internal
*/
_velocityPrevPoint = new Vec();
/**
* Update the pointer velocity based on elapsed time. Called by the tick manager.
* @param elapsed - The time elapsed since the last tick in milliseconds.
* @internal
*/
updatePointerVelocity(elapsed) {
const currentScreenPoint = this.getCurrentScreenPoint();
const pointerVelocity = this.getPointerVelocity();
if (elapsed === 0) return;
const delta = Vec.Sub(currentScreenPoint, this._velocityPrevPoint);
this._velocityPrevPoint = currentScreenPoint.clone();
const length = delta.len();
const direction = length ? delta.div(length) : new Vec(0, 0);
const next = pointerVelocity.clone().lrp(direction.mul(length / elapsed), 0.5);
if (Math.abs(next.x) < 0.01) next.x = 0;
if (Math.abs(next.y) < 0.01) next.y = 0;
if (!pointerVelocity.equals(next)) {
this._pointerVelocity.set(next);
}
}
/**
* Update the input points from a pointer, pinch, or wheel event.
*
* @param info - The event info.
* @internal
*/
updateFromEvent(info) {
const currentScreenPoint = this._currentScreenPoint.__unsafe__getWithoutCapture();
const currentPagePoint = this._currentPagePoint.__unsafe__getWithoutCapture();
const isPinching = this._isPinching.__unsafe__getWithoutCapture();
const { screenBounds } = this.editor.store.unsafeGetWithoutCapture(TLINSTANCE_ID);
const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.editor.getCamera());
const sx = info.point.x - screenBounds.x;
const sy = info.point.y - screenBounds.y;
const sz = info.point.z ?? 0.5;
this._previousScreenPoint.set(currentScreenPoint);
this._previousPagePoint.set(currentPagePoint);
this._currentScreenPoint.set(new Vec(sx, sy));
const nx = sx / cz - cx;
const ny = sy / cz - cy;
if (isFinite(nx) && isFinite(ny)) {
this._currentPagePoint.set(new Vec(nx, ny, sz));
}
this._isPen.set(info.type === "pointer" && info.isPen);
if (info.name === "pointer_down" || isPinching) {
this._pointerVelocity.set(new Vec());
this._originScreenPoint.set(this._currentScreenPoint.__unsafe__getWithoutCapture());
this._originPagePoint.set(this._currentPagePoint.__unsafe__getWithoutCapture());
}
if (this._getHasCollaborators()) {
this.editor.run(
() => {
const pagePoint = this._currentPagePoint.__unsafe__getWithoutCapture();
this.editor.store.put([
{
id: TLPOINTER_ID,
typeName: "pointer",
x: pagePoint.x,
y: pagePoint.y,
lastActivityTimestamp: (
// If our pointer moved only because we're following some other user, then don't
// update our last activity timestamp; otherwise, update it to the current timestamp.
(info.type === "pointer" && info.pointerId === INTERNAL_POINTER_IDS.CAMERA_MOVE ? this.editor.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ?? Date.now() : Date.now())
),
meta: {}
}
]);
},
{ history: "ignore" }
);
}
}
toJson() {
return {
originPagePoint: this._originPagePoint.get().toJson(),
originScreenPoint: this._originScreenPoint.get().toJson(),
previousPagePoint: this._previousPagePoint.get().toJson(),
previousScreenPoint: this._previousScreenPoint.get().toJson(),
currentPagePoint: this._currentPagePoint.get().toJson(),
currentScreenPoint: this._currentScreenPoint.get().toJson(),
pointerVelocity: this._pointerVelocity.get().toJson(),
shiftKey: this._shiftKey.get(),
metaKey: this._metaKey.get(),
ctrlKey: this._ctrlKey.get(),
altKey: this._altKey.get(),
isPen: this._isPen.get(),
isDragging: this._isDragging.get(),
isPointing: this._isPointing.get(),
isPinching: this._isPinching.get(),
isEditing: this._isEditing.get(),
isPanning: this._isPanning.get(),
isSpacebarPanning: this._isSpacebarPanning.get(),
keys: Array.from(this.keys.keys()),
buttons: Array.from(this.buttons.keys())
};
}
}
__decorateClass([
computed
], InputsManager.prototype, "_getHasCollaborators", 1);
export {
InputsManager
};
//# sourceMappingURL=InputsManager.mjs.map