@tldraw/editor 5.3.2 → 5.4.0-canary.042da660fa66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +94 -52
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +86 -26
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +7 -3
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +6 -3
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +6 -3
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/globals/editors.js +57 -0
- package/dist-cjs/lib/globals/editors.js.map +7 -0
- package/dist-cjs/lib/hooks/useViewportHeight.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +63 -21
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/utils/normalizeWheel.js +2 -0
- package/dist-cjs/lib/utils/normalizeWheel.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +94 -52
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +86 -26
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +7 -3
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +7 -4
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +6 -3
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/globals/editors.mjs +37 -0
- package/dist-esm/lib/globals/editors.mjs.map +7 -0
- package/dist-esm/lib/hooks/useViewportHeight.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +63 -21
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/utils/normalizeWheel.mjs +2 -0
- package/dist-esm/lib/utils/normalizeWheel.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +2 -0
- package/src/lib/editor/Editor.ts +126 -37
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +7 -3
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +42 -0
- package/src/lib/editor/managers/TextManager/TextManager.ts +10 -8
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +13 -0
- package/src/lib/editor/managers/TickManager/TickManager.ts +9 -3
- package/src/lib/globals/editors.test.ts +76 -0
- package/src/lib/globals/editors.ts +53 -0
- package/src/lib/hooks/useViewportHeight.ts +9 -1
- package/src/lib/primitives/geometry/Group2d.ts +63 -27
- package/src/lib/utils/normalizeWheel.test.ts +39 -0
- package/src/lib/utils/normalizeWheel.ts +6 -0
- package/src/version.ts +3 -3
|
@@ -83,6 +83,7 @@ import {
|
|
|
83
83
|
import { getOwnerWindow } from "../exports/domUtils.mjs";
|
|
84
84
|
import { exportToSvg } from "../exports/exportToSvg.mjs";
|
|
85
85
|
import { getSvgAsImageWithOptions, trimSvgToContent } from "../exports/getSvgAsImage.mjs";
|
|
86
|
+
import { registerMountedEditor, unregisterMountedEditor } from "../globals/editors.mjs";
|
|
86
87
|
import { tlmenus } from "../globals/menus.mjs";
|
|
87
88
|
import { tltime } from "../globals/time.mjs";
|
|
88
89
|
import { defaultTldrawOptions } from "../options.mjs";
|
|
@@ -604,9 +605,11 @@ class Editor extends EventEmitter {
|
|
|
604
605
|
this.on("tick", this._flushEventsForTick);
|
|
605
606
|
this.on("mount", () => {
|
|
606
607
|
this._isMounted.set(true);
|
|
608
|
+
registerMountedEditor(this);
|
|
607
609
|
});
|
|
608
610
|
this.on("unmount", () => {
|
|
609
611
|
this._isMounted.set(false);
|
|
612
|
+
unregisterMountedEditor(this);
|
|
610
613
|
});
|
|
611
614
|
this.timers.requestAnimationFrame(() => {
|
|
612
615
|
this._tickManager.start();
|
|
@@ -848,6 +851,7 @@ class Editor extends EventEmitter {
|
|
|
848
851
|
if (this._isMounted.get()) {
|
|
849
852
|
this.emit("unmount");
|
|
850
853
|
}
|
|
854
|
+
unregisterMountedEditor(this);
|
|
851
855
|
this.stopCameraAnimation();
|
|
852
856
|
if (this.getInstanceState().followingUserId) {
|
|
853
857
|
this.stopFollowingUser();
|
|
@@ -4339,17 +4343,16 @@ class Editor extends EventEmitter {
|
|
|
4339
4343
|
let inMarginClosestToEdgeHit = null;
|
|
4340
4344
|
const searchMargin = Math.max(innerMargin, outerMargin, this.getHitTestMargin());
|
|
4341
4345
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
|
|
4342
|
-
const shapesToCheck =
|
|
4343
|
-
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
|
|
4344
|
-
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
|
|
4345
|
-
return false;
|
|
4346
|
-
const pageMask = this.getShapeMask(shape);
|
|
4347
|
-
if (pageMask && !pointInPolygon(point, pageMask)) return false;
|
|
4348
|
-
if (filter && !filter(shape)) return false;
|
|
4349
|
-
return true;
|
|
4350
|
-
});
|
|
4346
|
+
const shapesToCheck = opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted();
|
|
4351
4347
|
for (let i = shapesToCheck.length - 1; i >= 0; i--) {
|
|
4352
4348
|
const shape = shapesToCheck[i];
|
|
4349
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4350
|
+
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group")) {
|
|
4351
|
+
continue;
|
|
4352
|
+
}
|
|
4353
|
+
const pageMask = this.getShapeMask(shape);
|
|
4354
|
+
if (pageMask && !pointInPolygon(point, pageMask)) continue;
|
|
4355
|
+
if (filter && !filter(shape)) continue;
|
|
4353
4356
|
const geometry = this.getShapeGeometry(shape);
|
|
4354
4357
|
const isGroup = geometry instanceof Group2d;
|
|
4355
4358
|
const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
|
|
@@ -4454,11 +4457,15 @@ class Editor extends EventEmitter {
|
|
|
4454
4457
|
getShapesAtPoint(point, opts = {}) {
|
|
4455
4458
|
const margin = opts.margin ?? 0;
|
|
4456
4459
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4460
|
+
const sorted = this.getCurrentPageShapesSorted();
|
|
4461
|
+
const result = [];
|
|
4462
|
+
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
4463
|
+
const shape = sorted[i];
|
|
4464
|
+
if (this.isShapeHidden(shape)) continue;
|
|
4465
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4466
|
+
if (this.isPointInShape(shape, point, opts)) result.push(shape);
|
|
4467
|
+
}
|
|
4468
|
+
return result;
|
|
4462
4469
|
}
|
|
4463
4470
|
/**
|
|
4464
4471
|
* Get shape IDs within the given bounds.
|
|
@@ -5754,6 +5761,9 @@ class Editor extends EventEmitter {
|
|
|
5754
5761
|
*/
|
|
5755
5762
|
alignShapes(shapes, operation) {
|
|
5756
5763
|
if (this.getIsReadonly()) return this;
|
|
5764
|
+
if (operation === "center") {
|
|
5765
|
+
return this.alignShapes(shapes, "center-horizontal").alignShapes(shapes, "center-vertical");
|
|
5766
|
+
}
|
|
5757
5767
|
const { clusters: shapeClustersToAlign, allBounds } = this.getShapeClusters(shapes, "align");
|
|
5758
5768
|
if (shapeClustersToAlign.length < 2) return this;
|
|
5759
5769
|
const commonBounds = Box.Common(allBounds);
|
|
@@ -7899,7 +7909,8 @@ class Editor extends EventEmitter {
|
|
|
7899
7909
|
_prevCursor = "default";
|
|
7900
7910
|
/** @internal */
|
|
7901
7911
|
_shiftKeyTimeout = -1;
|
|
7902
|
-
|
|
7912
|
+
_releaseShiftKey() {
|
|
7913
|
+
this._shiftKeyTimeout = -1;
|
|
7903
7914
|
this.inputs.setShiftKey(false);
|
|
7904
7915
|
this.dispatch({
|
|
7905
7916
|
type: "keyboard",
|
|
@@ -7915,7 +7926,8 @@ class Editor extends EventEmitter {
|
|
|
7915
7926
|
}
|
|
7916
7927
|
/** @internal */
|
|
7917
7928
|
_altKeyTimeout = -1;
|
|
7918
|
-
|
|
7929
|
+
_releaseAltKey() {
|
|
7930
|
+
this._altKeyTimeout = -1;
|
|
7919
7931
|
this.inputs.setAltKey(false);
|
|
7920
7932
|
this.dispatch({
|
|
7921
7933
|
type: "keyboard",
|
|
@@ -7931,7 +7943,8 @@ class Editor extends EventEmitter {
|
|
|
7931
7943
|
}
|
|
7932
7944
|
/** @internal */
|
|
7933
7945
|
_ctrlKeyTimeout = -1;
|
|
7934
|
-
|
|
7946
|
+
_releaseCtrlKey() {
|
|
7947
|
+
this._ctrlKeyTimeout = -1;
|
|
7935
7948
|
this.inputs.setCtrlKey(false);
|
|
7936
7949
|
this.dispatch({
|
|
7937
7950
|
type: "keyboard",
|
|
@@ -7947,7 +7960,8 @@ class Editor extends EventEmitter {
|
|
|
7947
7960
|
}
|
|
7948
7961
|
/** @internal */
|
|
7949
7962
|
_metaKeyTimeout = -1;
|
|
7950
|
-
|
|
7963
|
+
_releaseMetaKey() {
|
|
7964
|
+
this._metaKeyTimeout = -1;
|
|
7951
7965
|
this.inputs.setMetaKey(false);
|
|
7952
7966
|
this.dispatch({
|
|
7953
7967
|
type: "keyboard",
|
|
@@ -7961,6 +7975,51 @@ class Editor extends EventEmitter {
|
|
|
7961
7975
|
code: "MetaLeft"
|
|
7962
7976
|
});
|
|
7963
7977
|
}
|
|
7978
|
+
/**
|
|
7979
|
+
* Flush any modifier still sitting in its 150ms release-debounce window, so a new
|
|
7980
|
+
* interaction (a pointer down) starts with correct modifier state instead of a
|
|
7981
|
+
* just-released key still being counted as held. A pending timer is exactly
|
|
7982
|
+
* "released but still counted as held"; a genuinely-held modifier has no timer
|
|
7983
|
+
* (-1) and is left alone.
|
|
7984
|
+
*
|
|
7985
|
+
* Each modifier is released through the same path its timer would have taken
|
|
7986
|
+
* (`_releaseShiftKey` and friends), which dispatches the synthetic `key_up` so
|
|
7987
|
+
* stale codes (e.g. `ShiftLeft`) leave `inputs.keys` and tool `onKeyUp` handlers run.
|
|
7988
|
+
* We clear every pending modifier atom and timer *first*, then dispatch: a synthetic
|
|
7989
|
+
* `key_up` reports all currently-held modifiers, so releasing them one at a time
|
|
7990
|
+
* would make each event re-confirm the not-yet-released ones and cancel their flush.
|
|
7991
|
+
* @internal
|
|
7992
|
+
*/
|
|
7993
|
+
_releaseDebouncedModifiers() {
|
|
7994
|
+
const releaseShift = this._shiftKeyTimeout !== -1;
|
|
7995
|
+
const releaseAlt = this._altKeyTimeout !== -1;
|
|
7996
|
+
const releaseCtrl = this._ctrlKeyTimeout !== -1;
|
|
7997
|
+
const releaseMeta = this._metaKeyTimeout !== -1;
|
|
7998
|
+
if (releaseShift) {
|
|
7999
|
+
clearTimeout(this._shiftKeyTimeout);
|
|
8000
|
+
this._shiftKeyTimeout = -1;
|
|
8001
|
+
this.inputs.setShiftKey(false);
|
|
8002
|
+
}
|
|
8003
|
+
if (releaseAlt) {
|
|
8004
|
+
clearTimeout(this._altKeyTimeout);
|
|
8005
|
+
this._altKeyTimeout = -1;
|
|
8006
|
+
this.inputs.setAltKey(false);
|
|
8007
|
+
}
|
|
8008
|
+
if (releaseCtrl) {
|
|
8009
|
+
clearTimeout(this._ctrlKeyTimeout);
|
|
8010
|
+
this._ctrlKeyTimeout = -1;
|
|
8011
|
+
this.inputs.setCtrlKey(false);
|
|
8012
|
+
}
|
|
8013
|
+
if (releaseMeta) {
|
|
8014
|
+
clearTimeout(this._metaKeyTimeout);
|
|
8015
|
+
this._metaKeyTimeout = -1;
|
|
8016
|
+
this.inputs.setMetaKey(false);
|
|
8017
|
+
}
|
|
8018
|
+
if (releaseShift) this._releaseShiftKey();
|
|
8019
|
+
if (releaseAlt) this._releaseAltKey();
|
|
8020
|
+
if (releaseCtrl) this._releaseCtrlKey();
|
|
8021
|
+
if (releaseMeta) this._releaseMetaKey();
|
|
8022
|
+
}
|
|
7964
8023
|
/** @internal */
|
|
7965
8024
|
_restoreToolId = "select";
|
|
7966
8025
|
/** @internal */
|
|
@@ -8070,28 +8129,28 @@ class Editor extends EventEmitter {
|
|
|
8070
8129
|
this._shiftKeyTimeout = -1;
|
|
8071
8130
|
inputs.setShiftKey(true);
|
|
8072
8131
|
} else if (!info.shiftKey && inputs.getShiftKey() && this._shiftKeyTimeout === -1) {
|
|
8073
|
-
this._shiftKeyTimeout = this.timers.setTimeout(this.
|
|
8132
|
+
this._shiftKeyTimeout = this.timers.setTimeout(this._releaseShiftKey, 150);
|
|
8074
8133
|
}
|
|
8075
8134
|
if (info.altKey) {
|
|
8076
8135
|
clearTimeout(this._altKeyTimeout);
|
|
8077
8136
|
this._altKeyTimeout = -1;
|
|
8078
8137
|
inputs.setAltKey(true);
|
|
8079
8138
|
} else if (!info.altKey && inputs.getAltKey() && this._altKeyTimeout === -1) {
|
|
8080
|
-
this._altKeyTimeout = this.timers.setTimeout(this.
|
|
8139
|
+
this._altKeyTimeout = this.timers.setTimeout(this._releaseAltKey, 150);
|
|
8081
8140
|
}
|
|
8082
8141
|
if (info.ctrlKey) {
|
|
8083
8142
|
clearTimeout(this._ctrlKeyTimeout);
|
|
8084
8143
|
this._ctrlKeyTimeout = -1;
|
|
8085
8144
|
inputs.setCtrlKey(true);
|
|
8086
8145
|
} else if (!info.ctrlKey && inputs.getCtrlKey() && this._ctrlKeyTimeout === -1) {
|
|
8087
|
-
this._ctrlKeyTimeout = this.timers.setTimeout(this.
|
|
8146
|
+
this._ctrlKeyTimeout = this.timers.setTimeout(this._releaseCtrlKey, 150);
|
|
8088
8147
|
}
|
|
8089
8148
|
if (info.metaKey && info.name !== "key_up") {
|
|
8090
8149
|
clearTimeout(this._metaKeyTimeout);
|
|
8091
8150
|
this._metaKeyTimeout = -1;
|
|
8092
8151
|
inputs.setMetaKey(true);
|
|
8093
8152
|
} else if (!info.metaKey && inputs.getMetaKey() && this._metaKeyTimeout === -1) {
|
|
8094
|
-
this._metaKeyTimeout = this.timers.setTimeout(this.
|
|
8153
|
+
this._metaKeyTimeout = this.timers.setTimeout(this._releaseMetaKey, 150);
|
|
8095
8154
|
}
|
|
8096
8155
|
if (!inputs.getIsPointing()) {
|
|
8097
8156
|
inputs.setIsDragging(false);
|
|
@@ -8236,6 +8295,7 @@ class Editor extends EventEmitter {
|
|
|
8236
8295
|
switch (info.name) {
|
|
8237
8296
|
case "pointer_down": {
|
|
8238
8297
|
if (isPenMode && !isPen) return;
|
|
8298
|
+
this._releaseDebouncedModifiers();
|
|
8239
8299
|
if (!this.inputs.getIsPanning()) {
|
|
8240
8300
|
this._longPressTimeout = this.timers.setTimeout(() => {
|
|
8241
8301
|
const vsb = this.getViewportScreenBounds();
|
|
@@ -8718,16 +8778,16 @@ __decorateClass([
|
|
|
8718
8778
|
], Editor.prototype, "getIsReadonly", 1);
|
|
8719
8779
|
__decorateClass([
|
|
8720
8780
|
bind
|
|
8721
|
-
], Editor.prototype, "
|
|
8781
|
+
], Editor.prototype, "_releaseShiftKey", 1);
|
|
8722
8782
|
__decorateClass([
|
|
8723
8783
|
bind
|
|
8724
|
-
], Editor.prototype, "
|
|
8784
|
+
], Editor.prototype, "_releaseAltKey", 1);
|
|
8725
8785
|
__decorateClass([
|
|
8726
8786
|
bind
|
|
8727
|
-
], Editor.prototype, "
|
|
8787
|
+
], Editor.prototype, "_releaseCtrlKey", 1);
|
|
8728
8788
|
__decorateClass([
|
|
8729
8789
|
bind
|
|
8730
|
-
], Editor.prototype, "
|
|
8790
|
+
], Editor.prototype, "_releaseMetaKey", 1);
|
|
8731
8791
|
function alertMaxShapes(editor, pageId = editor.getCurrentPageId()) {
|
|
8732
8792
|
const name = editor.getPage(pageId).name;
|
|
8733
8793
|
editor.emit("max-shapes", { name, pageId, count: editor.options.maxShapesPerPage });
|