UNPKG

tldraw

Version:

A tiny little drawing editor.

250 lines (249 loc) • 8.95 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var DraggingHandle_exports = {}; __export(DraggingHandle_exports, { DraggingHandle: () => DraggingHandle }); module.exports = __toCommonJS(DraggingHandle_exports); var import_editor = require("@tldraw/editor"); var import_shared = require("../../../shapes/arrow/shared"); var import_selectHelpers = require("../selectHelpers"); class DraggingHandle extends import_editor.StateNode { static id = "dragging_handle"; shapeId = ""; initialHandle = {}; initialAdjacentHandle = null; initialPagePoint = {}; markId = ""; initialPageTransform; initialPageRotation; info = {}; isPrecise = false; isPreciseId = null; pointingId = null; onEnter(info) { const { shape, isCreating, creatingMarkId, handle } = info; this.info = info; this.parent.setCurrentToolIdMask(info.onInteractionEnd); this.shapeId = shape.id; this.markId = ""; if (isCreating) { if (creatingMarkId) { this.markId = creatingMarkId; } else { const markId = this.editor.getMarkIdMatching( `creating:${this.editor.getOnlySelectedShapeId()}` ); if (markId) { this.markId = markId; } } } else { this.markId = this.editor.markHistoryStoppingPoint("dragging handle"); } this.initialHandle = (0, import_editor.structuredClone)(handle); if (this.editor.isShapeOfType(shape, "line")) { if (this.initialHandle.type === "create") { this.editor.updateShape({ ...shape, props: { points: { ...shape.props.points, [handle.index]: { id: handle.index, index: handle.index, x: handle.x, y: handle.y } } } }); const handlesAfter = this.editor.getShapeHandles(shape); const handleAfter = handlesAfter.find((h) => h.index === handle.index); this.initialHandle = (0, import_editor.structuredClone)(handleAfter); } } this.initialPageTransform = this.editor.getShapePageTransform(shape); this.initialPageRotation = this.initialPageTransform.rotation(); this.initialPagePoint = this.editor.inputs.originPagePoint.clone(); this.editor.setCursor({ type: isCreating ? "cross" : "grabbing", rotation: 0 }); const handles = this.editor.getShapeHandles(shape).sort(import_editor.sortByIndex); const index = handles.findIndex((h) => h.id === info.handle.id); this.initialAdjacentHandle = null; for (let i = index + 1; i < handles.length; i++) { const handle2 = handles[i]; if (handle2.type === "vertex" && handle2.id !== "middle" && handle2.id !== info.handle.id) { this.initialAdjacentHandle = handle2; break; } } if (!this.initialAdjacentHandle) { for (let i = handles.length - 1; i >= 0; i--) { const handle2 = handles[i]; if (handle2.type === "vertex" && handle2.id !== "middle" && handle2.id !== info.handle.id) { this.initialAdjacentHandle = handle2; break; } } } if (this.editor.isShapeOfType(shape, "arrow")) { const initialBinding = (0, import_shared.getArrowBindings)(this.editor, shape)[info.handle.id]; this.isPrecise = false; if (initialBinding) { this.editor.setHintingShapes([initialBinding.toId]); this.isPrecise = initialBinding.props.isPrecise; if (this.isPrecise) { this.isPreciseId = initialBinding.toId; } else { this.resetExactTimeout(); } } else { this.editor.setHintingShapes([]); } } this.update(); this.editor.select(this.shapeId); } // Only relevant to arrows exactTimeout = -1; // Only relevant to arrows resetExactTimeout() { if (this.exactTimeout !== -1) { this.clearExactTimeout(); } this.exactTimeout = this.editor.timers.setTimeout(() => { if (this.getIsActive() && !this.isPrecise) { this.isPrecise = true; this.isPreciseId = this.pointingId; this.update(); } this.exactTimeout = -1; }, 750); } // Only relevant to arrows clearExactTimeout() { if (this.exactTimeout !== -1) { clearTimeout(this.exactTimeout); this.exactTimeout = -1; } } onPointerMove() { this.update(); } onKeyDown() { this.update(); } onKeyUp() { this.update(); } onPointerUp() { this.complete(); } onComplete() { this.update(); this.complete(); } onCancel() { this.cancel(); } onExit() { this.parent.setCurrentToolIdMask(void 0); this.editor.setHintingShapes([]); this.editor.snaps.clearIndicators(); this.editor.setCursor({ type: "default", rotation: 0 }); } complete() { this.editor.snaps.clearIndicators(); (0, import_selectHelpers.kickoutOccludedShapes)(this.editor, [this.shapeId]); const { onInteractionEnd } = this.info; if (this.editor.getInstanceState().isToolLocked && onInteractionEnd) { this.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId }); return; } this.parent.transition("idle"); } cancel() { this.editor.bailToMark(this.markId); this.editor.snaps.clearIndicators(); const { onInteractionEnd } = this.info; if (onInteractionEnd) { this.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId }); return; } this.parent.transition("idle"); } update() { const { editor, shapeId, initialPagePoint } = this; const { initialHandle, initialPageRotation, initialAdjacentHandle } = this; const hintingShapeIds = this.editor.getHintingShapeIds(); const isSnapMode = this.editor.user.getIsSnapMode(); const { snaps, inputs: { currentPagePoint, shiftKey, ctrlKey, altKey, pointerVelocity } } = editor; const initial = this.info.shape; const shape = editor.getShape(shapeId); if (!shape) return; const util = editor.getShapeUtil(shape); let point = currentPagePoint.clone().sub(initialPagePoint).rot(-initialPageRotation).add(initialHandle); if (shiftKey && initialAdjacentHandle && initialHandle.id !== "middle") { const angle = import_editor.Vec.Angle(initialAdjacentHandle, point); const snappedAngle = (0, import_editor.snapAngle)(angle, 24); const angleDifference = snappedAngle - angle; point = import_editor.Vec.RotWith(point, initialAdjacentHandle, angleDifference); } editor.snaps.clearIndicators(); let nextHandle = { ...initialHandle, x: point.x, y: point.y }; if (initialHandle.canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) { const pageTransform = editor.getShapePageTransform(shape.id); if (!pageTransform) throw Error("Expected a page transform"); const snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle }); if (snap) { snap.nudge.rot(-editor.getShapeParentTransform(shape).rotation()); point.add(snap.nudge); nextHandle = { ...initialHandle, x: point.x, y: point.y }; } } const changes = util.onHandleDrag?.(shape, { handle: nextHandle, isPrecise: this.isPrecise || altKey, initial }); const next = { id: shape.id, type: shape.type, ...changes }; if (initialHandle.type === "vertex" && this.editor.isShapeOfType(shape, "arrow")) { const bindingAfter = (0, import_shared.getArrowBindings)(editor, shape)[initialHandle.id]; if (bindingAfter) { if (hintingShapeIds[0] !== bindingAfter.toId) { editor.setHintingShapes([bindingAfter.toId]); this.pointingId = bindingAfter.toId; this.isPrecise = pointerVelocity.len() < 0.5 || altKey; this.isPreciseId = this.isPrecise ? bindingAfter.toId : null; this.resetExactTimeout(); } } else { if (hintingShapeIds.length > 0) { editor.setHintingShapes([]); this.pointingId = null; this.isPrecise = false; this.isPreciseId = null; this.resetExactTimeout(); } } } if (changes) { editor.updateShapes([next]); } } } //# sourceMappingURL=DraggingHandle.js.map