tldraw
Version:
A tiny little drawing editor.
198 lines (197 loc) • 7.96 kB
JavaScript
"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 EditingShape_exports = {};
__export(EditingShape_exports, {
EditingShape: () => EditingShape
});
module.exports = __toCommonJS(EditingShape_exports);
var import_editor = require("@tldraw/editor");
var import_shapes = require("../../../utils/shapes/shapes");
var import_richText = require("../../../utils/text/richText");
var import_getHitShapeOnCanvasPointerDown = require("../../selection-logic/getHitShapeOnCanvasPointerDown");
var import_updateHoveredShapeId = require("../../selection-logic/updateHoveredShapeId");
class EditingShape extends import_editor.StateNode {
static id = "editing_shape";
hitLabelOnShapeForPointerUp = null;
info = {};
didPointerDownOnEditingShape = false;
isTextInputFocused() {
const container = this.editor.getContainer();
return container.contains(document.activeElement) && (0, import_editor.activeElementShouldCaptureKeys)(false);
}
onEnter(info) {
const editingShape = this.editor.getEditingShape();
if (!editingShape) throw Error("Entered editing state without an editing shape");
this.hitLabelOnShapeForPointerUp = null;
this.didPointerDownOnEditingShape = false;
this.info = info;
if (info.isCreatingTextWhileToolLocked) {
this.parent.setCurrentToolIdMask("text");
}
(0, import_updateHoveredShapeId.updateHoveredShapeId)(this.editor);
this.editor.select(editingShape);
}
onExit() {
const hadEditingShape = !!this.editor.getEditingShapeId();
this.editor.setEditingShape(null);
import_updateHoveredShapeId.updateHoveredShapeId.cancel();
if (this.info.isCreatingTextWhileToolLocked && hadEditingShape) {
this.parent.setCurrentToolIdMask(void 0);
this.editor.setCurrentTool("text", {});
}
}
onPointerMove(info) {
if (this.hitLabelOnShapeForPointerUp && this.editor.inputs.getIsDragging()) {
if (this.editor.getIsReadonly()) return;
if (this.hitLabelOnShapeForPointerUp.isLocked) return;
this.editor.select(this.hitLabelOnShapeForPointerUp);
this.parent.transition("translating", info);
this.hitLabelOnShapeForPointerUp = null;
return;
}
if (this.didPointerDownOnEditingShape && this.editor.inputs.isDragging) {
if (this.editor.getIsReadonly()) return;
const editingShape = this.editor.getEditingShape();
if (!editingShape || editingShape.isLocked) return;
if (!this.isTextInputFocused()) {
this.editor.select(editingShape);
this.parent.transition("translating", info);
this.didPointerDownOnEditingShape = false;
return;
}
this.didPointerDownOnEditingShape = false;
}
switch (info.target) {
case "shape":
case "canvas": {
(0, import_updateHoveredShapeId.updateHoveredShapeId)(this.editor);
return;
}
}
}
onPointerDown(info) {
this.hitLabelOnShapeForPointerUp = null;
this.didPointerDownOnEditingShape = false;
switch (info.target) {
// N.B. This bit of logic has a bit of history to it.
// There was a PR that got rid of this logic: https://github.com/tldraw/tldraw/pull/4237
// But here we bring it back to help support the new rich text world.
// The original issue which is visible in the video attachments in the PR now seem
// to have been resolved anyway via some other layer.
case "canvas": {
const hitShape = (0, import_getHitShapeOnCanvasPointerDown.getHitShapeOnCanvasPointerDown)(
this.editor,
true
/* hitLabels */
);
if (hitShape) {
this.onPointerDown({
...info,
shape: hitShape,
target: "shape"
});
return;
}
break;
}
case "shape": {
const { shape: selectingShape } = info;
const editingShape = this.editor.getEditingShape();
if (!editingShape) {
throw Error("Expected an editing shape!");
}
const geometry = this.editor.getShapeUtil(selectingShape).getGeometry(selectingShape);
const textLabels = (0, import_shapes.getTextLabels)(geometry);
const textLabel = textLabels.length === 1 ? textLabels[0] : void 0;
const isEmptyTextShape = this.editor.isShapeOfType(editingShape, "text") && (0, import_richText.renderPlaintextFromRichText)(this.editor, editingShape.props.richText).trim() === "";
if (textLabel && !isEmptyTextShape) {
const pointInShapeSpace = this.editor.getPointInShapeSpace(
selectingShape,
this.editor.inputs.getCurrentPagePoint()
);
if (textLabel.bounds.containsPoint(pointInShapeSpace, 0) && textLabel.hitTestPoint(pointInShapeSpace)) {
if (selectingShape.id === editingShape.id) {
this.didPointerDownOnEditingShape = true;
return;
} else {
this.hitLabelOnShapeForPointerUp = selectingShape;
this.editor.markHistoryStoppingPoint("editing on pointer up");
this.editor.select(selectingShape.id);
return;
}
}
} else {
if (selectingShape.id === editingShape.id) {
if (this.editor.isShapeOfType(selectingShape, "frame")) {
this.editor.setEditingShape(null);
this.parent.transition("idle", info);
}
} else {
this.parent.transition("pointing_shape", info);
return;
}
return;
}
break;
}
}
this.parent.transition("idle", info);
this.editor.root.handleEvent(info);
}
onPointerUp(info) {
if (this.didPointerDownOnEditingShape) {
this.didPointerDownOnEditingShape = false;
if (!this.isTextInputFocused()) {
this.editor.getRichTextEditor()?.commands.focus("all");
return;
}
}
const hitShape = this.hitLabelOnShapeForPointerUp;
if (!hitShape) return;
this.hitLabelOnShapeForPointerUp = null;
const util = this.editor.getShapeUtil(hitShape);
if (hitShape.isLocked) return;
if (this.editor.getIsReadonly()) {
if (!util.canEditInReadonly(hitShape)) {
this.parent.transition("pointing_shape", info);
return;
}
}
this.editor.select(hitShape.id);
const currentEditingShape = this.editor.getEditingShape();
const isEditToEditAction = currentEditingShape && currentEditingShape.id !== hitShape.id;
this.editor.setEditingShape(hitShape.id);
const isMobile = import_editor.tlenv.isIos || import_editor.tlenv.isAndroid;
if (!isMobile || !isEditToEditAction) {
this.editor.emit("place-caret", { shapeId: hitShape.id, point: info.point });
} else if (isMobile && isEditToEditAction) {
this.editor.emit("select-all-text", { shapeId: hitShape.id });
}
(0, import_updateHoveredShapeId.updateHoveredShapeId)(this.editor);
}
onComplete(info) {
this.editor.getContainer().focus();
this.parent.transition("idle", info);
}
onCancel(info) {
this.editor.getContainer().focus();
this.parent.transition("idle", info);
}
}
//# sourceMappingURL=EditingShape.js.map