@tldraw/editor 5.3.0 → 5.4.0-canary.074b19f2c11f
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 +62 -52
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +82 -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 +5 -1
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- 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 +62 -52
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +82 -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 +5 -1
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- 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 +1 -0
- package/src/lib/editor/Editor.ts +120 -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 +8 -2
- 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
|
@@ -4331,17 +4331,16 @@ class Editor extends EventEmitter {
|
|
|
4331
4331
|
let inMarginClosestToEdgeHit = null;
|
|
4332
4332
|
const searchMargin = Math.max(innerMargin, outerMargin, this.getHitTestMargin());
|
|
4333
4333
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
|
|
4334
|
-
const shapesToCheck =
|
|
4335
|
-
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
|
|
4336
|
-
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
|
|
4337
|
-
return false;
|
|
4338
|
-
const pageMask = this.getShapeMask(shape);
|
|
4339
|
-
if (pageMask && !pointInPolygon(point, pageMask)) return false;
|
|
4340
|
-
if (filter && !filter(shape)) return false;
|
|
4341
|
-
return true;
|
|
4342
|
-
});
|
|
4334
|
+
const shapesToCheck = opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted();
|
|
4343
4335
|
for (let i = shapesToCheck.length - 1; i >= 0; i--) {
|
|
4344
4336
|
const shape = shapesToCheck[i];
|
|
4337
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4338
|
+
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group")) {
|
|
4339
|
+
continue;
|
|
4340
|
+
}
|
|
4341
|
+
const pageMask = this.getShapeMask(shape);
|
|
4342
|
+
if (pageMask && !pointInPolygon(point, pageMask)) continue;
|
|
4343
|
+
if (filter && !filter(shape)) continue;
|
|
4345
4344
|
const geometry = this.getShapeGeometry(shape);
|
|
4346
4345
|
const isGroup = geometry instanceof Group2d;
|
|
4347
4346
|
const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
|
|
@@ -4446,11 +4445,15 @@ class Editor extends EventEmitter {
|
|
|
4446
4445
|
getShapesAtPoint(point, opts = {}) {
|
|
4447
4446
|
const margin = opts.margin ?? 0;
|
|
4448
4447
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4448
|
+
const sorted = this.getCurrentPageShapesSorted();
|
|
4449
|
+
const result = [];
|
|
4450
|
+
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
4451
|
+
const shape = sorted[i];
|
|
4452
|
+
if (this.isShapeHidden(shape)) continue;
|
|
4453
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4454
|
+
if (this.isPointInShape(shape, point, opts)) result.push(shape);
|
|
4455
|
+
}
|
|
4456
|
+
return result;
|
|
4454
4457
|
}
|
|
4455
4458
|
/**
|
|
4456
4459
|
* Get shape IDs within the given bounds.
|
|
@@ -5746,6 +5749,9 @@ class Editor extends EventEmitter {
|
|
|
5746
5749
|
*/
|
|
5747
5750
|
alignShapes(shapes, operation) {
|
|
5748
5751
|
if (this.getIsReadonly()) return this;
|
|
5752
|
+
if (operation === "center") {
|
|
5753
|
+
return this.alignShapes(shapes, "center-horizontal").alignShapes(shapes, "center-vertical");
|
|
5754
|
+
}
|
|
5749
5755
|
const { clusters: shapeClustersToAlign, allBounds } = this.getShapeClusters(shapes, "align");
|
|
5750
5756
|
if (shapeClustersToAlign.length < 2) return this;
|
|
5751
5757
|
const commonBounds = Box.Common(allBounds);
|
|
@@ -7891,7 +7897,8 @@ class Editor extends EventEmitter {
|
|
|
7891
7897
|
_prevCursor = "default";
|
|
7892
7898
|
/** @internal */
|
|
7893
7899
|
_shiftKeyTimeout = -1;
|
|
7894
|
-
|
|
7900
|
+
_releaseShiftKey() {
|
|
7901
|
+
this._shiftKeyTimeout = -1;
|
|
7895
7902
|
this.inputs.setShiftKey(false);
|
|
7896
7903
|
this.dispatch({
|
|
7897
7904
|
type: "keyboard",
|
|
@@ -7907,7 +7914,8 @@ class Editor extends EventEmitter {
|
|
|
7907
7914
|
}
|
|
7908
7915
|
/** @internal */
|
|
7909
7916
|
_altKeyTimeout = -1;
|
|
7910
|
-
|
|
7917
|
+
_releaseAltKey() {
|
|
7918
|
+
this._altKeyTimeout = -1;
|
|
7911
7919
|
this.inputs.setAltKey(false);
|
|
7912
7920
|
this.dispatch({
|
|
7913
7921
|
type: "keyboard",
|
|
@@ -7923,7 +7931,8 @@ class Editor extends EventEmitter {
|
|
|
7923
7931
|
}
|
|
7924
7932
|
/** @internal */
|
|
7925
7933
|
_ctrlKeyTimeout = -1;
|
|
7926
|
-
|
|
7934
|
+
_releaseCtrlKey() {
|
|
7935
|
+
this._ctrlKeyTimeout = -1;
|
|
7927
7936
|
this.inputs.setCtrlKey(false);
|
|
7928
7937
|
this.dispatch({
|
|
7929
7938
|
type: "keyboard",
|
|
@@ -7939,7 +7948,8 @@ class Editor extends EventEmitter {
|
|
|
7939
7948
|
}
|
|
7940
7949
|
/** @internal */
|
|
7941
7950
|
_metaKeyTimeout = -1;
|
|
7942
|
-
|
|
7951
|
+
_releaseMetaKey() {
|
|
7952
|
+
this._metaKeyTimeout = -1;
|
|
7943
7953
|
this.inputs.setMetaKey(false);
|
|
7944
7954
|
this.dispatch({
|
|
7945
7955
|
type: "keyboard",
|
|
@@ -7953,6 +7963,51 @@ class Editor extends EventEmitter {
|
|
|
7953
7963
|
code: "MetaLeft"
|
|
7954
7964
|
});
|
|
7955
7965
|
}
|
|
7966
|
+
/**
|
|
7967
|
+
* Flush any modifier still sitting in its 150ms release-debounce window, so a new
|
|
7968
|
+
* interaction (a pointer down) starts with correct modifier state instead of a
|
|
7969
|
+
* just-released key still being counted as held. A pending timer is exactly
|
|
7970
|
+
* "released but still counted as held"; a genuinely-held modifier has no timer
|
|
7971
|
+
* (-1) and is left alone.
|
|
7972
|
+
*
|
|
7973
|
+
* Each modifier is released through the same path its timer would have taken
|
|
7974
|
+
* (`_releaseShiftKey` and friends), which dispatches the synthetic `key_up` so
|
|
7975
|
+
* stale codes (e.g. `ShiftLeft`) leave `inputs.keys` and tool `onKeyUp` handlers run.
|
|
7976
|
+
* We clear every pending modifier atom and timer *first*, then dispatch: a synthetic
|
|
7977
|
+
* `key_up` reports all currently-held modifiers, so releasing them one at a time
|
|
7978
|
+
* would make each event re-confirm the not-yet-released ones and cancel their flush.
|
|
7979
|
+
* @internal
|
|
7980
|
+
*/
|
|
7981
|
+
_releaseDebouncedModifiers() {
|
|
7982
|
+
const releaseShift = this._shiftKeyTimeout !== -1;
|
|
7983
|
+
const releaseAlt = this._altKeyTimeout !== -1;
|
|
7984
|
+
const releaseCtrl = this._ctrlKeyTimeout !== -1;
|
|
7985
|
+
const releaseMeta = this._metaKeyTimeout !== -1;
|
|
7986
|
+
if (releaseShift) {
|
|
7987
|
+
clearTimeout(this._shiftKeyTimeout);
|
|
7988
|
+
this._shiftKeyTimeout = -1;
|
|
7989
|
+
this.inputs.setShiftKey(false);
|
|
7990
|
+
}
|
|
7991
|
+
if (releaseAlt) {
|
|
7992
|
+
clearTimeout(this._altKeyTimeout);
|
|
7993
|
+
this._altKeyTimeout = -1;
|
|
7994
|
+
this.inputs.setAltKey(false);
|
|
7995
|
+
}
|
|
7996
|
+
if (releaseCtrl) {
|
|
7997
|
+
clearTimeout(this._ctrlKeyTimeout);
|
|
7998
|
+
this._ctrlKeyTimeout = -1;
|
|
7999
|
+
this.inputs.setCtrlKey(false);
|
|
8000
|
+
}
|
|
8001
|
+
if (releaseMeta) {
|
|
8002
|
+
clearTimeout(this._metaKeyTimeout);
|
|
8003
|
+
this._metaKeyTimeout = -1;
|
|
8004
|
+
this.inputs.setMetaKey(false);
|
|
8005
|
+
}
|
|
8006
|
+
if (releaseShift) this._releaseShiftKey();
|
|
8007
|
+
if (releaseAlt) this._releaseAltKey();
|
|
8008
|
+
if (releaseCtrl) this._releaseCtrlKey();
|
|
8009
|
+
if (releaseMeta) this._releaseMetaKey();
|
|
8010
|
+
}
|
|
7956
8011
|
/** @internal */
|
|
7957
8012
|
_restoreToolId = "select";
|
|
7958
8013
|
/** @internal */
|
|
@@ -8062,28 +8117,28 @@ class Editor extends EventEmitter {
|
|
|
8062
8117
|
this._shiftKeyTimeout = -1;
|
|
8063
8118
|
inputs.setShiftKey(true);
|
|
8064
8119
|
} else if (!info.shiftKey && inputs.getShiftKey() && this._shiftKeyTimeout === -1) {
|
|
8065
|
-
this._shiftKeyTimeout = this.timers.setTimeout(this.
|
|
8120
|
+
this._shiftKeyTimeout = this.timers.setTimeout(this._releaseShiftKey, 150);
|
|
8066
8121
|
}
|
|
8067
8122
|
if (info.altKey) {
|
|
8068
8123
|
clearTimeout(this._altKeyTimeout);
|
|
8069
8124
|
this._altKeyTimeout = -1;
|
|
8070
8125
|
inputs.setAltKey(true);
|
|
8071
8126
|
} else if (!info.altKey && inputs.getAltKey() && this._altKeyTimeout === -1) {
|
|
8072
|
-
this._altKeyTimeout = this.timers.setTimeout(this.
|
|
8127
|
+
this._altKeyTimeout = this.timers.setTimeout(this._releaseAltKey, 150);
|
|
8073
8128
|
}
|
|
8074
8129
|
if (info.ctrlKey) {
|
|
8075
8130
|
clearTimeout(this._ctrlKeyTimeout);
|
|
8076
8131
|
this._ctrlKeyTimeout = -1;
|
|
8077
8132
|
inputs.setCtrlKey(true);
|
|
8078
8133
|
} else if (!info.ctrlKey && inputs.getCtrlKey() && this._ctrlKeyTimeout === -1) {
|
|
8079
|
-
this._ctrlKeyTimeout = this.timers.setTimeout(this.
|
|
8134
|
+
this._ctrlKeyTimeout = this.timers.setTimeout(this._releaseCtrlKey, 150);
|
|
8080
8135
|
}
|
|
8081
8136
|
if (info.metaKey && info.name !== "key_up") {
|
|
8082
8137
|
clearTimeout(this._metaKeyTimeout);
|
|
8083
8138
|
this._metaKeyTimeout = -1;
|
|
8084
8139
|
inputs.setMetaKey(true);
|
|
8085
8140
|
} else if (!info.metaKey && inputs.getMetaKey() && this._metaKeyTimeout === -1) {
|
|
8086
|
-
this._metaKeyTimeout = this.timers.setTimeout(this.
|
|
8141
|
+
this._metaKeyTimeout = this.timers.setTimeout(this._releaseMetaKey, 150);
|
|
8087
8142
|
}
|
|
8088
8143
|
if (!inputs.getIsPointing()) {
|
|
8089
8144
|
inputs.setIsDragging(false);
|
|
@@ -8228,6 +8283,7 @@ class Editor extends EventEmitter {
|
|
|
8228
8283
|
switch (info.name) {
|
|
8229
8284
|
case "pointer_down": {
|
|
8230
8285
|
if (isPenMode && !isPen) return;
|
|
8286
|
+
this._releaseDebouncedModifiers();
|
|
8231
8287
|
if (!this.inputs.getIsPanning()) {
|
|
8232
8288
|
this._longPressTimeout = this.timers.setTimeout(() => {
|
|
8233
8289
|
const vsb = this.getViewportScreenBounds();
|
|
@@ -8710,16 +8766,16 @@ __decorateClass([
|
|
|
8710
8766
|
], Editor.prototype, "getIsReadonly", 1);
|
|
8711
8767
|
__decorateClass([
|
|
8712
8768
|
bind
|
|
8713
|
-
], Editor.prototype, "
|
|
8769
|
+
], Editor.prototype, "_releaseShiftKey", 1);
|
|
8714
8770
|
__decorateClass([
|
|
8715
8771
|
bind
|
|
8716
|
-
], Editor.prototype, "
|
|
8772
|
+
], Editor.prototype, "_releaseAltKey", 1);
|
|
8717
8773
|
__decorateClass([
|
|
8718
8774
|
bind
|
|
8719
|
-
], Editor.prototype, "
|
|
8775
|
+
], Editor.prototype, "_releaseCtrlKey", 1);
|
|
8720
8776
|
__decorateClass([
|
|
8721
8777
|
bind
|
|
8722
|
-
], Editor.prototype, "
|
|
8778
|
+
], Editor.prototype, "_releaseMetaKey", 1);
|
|
8723
8779
|
function alertMaxShapes(editor, pageId = editor.getCurrentPageId()) {
|
|
8724
8780
|
const name = editor.getPage(pageId).name;
|
|
8725
8781
|
editor.emit("max-shapes", { name, pageId, count: editor.options.maxShapesPerPage });
|