kritzel-stencil 0.2.3 → 0.2.4
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.cjs.js +1 -1
- package/dist/cjs/kritzel-active-users_42.cjs.entry.js +55 -7
- package/dist/cjs/{workspace.migrations-CYeB_XRB.js → workspace.migrations-B89-6fP-.js} +34 -8
- package/dist/collection/classes/core/core.class.js +9 -2
- package/dist/collection/classes/handlers/line-handle.handler.js +1 -0
- package/dist/collection/classes/handlers/move.handler.js +2 -0
- package/dist/collection/classes/handlers/resize.handler.js +2 -0
- package/dist/collection/classes/handlers/rotation.handler.js +2 -0
- package/dist/collection/classes/structures/object-map.structure.js +44 -3
- package/dist/collection/classes/tools/brush-tool.class.js +2 -0
- package/dist/collection/classes/tools/eraser-tool.class.js +22 -8
- package/dist/collection/classes/tools/line-tool.class.js +2 -0
- package/dist/collection/classes/tools/shape-tool.class.js +1 -0
- package/dist/collection/constants/version.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/{p-yX5Zk5pS.js → p-3YivOJM2.js} +1 -1
- package/dist/components/p-B2dVTxsc.js +9 -0
- package/dist/components/{p-CdaOQi45.js → p-BabNumqA.js} +1 -1
- package/dist/components/{p-BeeKeeeo.js → p-DMYfjC1C.js} +1 -1
- package/dist/components/p-Dqpa31TI.js +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-active-users_42.entry.js +55 -7
- package/dist/esm/{workspace.migrations-BrA5xRPn.js → workspace.migrations-D_y5zlxK.js} +34 -8
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-74898384.entry.js +9 -0
- package/dist/stencil/{p-BrA5xRPn.js → p-D_y5zlxK.js} +1 -1
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/structures/object-map.structure.d.ts +19 -0
- package/dist/types/constants/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/components/p-Bs7lEBy5.js +0 -9
- package/dist/components/p-C1UNiqO2.js +0 -1
- package/dist/stencil/p-56b81681.entry.js +0 -9
package/dist/cjs/index.cjs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var index = require('./index-CFnj_FXt.js');
|
|
4
|
-
var workspace_migrations = require('./workspace.migrations-
|
|
4
|
+
var workspace_migrations = require('./workspace.migrations-B89-6fP-.js');
|
|
5
5
|
var Y = require('yjs');
|
|
6
6
|
require('y-indexeddb');
|
|
7
7
|
require('y-websocket');
|
|
@@ -21445,6 +21445,12 @@ class KritzelObjectMap {
|
|
|
21445
21445
|
* redundant full serializations of every child object per frame.
|
|
21446
21446
|
*/
|
|
21447
21447
|
_localOnlyMode = false;
|
|
21448
|
+
/**
|
|
21449
|
+
* Tracks whether we're currently executing inside a `transaction()`
|
|
21450
|
+
* callback. While true, `markUndoBoundary()` is a no-op so nested
|
|
21451
|
+
* insert/remove calls don't split the in-progress undo step.
|
|
21452
|
+
*/
|
|
21453
|
+
_inTransaction = false;
|
|
21448
21454
|
/**
|
|
21449
21455
|
* Indicates whether the object map has been initialized and is ready for use.
|
|
21450
21456
|
* @returns `true` if providers are connected and the map is operational
|
|
@@ -21683,9 +21689,12 @@ class KritzelObjectMap {
|
|
|
21683
21689
|
}
|
|
21684
21690
|
this._providers.push(provider);
|
|
21685
21691
|
}
|
|
21686
|
-
//
|
|
21692
|
+
// captureTimeout is effectively infinite — undo-step boundaries are
|
|
21693
|
+
// marked explicitly via markUndoBoundary() in insert/remove/reset and
|
|
21694
|
+
// at stroke/gesture boundaries in the tools. This prevents a single
|
|
21695
|
+
// brush stroke from being split when the user pauses after pointerdown.
|
|
21687
21696
|
this._undoManager = new Y__namespace.UndoManager([this._objectsMap], {
|
|
21688
|
-
captureTimeout:
|
|
21697
|
+
captureTimeout: Number.MAX_SAFE_INTEGER,
|
|
21689
21698
|
trackedOrigins: new Set(['local', 'temporary']),
|
|
21690
21699
|
ignoreRemoteMapChanges: true,
|
|
21691
21700
|
});
|
|
@@ -22003,8 +22012,34 @@ class KritzelObjectMap {
|
|
|
22003
22012
|
*/
|
|
22004
22013
|
transaction(callback) {
|
|
22005
22014
|
if (this._ydoc) {
|
|
22006
|
-
this.
|
|
22015
|
+
this._inTransaction = true;
|
|
22016
|
+
try {
|
|
22017
|
+
this._ydoc.transact(callback, 'local');
|
|
22018
|
+
}
|
|
22019
|
+
finally {
|
|
22020
|
+
this._inTransaction = false;
|
|
22021
|
+
}
|
|
22022
|
+
}
|
|
22023
|
+
}
|
|
22024
|
+
/**
|
|
22025
|
+
* Closes the current undo stack item so the next tracked change starts
|
|
22026
|
+
* a new one. Call at gesture/stroke boundaries (e.g. drag/resize/rotate
|
|
22027
|
+
* end, brush/line/shape stroke end).
|
|
22028
|
+
*
|
|
22029
|
+
* No-op while a transaction() is open.
|
|
22030
|
+
*/
|
|
22031
|
+
stopUndoCapturing() {
|
|
22032
|
+
this.markUndoBoundary();
|
|
22033
|
+
}
|
|
22034
|
+
/**
|
|
22035
|
+
* Internal: closes the current undo stack item. No-op while inside a
|
|
22036
|
+
* transaction() so wrapped multi-op work stays a single undo step.
|
|
22037
|
+
*/
|
|
22038
|
+
markUndoBoundary() {
|
|
22039
|
+
if (this._inTransaction) {
|
|
22040
|
+
return;
|
|
22007
22041
|
}
|
|
22042
|
+
this._undoManager?.stopCapturing();
|
|
22008
22043
|
}
|
|
22009
22044
|
/**
|
|
22010
22045
|
* Executes a callback where all update() calls only modify local state
|
|
@@ -22069,6 +22104,7 @@ class KritzelObjectMap {
|
|
|
22069
22104
|
reset() {
|
|
22070
22105
|
this.quadtree.reset();
|
|
22071
22106
|
this._idMap.clear();
|
|
22107
|
+
this.markUndoBoundary();
|
|
22072
22108
|
this._ydoc?.transact(() => {
|
|
22073
22109
|
this._objectsMap?.clear();
|
|
22074
22110
|
}, 'local');
|
|
@@ -22089,6 +22125,7 @@ class KritzelObjectMap {
|
|
|
22089
22125
|
this._idMap.set(object.id, object);
|
|
22090
22126
|
if (this._objectsMap && this.isPersistable(object)) {
|
|
22091
22127
|
const serialized = object.serialize();
|
|
22128
|
+
this.markUndoBoundary();
|
|
22092
22129
|
this._ydoc?.transact(() => {
|
|
22093
22130
|
this._objectsMap?.set(object.id, serialized);
|
|
22094
22131
|
}, 'local');
|
|
@@ -22133,6 +22170,10 @@ class KritzelObjectMap {
|
|
|
22133
22170
|
*/
|
|
22134
22171
|
remove(predicate) {
|
|
22135
22172
|
const objectsToRemove = this.quadtree.filter(predicate);
|
|
22173
|
+
if (objectsToRemove.length === 0) {
|
|
22174
|
+
return;
|
|
22175
|
+
}
|
|
22176
|
+
this.markUndoBoundary();
|
|
22136
22177
|
for (const object of objectsToRemove) {
|
|
22137
22178
|
this.quadtree.remove(o => o.id === object.id);
|
|
22138
22179
|
this._idMap.delete(object.id);
|
|
@@ -23823,8 +23864,15 @@ class KritzelCore {
|
|
|
23823
23864
|
if (!selectionGroup) {
|
|
23824
23865
|
return;
|
|
23825
23866
|
}
|
|
23826
|
-
|
|
23827
|
-
|
|
23867
|
+
// Seal the selection group's creation into its own undo step so Yjs
|
|
23868
|
+
// doesn't collapse create+delete of the SG into a no-op on undo.
|
|
23869
|
+
this._store.objects.stopUndoCapturing();
|
|
23870
|
+
this._store.objects.transaction(() => {
|
|
23871
|
+
selectionGroup.objects.forEach(obj => this.removeObject(obj));
|
|
23872
|
+
this.removeSelectionGroup();
|
|
23873
|
+
});
|
|
23874
|
+
// Close the deletion step so subsequent unrelated changes start a new step.
|
|
23875
|
+
this._store.objects.stopUndoCapturing();
|
|
23828
23876
|
this.engine.emitObjectsInViewportChange();
|
|
23829
23877
|
this.rerender();
|
|
23830
23878
|
}
|
|
@@ -29041,7 +29089,7 @@ const KritzelPortal = class {
|
|
|
29041
29089
|
* This file is auto-generated by the version bump scripts.
|
|
29042
29090
|
* Do not modify manually.
|
|
29043
29091
|
*/
|
|
29044
|
-
const KRITZEL_VERSION = '0.2.
|
|
29092
|
+
const KRITZEL_VERSION = '0.2.4';
|
|
29045
29093
|
|
|
29046
29094
|
const kritzelSettingsCss = () => `:host{display:contents}kritzel-dialog{--kritzel-dialog-body-padding:0;--kritzel-dialog-width-large:800px;--kritzel-dialog-height-large:500px}.footer-button{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:14px}.cancel-button{border:1px solid #ebebeb;background:#fff;color:inherit}.cancel-button:hover{background:#f5f5f5}.settings-content{padding:0}.settings-content h3{margin:0 0 16px 0;font-size:18px;font-weight:600;color:var(--kritzel-settings-content-heading-color, #333333)}.settings-content p{margin:0;font-size:14px;color:var(--kritzel-settings-content-text-color, #666666);line-height:1.5}.settings-group{display:flex;flex-direction:column;gap:24px}.settings-item{display:flex;flex-direction:column;gap:8px}.settings-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.settings-label{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.settings-description{font-size:12px;color:var(--kritzel-settings-description-color, #888888);margin:0;line-height:1.4}.shortcuts-list{display:flex;flex-direction:column;gap:24px}.shortcuts-category{display:flex;flex-direction:column;gap:8px}.shortcuts-category-title{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.shortcuts-group{display:flex;flex-direction:column;gap:4px}.shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-item-bg, rgba(0, 0, 0, 0.02))}.shortcut-label{font-size:14px;color:var(--kritzel-settings-content-text-color, #666666)}.shortcut-key{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-key-bg, #f0f0f0);color:var(--kritzel-settings-shortcut-key-color, #333333);border:1px solid var(--kritzel-settings-shortcut-key-border, #ddd)}`;
|
|
29047
29095
|
|
|
@@ -19679,6 +19679,7 @@ class KritzelBrushTool extends KritzelBaseTool {
|
|
|
19679
19679
|
}
|
|
19680
19680
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
19681
19681
|
this._currentPathId = null;
|
|
19682
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
19682
19683
|
}
|
|
19683
19684
|
}
|
|
19684
19685
|
}
|
|
@@ -19695,6 +19696,7 @@ class KritzelBrushTool extends KritzelBaseTool {
|
|
|
19695
19696
|
}
|
|
19696
19697
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
19697
19698
|
this._currentPathId = null;
|
|
19699
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
19698
19700
|
}
|
|
19699
19701
|
}
|
|
19700
19702
|
}
|
|
@@ -20526,6 +20528,7 @@ class KritzelLineTool extends KritzelBaseTool {
|
|
|
20526
20528
|
}
|
|
20527
20529
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
20528
20530
|
this._currentLineId = null;
|
|
20531
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
20529
20532
|
}
|
|
20530
20533
|
}
|
|
20531
20534
|
}
|
|
@@ -20544,6 +20547,7 @@ class KritzelLineTool extends KritzelBaseTool {
|
|
|
20544
20547
|
}
|
|
20545
20548
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
20546
20549
|
this._currentLineId = null;
|
|
20550
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
20547
20551
|
}
|
|
20548
20552
|
}
|
|
20549
20553
|
}
|
|
@@ -20650,17 +20654,24 @@ class KritzelEraserTool extends KritzelBaseTool {
|
|
|
20650
20654
|
if (event.pointerType === 'mouse') {
|
|
20651
20655
|
if (this._core.store.state.isErasing) {
|
|
20652
20656
|
const objectsToRemove = this._core.store.allObjects.filter(object => object.markedForRemoval);
|
|
20653
|
-
objectsToRemove.forEach(object => {
|
|
20654
|
-
object.markedForRemoval = false;
|
|
20655
|
-
this._core.removeObject(object);
|
|
20656
|
-
});
|
|
20657
20657
|
if (objectsToRemove.length > 0) {
|
|
20658
|
+
// Seal the previous undo step so create+delete of the same object
|
|
20659
|
+
// (e.g. just-drawn shape) don't collapse into a no-op on undo.
|
|
20660
|
+
this._core.store.objects.stopUndoCapturing();
|
|
20661
|
+
// Group all removals from this sweep into a single undo step.
|
|
20662
|
+
this._core.store.objects.transaction(() => {
|
|
20663
|
+
objectsToRemove.forEach(object => {
|
|
20664
|
+
object.markedForRemoval = false;
|
|
20665
|
+
this._core.removeObject(object);
|
|
20666
|
+
});
|
|
20667
|
+
});
|
|
20658
20668
|
this._core.rerender();
|
|
20659
20669
|
}
|
|
20660
20670
|
this._core.store.state.isErasing = false;
|
|
20661
20671
|
this._core.engine.emitObjectsChange();
|
|
20662
20672
|
if (objectsToRemove.length > 0) {
|
|
20663
20673
|
this._core.engine.emitObjectsRemoved(objectsToRemove);
|
|
20674
|
+
this._core.store.objects.stopUndoCapturing();
|
|
20664
20675
|
}
|
|
20665
20676
|
}
|
|
20666
20677
|
}
|
|
@@ -20668,17 +20679,24 @@ class KritzelEraserTool extends KritzelBaseTool {
|
|
|
20668
20679
|
clearTimeout(this.touchStartTimeout);
|
|
20669
20680
|
if (this._core.store.state.isErasing) {
|
|
20670
20681
|
const objectsToRemove = this._core.store.allObjects.filter(object => object.markedForRemoval);
|
|
20671
|
-
objectsToRemove.forEach(object => {
|
|
20672
|
-
object.markedForRemoval = false;
|
|
20673
|
-
this._core.removeObject(object);
|
|
20674
|
-
});
|
|
20675
20682
|
if (objectsToRemove.length > 0) {
|
|
20683
|
+
// Seal the previous undo step so create+delete of the same object
|
|
20684
|
+
// (e.g. just-drawn shape) don't collapse into a no-op on undo.
|
|
20685
|
+
this._core.store.objects.stopUndoCapturing();
|
|
20686
|
+
// Group all removals from this sweep into a single undo step.
|
|
20687
|
+
this._core.store.objects.transaction(() => {
|
|
20688
|
+
objectsToRemove.forEach(object => {
|
|
20689
|
+
object.markedForRemoval = false;
|
|
20690
|
+
this._core.removeObject(object);
|
|
20691
|
+
});
|
|
20692
|
+
});
|
|
20676
20693
|
this._core.rerender();
|
|
20677
20694
|
}
|
|
20678
20695
|
this._core.store.state.isErasing = false;
|
|
20679
20696
|
this._core.engine.emitObjectsChange();
|
|
20680
20697
|
if (objectsToRemove.length > 0) {
|
|
20681
20698
|
this._core.engine.emitObjectsRemoved(objectsToRemove);
|
|
20699
|
+
this._core.store.objects.stopUndoCapturing();
|
|
20682
20700
|
}
|
|
20683
20701
|
}
|
|
20684
20702
|
}
|
|
@@ -21283,6 +21301,7 @@ class KritzelShapeTool extends KritzelBaseTool {
|
|
|
21283
21301
|
this.isDrawing = false;
|
|
21284
21302
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
21285
21303
|
this.currentShape = null;
|
|
21304
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
21286
21305
|
this._core.rerender();
|
|
21287
21306
|
}
|
|
21288
21307
|
}
|
|
@@ -21692,6 +21711,7 @@ class KritzelMoveHandler extends KritzelBaseHandler {
|
|
|
21692
21711
|
this._core.store.selectionGroup.update();
|
|
21693
21712
|
this._core.engine.emitObjectsChange();
|
|
21694
21713
|
this._core.store.state.hasObjectsChanged = true;
|
|
21714
|
+
this._core.store.objects.stopUndoCapturing();
|
|
21695
21715
|
}
|
|
21696
21716
|
}
|
|
21697
21717
|
}
|
|
@@ -21703,6 +21723,7 @@ class KritzelMoveHandler extends KritzelBaseHandler {
|
|
|
21703
21723
|
this._core.store.selectionGroup.update();
|
|
21704
21724
|
this._core.engine.emitObjectsChange();
|
|
21705
21725
|
this._core.store.state.hasObjectsChanged = true;
|
|
21726
|
+
this._core.store.objects.stopUndoCapturing();
|
|
21706
21727
|
}
|
|
21707
21728
|
}
|
|
21708
21729
|
}
|
|
@@ -22055,6 +22076,7 @@ class KritzelResizeHandler extends KritzelBaseHandler {
|
|
|
22055
22076
|
this._core.store.selectionGroup.update();
|
|
22056
22077
|
this._core.engine.emitObjectsChange();
|
|
22057
22078
|
this._core.store.state.hasObjectsChanged = true;
|
|
22079
|
+
this._core.store.objects.stopUndoCapturing();
|
|
22058
22080
|
}
|
|
22059
22081
|
this.reset();
|
|
22060
22082
|
}
|
|
@@ -22066,6 +22088,7 @@ class KritzelResizeHandler extends KritzelBaseHandler {
|
|
|
22066
22088
|
this._core.store.selectionGroup.update();
|
|
22067
22089
|
this._core.engine.emitObjectsChange();
|
|
22068
22090
|
this._core.store.state.hasObjectsChanged = true;
|
|
22091
|
+
this._core.store.objects.stopUndoCapturing();
|
|
22069
22092
|
}
|
|
22070
22093
|
this.reset();
|
|
22071
22094
|
const timeout = this._core.store.state.longTouchTimeout;
|
|
@@ -22217,6 +22240,7 @@ class KritzelRotationHandler extends KritzelBaseHandler {
|
|
|
22217
22240
|
this._core.engine.emitObjectsChange();
|
|
22218
22241
|
this._core.store.state.isRotating = false;
|
|
22219
22242
|
this._core.store.state.hasObjectsChanged = true;
|
|
22243
|
+
this._core.store.objects.stopUndoCapturing();
|
|
22220
22244
|
this.reset();
|
|
22221
22245
|
}
|
|
22222
22246
|
}
|
|
@@ -22226,6 +22250,7 @@ class KritzelRotationHandler extends KritzelBaseHandler {
|
|
|
22226
22250
|
this._core.engine.emitObjectsChange();
|
|
22227
22251
|
this._core.store.state.isRotating = false;
|
|
22228
22252
|
this._core.store.state.hasObjectsChanged = true;
|
|
22253
|
+
this._core.store.objects.stopUndoCapturing();
|
|
22229
22254
|
this.reset();
|
|
22230
22255
|
const timeout = this._core.store.state.longTouchTimeout;
|
|
22231
22256
|
if (timeout) {
|
|
@@ -23243,6 +23268,7 @@ class KritzelLineHandleHandler extends KritzelBaseHandler {
|
|
|
23243
23268
|
this._core.engine.emitObjectsChange();
|
|
23244
23269
|
this._core.store.state.hasObjectsChanged = true;
|
|
23245
23270
|
}
|
|
23271
|
+
this._core.store.objects.stopUndoCapturing();
|
|
23246
23272
|
}
|
|
23247
23273
|
this._core.store.state.isLineHandleDragging = false;
|
|
23248
23274
|
this.reset();
|
|
@@ -587,8 +587,15 @@ export class KritzelCore {
|
|
|
587
587
|
if (!selectionGroup) {
|
|
588
588
|
return;
|
|
589
589
|
}
|
|
590
|
-
|
|
591
|
-
|
|
590
|
+
// Seal the selection group's creation into its own undo step so Yjs
|
|
591
|
+
// doesn't collapse create+delete of the SG into a no-op on undo.
|
|
592
|
+
this._store.objects.stopUndoCapturing();
|
|
593
|
+
this._store.objects.transaction(() => {
|
|
594
|
+
selectionGroup.objects.forEach(obj => this.removeObject(obj));
|
|
595
|
+
this.removeSelectionGroup();
|
|
596
|
+
});
|
|
597
|
+
// Close the deletion step so subsequent unrelated changes start a new step.
|
|
598
|
+
this._store.objects.stopUndoCapturing();
|
|
592
599
|
this.engine.emitObjectsInViewportChange();
|
|
593
600
|
this.rerender();
|
|
594
601
|
}
|
|
@@ -439,6 +439,7 @@ export class KritzelLineHandleHandler extends KritzelBaseHandler {
|
|
|
439
439
|
this._core.engine.emitObjectsChange();
|
|
440
440
|
this._core.store.state.hasObjectsChanged = true;
|
|
441
441
|
}
|
|
442
|
+
this._core.store.objects.stopUndoCapturing();
|
|
442
443
|
}
|
|
443
444
|
this._core.store.state.isLineHandleDragging = false;
|
|
444
445
|
this.reset();
|
|
@@ -214,6 +214,7 @@ export class KritzelMoveHandler extends KritzelBaseHandler {
|
|
|
214
214
|
this._core.store.selectionGroup.update();
|
|
215
215
|
this._core.engine.emitObjectsChange();
|
|
216
216
|
this._core.store.state.hasObjectsChanged = true;
|
|
217
|
+
this._core.store.objects.stopUndoCapturing();
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
220
|
}
|
|
@@ -225,6 +226,7 @@ export class KritzelMoveHandler extends KritzelBaseHandler {
|
|
|
225
226
|
this._core.store.selectionGroup.update();
|
|
226
227
|
this._core.engine.emitObjectsChange();
|
|
227
228
|
this._core.store.state.hasObjectsChanged = true;
|
|
229
|
+
this._core.store.objects.stopUndoCapturing();
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
}
|
|
@@ -280,6 +280,7 @@ export class KritzelResizeHandler extends KritzelBaseHandler {
|
|
|
280
280
|
this._core.store.selectionGroup.update();
|
|
281
281
|
this._core.engine.emitObjectsChange();
|
|
282
282
|
this._core.store.state.hasObjectsChanged = true;
|
|
283
|
+
this._core.store.objects.stopUndoCapturing();
|
|
283
284
|
}
|
|
284
285
|
this.reset();
|
|
285
286
|
}
|
|
@@ -291,6 +292,7 @@ export class KritzelResizeHandler extends KritzelBaseHandler {
|
|
|
291
292
|
this._core.store.selectionGroup.update();
|
|
292
293
|
this._core.engine.emitObjectsChange();
|
|
293
294
|
this._core.store.state.hasObjectsChanged = true;
|
|
295
|
+
this._core.store.objects.stopUndoCapturing();
|
|
294
296
|
}
|
|
295
297
|
this.reset();
|
|
296
298
|
const timeout = this._core.store.state.longTouchTimeout;
|
|
@@ -140,6 +140,7 @@ export class KritzelRotationHandler extends KritzelBaseHandler {
|
|
|
140
140
|
this._core.engine.emitObjectsChange();
|
|
141
141
|
this._core.store.state.isRotating = false;
|
|
142
142
|
this._core.store.state.hasObjectsChanged = true;
|
|
143
|
+
this._core.store.objects.stopUndoCapturing();
|
|
143
144
|
this.reset();
|
|
144
145
|
}
|
|
145
146
|
}
|
|
@@ -149,6 +150,7 @@ export class KritzelRotationHandler extends KritzelBaseHandler {
|
|
|
149
150
|
this._core.engine.emitObjectsChange();
|
|
150
151
|
this._core.store.state.isRotating = false;
|
|
151
152
|
this._core.store.state.hasObjectsChanged = true;
|
|
153
|
+
this._core.store.objects.stopUndoCapturing();
|
|
152
154
|
this.reset();
|
|
153
155
|
const timeout = this._core.store.state.longTouchTimeout;
|
|
154
156
|
if (timeout) {
|
|
@@ -44,6 +44,12 @@ export class KritzelObjectMap {
|
|
|
44
44
|
* redundant full serializations of every child object per frame.
|
|
45
45
|
*/
|
|
46
46
|
_localOnlyMode = false;
|
|
47
|
+
/**
|
|
48
|
+
* Tracks whether we're currently executing inside a `transaction()`
|
|
49
|
+
* callback. While true, `markUndoBoundary()` is a no-op so nested
|
|
50
|
+
* insert/remove calls don't split the in-progress undo step.
|
|
51
|
+
*/
|
|
52
|
+
_inTransaction = false;
|
|
47
53
|
/**
|
|
48
54
|
* Indicates whether the object map has been initialized and is ready for use.
|
|
49
55
|
* @returns `true` if providers are connected and the map is operational
|
|
@@ -282,9 +288,12 @@ export class KritzelObjectMap {
|
|
|
282
288
|
}
|
|
283
289
|
this._providers.push(provider);
|
|
284
290
|
}
|
|
285
|
-
//
|
|
291
|
+
// captureTimeout is effectively infinite — undo-step boundaries are
|
|
292
|
+
// marked explicitly via markUndoBoundary() in insert/remove/reset and
|
|
293
|
+
// at stroke/gesture boundaries in the tools. This prevents a single
|
|
294
|
+
// brush stroke from being split when the user pauses after pointerdown.
|
|
286
295
|
this._undoManager = new Y.UndoManager([this._objectsMap], {
|
|
287
|
-
captureTimeout:
|
|
296
|
+
captureTimeout: Number.MAX_SAFE_INTEGER,
|
|
288
297
|
trackedOrigins: new Set(['local', 'temporary']),
|
|
289
298
|
ignoreRemoteMapChanges: true,
|
|
290
299
|
});
|
|
@@ -602,9 +611,35 @@ export class KritzelObjectMap {
|
|
|
602
611
|
*/
|
|
603
612
|
transaction(callback) {
|
|
604
613
|
if (this._ydoc) {
|
|
605
|
-
this.
|
|
614
|
+
this._inTransaction = true;
|
|
615
|
+
try {
|
|
616
|
+
this._ydoc.transact(callback, 'local');
|
|
617
|
+
}
|
|
618
|
+
finally {
|
|
619
|
+
this._inTransaction = false;
|
|
620
|
+
}
|
|
606
621
|
}
|
|
607
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Closes the current undo stack item so the next tracked change starts
|
|
625
|
+
* a new one. Call at gesture/stroke boundaries (e.g. drag/resize/rotate
|
|
626
|
+
* end, brush/line/shape stroke end).
|
|
627
|
+
*
|
|
628
|
+
* No-op while a transaction() is open.
|
|
629
|
+
*/
|
|
630
|
+
stopUndoCapturing() {
|
|
631
|
+
this.markUndoBoundary();
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Internal: closes the current undo stack item. No-op while inside a
|
|
635
|
+
* transaction() so wrapped multi-op work stays a single undo step.
|
|
636
|
+
*/
|
|
637
|
+
markUndoBoundary() {
|
|
638
|
+
if (this._inTransaction) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
this._undoManager?.stopCapturing();
|
|
642
|
+
}
|
|
608
643
|
/**
|
|
609
644
|
* Executes a callback where all update() calls only modify local state
|
|
610
645
|
* (quadtree + idMap) without writing to Yjs. This avoids expensive full
|
|
@@ -668,6 +703,7 @@ export class KritzelObjectMap {
|
|
|
668
703
|
reset() {
|
|
669
704
|
this.quadtree.reset();
|
|
670
705
|
this._idMap.clear();
|
|
706
|
+
this.markUndoBoundary();
|
|
671
707
|
this._ydoc?.transact(() => {
|
|
672
708
|
this._objectsMap?.clear();
|
|
673
709
|
}, 'local');
|
|
@@ -688,6 +724,7 @@ export class KritzelObjectMap {
|
|
|
688
724
|
this._idMap.set(object.id, object);
|
|
689
725
|
if (this._objectsMap && this.isPersistable(object)) {
|
|
690
726
|
const serialized = object.serialize();
|
|
727
|
+
this.markUndoBoundary();
|
|
691
728
|
this._ydoc?.transact(() => {
|
|
692
729
|
this._objectsMap?.set(object.id, serialized);
|
|
693
730
|
}, 'local');
|
|
@@ -732,6 +769,10 @@ export class KritzelObjectMap {
|
|
|
732
769
|
*/
|
|
733
770
|
remove(predicate) {
|
|
734
771
|
const objectsToRemove = this.quadtree.filter(predicate);
|
|
772
|
+
if (objectsToRemove.length === 0) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
this.markUndoBoundary();
|
|
735
776
|
for (const object of objectsToRemove) {
|
|
736
777
|
this.quadtree.remove(o => o.id === object.id);
|
|
737
778
|
this._idMap.delete(object.id);
|
|
@@ -172,6 +172,7 @@ export class KritzelBrushTool extends KritzelBaseTool {
|
|
|
172
172
|
}
|
|
173
173
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
174
174
|
this._currentPathId = null;
|
|
175
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
}
|
|
@@ -188,6 +189,7 @@ export class KritzelBrushTool extends KritzelBaseTool {
|
|
|
188
189
|
}
|
|
189
190
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
190
191
|
this._currentPathId = null;
|
|
192
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
}
|
|
@@ -82,17 +82,24 @@ export class KritzelEraserTool extends KritzelBaseTool {
|
|
|
82
82
|
if (event.pointerType === 'mouse') {
|
|
83
83
|
if (this._core.store.state.isErasing) {
|
|
84
84
|
const objectsToRemove = this._core.store.allObjects.filter(object => object.markedForRemoval);
|
|
85
|
-
objectsToRemove.forEach(object => {
|
|
86
|
-
object.markedForRemoval = false;
|
|
87
|
-
this._core.removeObject(object);
|
|
88
|
-
});
|
|
89
85
|
if (objectsToRemove.length > 0) {
|
|
86
|
+
// Seal the previous undo step so create+delete of the same object
|
|
87
|
+
// (e.g. just-drawn shape) don't collapse into a no-op on undo.
|
|
88
|
+
this._core.store.objects.stopUndoCapturing();
|
|
89
|
+
// Group all removals from this sweep into a single undo step.
|
|
90
|
+
this._core.store.objects.transaction(() => {
|
|
91
|
+
objectsToRemove.forEach(object => {
|
|
92
|
+
object.markedForRemoval = false;
|
|
93
|
+
this._core.removeObject(object);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
90
96
|
this._core.rerender();
|
|
91
97
|
}
|
|
92
98
|
this._core.store.state.isErasing = false;
|
|
93
99
|
this._core.engine.emitObjectsChange();
|
|
94
100
|
if (objectsToRemove.length > 0) {
|
|
95
101
|
this._core.engine.emitObjectsRemoved(objectsToRemove);
|
|
102
|
+
this._core.store.objects.stopUndoCapturing();
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
105
|
}
|
|
@@ -100,17 +107,24 @@ export class KritzelEraserTool extends KritzelBaseTool {
|
|
|
100
107
|
clearTimeout(this.touchStartTimeout);
|
|
101
108
|
if (this._core.store.state.isErasing) {
|
|
102
109
|
const objectsToRemove = this._core.store.allObjects.filter(object => object.markedForRemoval);
|
|
103
|
-
objectsToRemove.forEach(object => {
|
|
104
|
-
object.markedForRemoval = false;
|
|
105
|
-
this._core.removeObject(object);
|
|
106
|
-
});
|
|
107
110
|
if (objectsToRemove.length > 0) {
|
|
111
|
+
// Seal the previous undo step so create+delete of the same object
|
|
112
|
+
// (e.g. just-drawn shape) don't collapse into a no-op on undo.
|
|
113
|
+
this._core.store.objects.stopUndoCapturing();
|
|
114
|
+
// Group all removals from this sweep into a single undo step.
|
|
115
|
+
this._core.store.objects.transaction(() => {
|
|
116
|
+
objectsToRemove.forEach(object => {
|
|
117
|
+
object.markedForRemoval = false;
|
|
118
|
+
this._core.removeObject(object);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
108
121
|
this._core.rerender();
|
|
109
122
|
}
|
|
110
123
|
this._core.store.state.isErasing = false;
|
|
111
124
|
this._core.engine.emitObjectsChange();
|
|
112
125
|
if (objectsToRemove.length > 0) {
|
|
113
126
|
this._core.engine.emitObjectsRemoved(objectsToRemove);
|
|
127
|
+
this._core.store.objects.stopUndoCapturing();
|
|
114
128
|
}
|
|
115
129
|
}
|
|
116
130
|
}
|
|
@@ -201,6 +201,7 @@ export class KritzelLineTool extends KritzelBaseTool {
|
|
|
201
201
|
}
|
|
202
202
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
203
203
|
this._currentLineId = null;
|
|
204
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
}
|
|
@@ -219,6 +220,7 @@ export class KritzelLineTool extends KritzelBaseTool {
|
|
|
219
220
|
}
|
|
220
221
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
221
222
|
this._currentLineId = null;
|
|
223
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
226
|
}
|
|
@@ -242,6 +242,7 @@ export class KritzelShapeTool extends KritzelBaseTool {
|
|
|
242
242
|
this.isDrawing = false;
|
|
243
243
|
this._core.store.objects?.setActiveDrawingObject(null);
|
|
244
244
|
this.currentShape = null;
|
|
245
|
+
this._core.store.objects?.stopUndoCapturing();
|
|
245
246
|
this._core.rerender();
|
|
246
247
|
}
|
|
247
248
|
}
|