@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
|
@@ -4298,17 +4298,16 @@ class Editor extends import_eventemitter3.default {
|
|
|
4298
4298
|
let inMarginClosestToEdgeHit = null;
|
|
4299
4299
|
const searchMargin = Math.max(innerMargin, outerMargin, this.getHitTestMargin());
|
|
4300
4300
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
|
|
4301
|
-
const shapesToCheck =
|
|
4302
|
-
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
|
|
4303
|
-
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
|
|
4304
|
-
return false;
|
|
4305
|
-
const pageMask = this.getShapeMask(shape);
|
|
4306
|
-
if (pageMask && !(0, import_utils2.pointInPolygon)(point, pageMask)) return false;
|
|
4307
|
-
if (filter && !filter(shape)) return false;
|
|
4308
|
-
return true;
|
|
4309
|
-
});
|
|
4301
|
+
const shapesToCheck = opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted();
|
|
4310
4302
|
for (let i = shapesToCheck.length - 1; i >= 0; i--) {
|
|
4311
4303
|
const shape = shapesToCheck[i];
|
|
4304
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4305
|
+
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group")) {
|
|
4306
|
+
continue;
|
|
4307
|
+
}
|
|
4308
|
+
const pageMask = this.getShapeMask(shape);
|
|
4309
|
+
if (pageMask && !(0, import_utils2.pointInPolygon)(point, pageMask)) continue;
|
|
4310
|
+
if (filter && !filter(shape)) continue;
|
|
4312
4311
|
const geometry = this.getShapeGeometry(shape);
|
|
4313
4312
|
const isGroup = geometry instanceof import_Group2d.Group2d;
|
|
4314
4313
|
const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
|
|
@@ -4413,11 +4412,15 @@ class Editor extends import_eventemitter3.default {
|
|
|
4413
4412
|
getShapesAtPoint(point, opts = {}) {
|
|
4414
4413
|
const margin = opts.margin ?? 0;
|
|
4415
4414
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4415
|
+
const sorted = this.getCurrentPageShapesSorted();
|
|
4416
|
+
const result = [];
|
|
4417
|
+
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
4418
|
+
const shape = sorted[i];
|
|
4419
|
+
if (this.isShapeHidden(shape)) continue;
|
|
4420
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4421
|
+
if (this.isPointInShape(shape, point, opts)) result.push(shape);
|
|
4422
|
+
}
|
|
4423
|
+
return result;
|
|
4421
4424
|
}
|
|
4422
4425
|
/**
|
|
4423
4426
|
* Get shape IDs within the given bounds.
|
|
@@ -5713,6 +5716,9 @@ class Editor extends import_eventemitter3.default {
|
|
|
5713
5716
|
*/
|
|
5714
5717
|
alignShapes(shapes, operation) {
|
|
5715
5718
|
if (this.getIsReadonly()) return this;
|
|
5719
|
+
if (operation === "center") {
|
|
5720
|
+
return this.alignShapes(shapes, "center-horizontal").alignShapes(shapes, "center-vertical");
|
|
5721
|
+
}
|
|
5716
5722
|
const { clusters: shapeClustersToAlign, allBounds } = this.getShapeClusters(shapes, "align");
|
|
5717
5723
|
if (shapeClustersToAlign.length < 2) return this;
|
|
5718
5724
|
const commonBounds = import_Box.Box.Common(allBounds);
|
|
@@ -7858,7 +7864,8 @@ class Editor extends import_eventemitter3.default {
|
|
|
7858
7864
|
_prevCursor = "default";
|
|
7859
7865
|
/** @internal */
|
|
7860
7866
|
_shiftKeyTimeout = -1;
|
|
7861
|
-
|
|
7867
|
+
_releaseShiftKey() {
|
|
7868
|
+
this._shiftKeyTimeout = -1;
|
|
7862
7869
|
this.inputs.setShiftKey(false);
|
|
7863
7870
|
this.dispatch({
|
|
7864
7871
|
type: "keyboard",
|
|
@@ -7874,7 +7881,8 @@ class Editor extends import_eventemitter3.default {
|
|
|
7874
7881
|
}
|
|
7875
7882
|
/** @internal */
|
|
7876
7883
|
_altKeyTimeout = -1;
|
|
7877
|
-
|
|
7884
|
+
_releaseAltKey() {
|
|
7885
|
+
this._altKeyTimeout = -1;
|
|
7878
7886
|
this.inputs.setAltKey(false);
|
|
7879
7887
|
this.dispatch({
|
|
7880
7888
|
type: "keyboard",
|
|
@@ -7890,7 +7898,8 @@ class Editor extends import_eventemitter3.default {
|
|
|
7890
7898
|
}
|
|
7891
7899
|
/** @internal */
|
|
7892
7900
|
_ctrlKeyTimeout = -1;
|
|
7893
|
-
|
|
7901
|
+
_releaseCtrlKey() {
|
|
7902
|
+
this._ctrlKeyTimeout = -1;
|
|
7894
7903
|
this.inputs.setCtrlKey(false);
|
|
7895
7904
|
this.dispatch({
|
|
7896
7905
|
type: "keyboard",
|
|
@@ -7906,7 +7915,8 @@ class Editor extends import_eventemitter3.default {
|
|
|
7906
7915
|
}
|
|
7907
7916
|
/** @internal */
|
|
7908
7917
|
_metaKeyTimeout = -1;
|
|
7909
|
-
|
|
7918
|
+
_releaseMetaKey() {
|
|
7919
|
+
this._metaKeyTimeout = -1;
|
|
7910
7920
|
this.inputs.setMetaKey(false);
|
|
7911
7921
|
this.dispatch({
|
|
7912
7922
|
type: "keyboard",
|
|
@@ -7920,6 +7930,51 @@ class Editor extends import_eventemitter3.default {
|
|
|
7920
7930
|
code: "MetaLeft"
|
|
7921
7931
|
});
|
|
7922
7932
|
}
|
|
7933
|
+
/**
|
|
7934
|
+
* Flush any modifier still sitting in its 150ms release-debounce window, so a new
|
|
7935
|
+
* interaction (a pointer down) starts with correct modifier state instead of a
|
|
7936
|
+
* just-released key still being counted as held. A pending timer is exactly
|
|
7937
|
+
* "released but still counted as held"; a genuinely-held modifier has no timer
|
|
7938
|
+
* (-1) and is left alone.
|
|
7939
|
+
*
|
|
7940
|
+
* Each modifier is released through the same path its timer would have taken
|
|
7941
|
+
* (`_releaseShiftKey` and friends), which dispatches the synthetic `key_up` so
|
|
7942
|
+
* stale codes (e.g. `ShiftLeft`) leave `inputs.keys` and tool `onKeyUp` handlers run.
|
|
7943
|
+
* We clear every pending modifier atom and timer *first*, then dispatch: a synthetic
|
|
7944
|
+
* `key_up` reports all currently-held modifiers, so releasing them one at a time
|
|
7945
|
+
* would make each event re-confirm the not-yet-released ones and cancel their flush.
|
|
7946
|
+
* @internal
|
|
7947
|
+
*/
|
|
7948
|
+
_releaseDebouncedModifiers() {
|
|
7949
|
+
const releaseShift = this._shiftKeyTimeout !== -1;
|
|
7950
|
+
const releaseAlt = this._altKeyTimeout !== -1;
|
|
7951
|
+
const releaseCtrl = this._ctrlKeyTimeout !== -1;
|
|
7952
|
+
const releaseMeta = this._metaKeyTimeout !== -1;
|
|
7953
|
+
if (releaseShift) {
|
|
7954
|
+
clearTimeout(this._shiftKeyTimeout);
|
|
7955
|
+
this._shiftKeyTimeout = -1;
|
|
7956
|
+
this.inputs.setShiftKey(false);
|
|
7957
|
+
}
|
|
7958
|
+
if (releaseAlt) {
|
|
7959
|
+
clearTimeout(this._altKeyTimeout);
|
|
7960
|
+
this._altKeyTimeout = -1;
|
|
7961
|
+
this.inputs.setAltKey(false);
|
|
7962
|
+
}
|
|
7963
|
+
if (releaseCtrl) {
|
|
7964
|
+
clearTimeout(this._ctrlKeyTimeout);
|
|
7965
|
+
this._ctrlKeyTimeout = -1;
|
|
7966
|
+
this.inputs.setCtrlKey(false);
|
|
7967
|
+
}
|
|
7968
|
+
if (releaseMeta) {
|
|
7969
|
+
clearTimeout(this._metaKeyTimeout);
|
|
7970
|
+
this._metaKeyTimeout = -1;
|
|
7971
|
+
this.inputs.setMetaKey(false);
|
|
7972
|
+
}
|
|
7973
|
+
if (releaseShift) this._releaseShiftKey();
|
|
7974
|
+
if (releaseAlt) this._releaseAltKey();
|
|
7975
|
+
if (releaseCtrl) this._releaseCtrlKey();
|
|
7976
|
+
if (releaseMeta) this._releaseMetaKey();
|
|
7977
|
+
}
|
|
7923
7978
|
/** @internal */
|
|
7924
7979
|
_restoreToolId = "select";
|
|
7925
7980
|
/** @internal */
|
|
@@ -8029,28 +8084,28 @@ class Editor extends import_eventemitter3.default {
|
|
|
8029
8084
|
this._shiftKeyTimeout = -1;
|
|
8030
8085
|
inputs.setShiftKey(true);
|
|
8031
8086
|
} else if (!info.shiftKey && inputs.getShiftKey() && this._shiftKeyTimeout === -1) {
|
|
8032
|
-
this._shiftKeyTimeout = this.timers.setTimeout(this.
|
|
8087
|
+
this._shiftKeyTimeout = this.timers.setTimeout(this._releaseShiftKey, 150);
|
|
8033
8088
|
}
|
|
8034
8089
|
if (info.altKey) {
|
|
8035
8090
|
clearTimeout(this._altKeyTimeout);
|
|
8036
8091
|
this._altKeyTimeout = -1;
|
|
8037
8092
|
inputs.setAltKey(true);
|
|
8038
8093
|
} else if (!info.altKey && inputs.getAltKey() && this._altKeyTimeout === -1) {
|
|
8039
|
-
this._altKeyTimeout = this.timers.setTimeout(this.
|
|
8094
|
+
this._altKeyTimeout = this.timers.setTimeout(this._releaseAltKey, 150);
|
|
8040
8095
|
}
|
|
8041
8096
|
if (info.ctrlKey) {
|
|
8042
8097
|
clearTimeout(this._ctrlKeyTimeout);
|
|
8043
8098
|
this._ctrlKeyTimeout = -1;
|
|
8044
8099
|
inputs.setCtrlKey(true);
|
|
8045
8100
|
} else if (!info.ctrlKey && inputs.getCtrlKey() && this._ctrlKeyTimeout === -1) {
|
|
8046
|
-
this._ctrlKeyTimeout = this.timers.setTimeout(this.
|
|
8101
|
+
this._ctrlKeyTimeout = this.timers.setTimeout(this._releaseCtrlKey, 150);
|
|
8047
8102
|
}
|
|
8048
8103
|
if (info.metaKey && info.name !== "key_up") {
|
|
8049
8104
|
clearTimeout(this._metaKeyTimeout);
|
|
8050
8105
|
this._metaKeyTimeout = -1;
|
|
8051
8106
|
inputs.setMetaKey(true);
|
|
8052
8107
|
} else if (!info.metaKey && inputs.getMetaKey() && this._metaKeyTimeout === -1) {
|
|
8053
|
-
this._metaKeyTimeout = this.timers.setTimeout(this.
|
|
8108
|
+
this._metaKeyTimeout = this.timers.setTimeout(this._releaseMetaKey, 150);
|
|
8054
8109
|
}
|
|
8055
8110
|
if (!inputs.getIsPointing()) {
|
|
8056
8111
|
inputs.setIsDragging(false);
|
|
@@ -8195,6 +8250,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
8195
8250
|
switch (info.name) {
|
|
8196
8251
|
case "pointer_down": {
|
|
8197
8252
|
if (isPenMode && !isPen) return;
|
|
8253
|
+
this._releaseDebouncedModifiers();
|
|
8198
8254
|
if (!this.inputs.getIsPanning()) {
|
|
8199
8255
|
this._longPressTimeout = this.timers.setTimeout(() => {
|
|
8200
8256
|
const vsb = this.getViewportScreenBounds();
|
|
@@ -8677,16 +8733,16 @@ __decorateClass([
|
|
|
8677
8733
|
], Editor.prototype, "getIsReadonly", 1);
|
|
8678
8734
|
__decorateClass([
|
|
8679
8735
|
import_utils.bind
|
|
8680
|
-
], Editor.prototype, "
|
|
8736
|
+
], Editor.prototype, "_releaseShiftKey", 1);
|
|
8681
8737
|
__decorateClass([
|
|
8682
8738
|
import_utils.bind
|
|
8683
|
-
], Editor.prototype, "
|
|
8739
|
+
], Editor.prototype, "_releaseAltKey", 1);
|
|
8684
8740
|
__decorateClass([
|
|
8685
8741
|
import_utils.bind
|
|
8686
|
-
], Editor.prototype, "
|
|
8742
|
+
], Editor.prototype, "_releaseCtrlKey", 1);
|
|
8687
8743
|
__decorateClass([
|
|
8688
8744
|
import_utils.bind
|
|
8689
|
-
], Editor.prototype, "
|
|
8745
|
+
], Editor.prototype, "_releaseMetaKey", 1);
|
|
8690
8746
|
function alertMaxShapes(editor, pageId = editor.getCurrentPageId()) {
|
|
8691
8747
|
const name = editor.getPage(pageId).name;
|
|
8692
8748
|
editor.emit("max-shapes", { name, pageId, count: editor.options.maxShapesPerPage });
|