@inditextech/weave-sdk 5.0.0-SNAPSHOT.342.1 → 5.0.0-SNAPSHOT.366.1

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/sdk.node.js CHANGED
@@ -1156,8 +1156,8 @@ var require_isArray = __commonJS({ "../../node_modules/lodash/isArray.js"(export
1156
1156
  * _.isArray(_.noop);
1157
1157
  * // => false
1158
1158
  */
1159
- var isArray$13 = Array.isArray;
1160
- module.exports = isArray$13;
1159
+ var isArray$12 = Array.isArray;
1160
+ module.exports = isArray$12;
1161
1161
  } });
1162
1162
 
1163
1163
  //#endregion
@@ -1382,7 +1382,7 @@ var require_isTypedArray = __commonJS({ "../../node_modules/lodash/isTypedArray.
1382
1382
  //#endregion
1383
1383
  //#region ../../node_modules/lodash/isEmpty.js
1384
1384
  var require_isEmpty = __commonJS({ "../../node_modules/lodash/isEmpty.js"(exports, module) {
1385
- var baseKeys$1 = require__baseKeys(), getTag$1 = require__getTag(), isArguments$3 = require_isArguments(), isArray$12 = require_isArray(), isArrayLike$6 = require_isArrayLike(), isBuffer$3 = require_isBuffer(), isPrototype$2 = require__isPrototype(), isTypedArray$3 = require_isTypedArray();
1385
+ var baseKeys$1 = require__baseKeys(), getTag$1 = require__getTag(), isArguments$3 = require_isArguments(), isArray$11 = require_isArray(), isArrayLike$6 = require_isArrayLike(), isBuffer$3 = require_isBuffer(), isPrototype$2 = require__isPrototype(), isTypedArray$3 = require_isTypedArray();
1386
1386
  /** `Object#toString` result references. */
1387
1387
  var mapTag$1 = "[object Map]", setTag$1 = "[object Set]";
1388
1388
  /** Used for built-in method references. */
@@ -1424,7 +1424,7 @@ var require_isEmpty = __commonJS({ "../../node_modules/lodash/isEmpty.js"(export
1424
1424
  */
1425
1425
  function isEmpty(value) {
1426
1426
  if (value == null) return true;
1427
- if (isArrayLike$6(value) && (isArray$12(value) || typeof value == "string" || typeof value.splice == "function" || isBuffer$3(value) || isTypedArray$3(value) || isArguments$3(value))) return !value.length;
1427
+ if (isArrayLike$6(value) && (isArray$11(value) || typeof value == "string" || typeof value.splice == "function" || isBuffer$3(value) || isTypedArray$3(value) || isArguments$3(value))) return !value.length;
1428
1428
  var tag = getTag$1(value);
1429
1429
  if (tag == mapTag$1 || tag == setTag$1) return !value.size;
1430
1430
  if (isPrototype$2(value)) return !baseKeys$1(value).length;
@@ -1751,13 +1751,6 @@ const WEAVE_NODES_SELECTION_DEFAULT_CONFIG = {
1751
1751
  style: { dragOpacity: .75 }
1752
1752
  };
1753
1753
 
1754
- //#endregion
1755
- //#region src/plugins/context-menu/constants.ts
1756
- const WEAVE_CONTEXT_MENU_PLUGIN_KEY = "contextMenu";
1757
- const WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT = 4;
1758
- const WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT = 4;
1759
- const WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT = 500;
1760
-
1761
1754
  //#endregion
1762
1755
  //#region ../../node_modules/lodash/_listCacheClear.js
1763
1756
  var require__listCacheClear = __commonJS({ "../../node_modules/lodash/_listCacheClear.js"(exports, module) {
@@ -2864,7 +2857,7 @@ var require__isIndex = __commonJS({ "../../node_modules/lodash/_isIndex.js"(expo
2864
2857
  //#endregion
2865
2858
  //#region ../../node_modules/lodash/_arrayLikeKeys.js
2866
2859
  var require__arrayLikeKeys = __commonJS({ "../../node_modules/lodash/_arrayLikeKeys.js"(exports, module) {
2867
- var baseTimes = require__baseTimes(), isArguments$2 = require_isArguments(), isArray$11 = require_isArray(), isBuffer$2 = require_isBuffer(), isIndex$2 = require__isIndex(), isTypedArray$2 = require_isTypedArray();
2860
+ var baseTimes = require__baseTimes(), isArguments$2 = require_isArguments(), isArray$10 = require_isArray(), isBuffer$2 = require_isBuffer(), isIndex$2 = require__isIndex(), isTypedArray$2 = require_isTypedArray();
2868
2861
  /** Used for built-in method references. */
2869
2862
  var objectProto$4 = Object.prototype;
2870
2863
  /** Used to check objects for own properties. */
@@ -2878,7 +2871,7 @@ var require__arrayLikeKeys = __commonJS({ "../../node_modules/lodash/_arrayLikeK
2878
2871
  * @returns {Array} Returns the array of property names.
2879
2872
  */
2880
2873
  function arrayLikeKeys$2(value, inherited) {
2881
- var isArr = isArray$11(value), isArg = !isArr && isArguments$2(value), isBuff = !isArr && !isArg && isBuffer$2(value), isType = !isArr && !isArg && !isBuff && isTypedArray$2(value), skipIndexes = isArr || isArg || isBuff || isType, result = skipIndexes ? baseTimes(value.length, String) : [], length = result.length;
2874
+ var isArr = isArray$10(value), isArg = !isArr && isArguments$2(value), isBuff = !isArr && !isArg && isBuffer$2(value), isType = !isArr && !isArg && !isBuff && isTypedArray$2(value), skipIndexes = isArr || isArg || isBuff || isType, result = skipIndexes ? baseTimes(value.length, String) : [], length = result.length;
2882
2875
  for (var key in value) if ((inherited || hasOwnProperty$3.call(value, key)) && !(skipIndexes && (key == "length" || isBuff && (key == "offset" || key == "parent") || isType && (key == "buffer" || key == "byteLength" || key == "byteOffset") || isIndex$2(key, length)))) result.push(key);
2883
2876
  return result;
2884
2877
  }
@@ -2999,7 +2992,7 @@ var require_toPlainObject = __commonJS({ "../../node_modules/lodash/toPlainObjec
2999
2992
  //#endregion
3000
2993
  //#region ../../node_modules/lodash/_baseMergeDeep.js
3001
2994
  var require__baseMergeDeep = __commonJS({ "../../node_modules/lodash/_baseMergeDeep.js"(exports, module) {
3002
- var assignMergeValue$1 = require__assignMergeValue(), cloneBuffer = require__cloneBuffer(), cloneTypedArray = require__cloneTypedArray(), copyArray = require__copyArray(), initCloneObject = require__initCloneObject(), isArguments$1 = require_isArguments(), isArray$10 = require_isArray(), isArrayLikeObject = require_isArrayLikeObject(), isBuffer$1 = require_isBuffer(), isFunction = require_isFunction(), isObject$6 = require_isObject(), isPlainObject = require_isPlainObject(), isTypedArray$1 = require_isTypedArray(), safeGet$1 = require__safeGet(), toPlainObject = require_toPlainObject();
2995
+ var assignMergeValue$1 = require__assignMergeValue(), cloneBuffer = require__cloneBuffer(), cloneTypedArray = require__cloneTypedArray(), copyArray = require__copyArray(), initCloneObject = require__initCloneObject(), isArguments$1 = require_isArguments(), isArray$9 = require_isArray(), isArrayLikeObject = require_isArrayLikeObject(), isBuffer$1 = require_isBuffer(), isFunction = require_isFunction(), isObject$6 = require_isObject(), isPlainObject = require_isPlainObject(), isTypedArray$1 = require_isTypedArray(), safeGet$1 = require__safeGet(), toPlainObject = require_toPlainObject();
3003
2996
  /**
3004
2997
  * A specialized version of `baseMerge` for arrays and objects which performs
3005
2998
  * deep merges and tracks traversed objects enabling objects with circular
@@ -3024,9 +3017,9 @@ var require__baseMergeDeep = __commonJS({ "../../node_modules/lodash/_baseMergeD
3024
3017
  var newValue = customizer ? customizer(objValue, srcValue, key + "", object, source, stack) : void 0;
3025
3018
  var isCommon = newValue === void 0;
3026
3019
  if (isCommon) {
3027
- var isArr = isArray$10(srcValue), isBuff = !isArr && isBuffer$1(srcValue), isTyped = !isArr && !isBuff && isTypedArray$1(srcValue);
3020
+ var isArr = isArray$9(srcValue), isBuff = !isArr && isBuffer$1(srcValue), isTyped = !isArr && !isBuff && isTypedArray$1(srcValue);
3028
3021
  newValue = srcValue;
3029
- if (isArr || isBuff || isTyped) if (isArray$10(objValue)) newValue = objValue;
3022
+ if (isArr || isBuff || isTyped) if (isArray$9(objValue)) newValue = objValue;
3030
3023
  else if (isArrayLikeObject(objValue)) newValue = copyArray(objValue);
3031
3024
  else if (isBuff) {
3032
3025
  isCommon = false;
@@ -3702,223 +3695,6 @@ function isNumber(value) {
3702
3695
  return typeof value === "number" && !Number.isNaN(value);
3703
3696
  }
3704
3697
 
3705
- //#endregion
3706
- //#region src/actions/selection-tool/constants.ts
3707
- const SELECTION_TOOL_ACTION_NAME = "selectionTool";
3708
- const SELECTION_TOOL_STATE = {
3709
- ["IDLE"]: "idle",
3710
- ["SELECTING"]: "selection"
3711
- };
3712
-
3713
- //#endregion
3714
- //#region src/plugins/context-menu/context-menu.ts
3715
- var WeaveContextMenuPlugin = class extends WeavePlugin {
3716
- getLayerName = void 0;
3717
- initLayer = void 0;
3718
- constructor(params) {
3719
- super();
3720
- const { config } = params ?? {};
3721
- this.config = {
3722
- xOffset: WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT,
3723
- yOffset: WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT,
3724
- ...config
3725
- };
3726
- this.initialize();
3727
- }
3728
- initialize() {
3729
- this.timer = null;
3730
- this.tapHold = false;
3731
- this.contextMenuVisible = false;
3732
- this.tapStart = {
3733
- x: 0,
3734
- y: 0,
3735
- time: 0
3736
- };
3737
- this.tapHoldTimeout = WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT;
3738
- this.pointers = {};
3739
- }
3740
- getName() {
3741
- return WEAVE_CONTEXT_MENU_PLUGIN_KEY;
3742
- }
3743
- onInit() {
3744
- this.initEvents();
3745
- }
3746
- isPressed(e) {
3747
- return e.evt.buttons > 0;
3748
- }
3749
- setTapStart(e) {
3750
- this.tapStart = {
3751
- x: e.evt.clientX,
3752
- y: e.evt.clientY,
3753
- time: performance.now()
3754
- };
3755
- }
3756
- triggerContextMenu(eventTarget, target) {
3757
- const stage = this.instance.getStage();
3758
- const selectionPlugin = this.getSelectionPlugin();
3759
- let nodes = [];
3760
- if (target && target !== stage) {
3761
- const nodeHandler = this.instance.getNodeHandler(target.getAttrs().nodeType);
3762
- nodes = [{
3763
- instance: target,
3764
- node: nodeHandler?.serialize(target)
3765
- }];
3766
- }
3767
- const eventTargetParent = eventTarget.getParent();
3768
- if (eventTargetParent instanceof Konva.Transformer) nodes = eventTargetParent.nodes().map((node) => {
3769
- const nodeHandler = this.instance.getNodeHandler(node.getAttrs().nodeType);
3770
- return {
3771
- instance: node,
3772
- node: nodeHandler?.serialize(node)
3773
- };
3774
- });
3775
- if (this.contextMenuVisible) this.closeContextMenu();
3776
- let allNodesMutexUnlocked = true;
3777
- let allNodesUnlocked = true;
3778
- const actUser = this.instance.getStore().getUser();
3779
- for (const node of nodes) {
3780
- const locked = node.instance.getAttrs().locked;
3781
- const mutexInfo = this.instance.getNodeMutexLock(node.node?.key ?? "");
3782
- if (locked) {
3783
- allNodesUnlocked = false;
3784
- break;
3785
- }
3786
- if (mutexInfo && mutexInfo.user.id !== actUser.id) {
3787
- allNodesMutexUnlocked = false;
3788
- break;
3789
- }
3790
- }
3791
- if (!allNodesMutexUnlocked || !allNodesUnlocked) return;
3792
- if (selectionPlugin && !(eventTarget.getParent() instanceof Konva.Transformer && selectionPlugin.getSelectedNodes().length > 0)) {
3793
- selectionPlugin.setSelectedNodes([...nodes.map((node) => node.instance)]);
3794
- selectionPlugin.getHoverTransformer().nodes([]);
3795
- }
3796
- const containerRect = stage.container().getBoundingClientRect();
3797
- const pointerPos = stage.getPointerPosition();
3798
- const relativeClickPoint = stage.getRelativePointerPosition();
3799
- if (containerRect && pointerPos && relativeClickPoint && allNodesUnlocked) {
3800
- const contextMenuPoint = {
3801
- x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
3802
- y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
3803
- };
3804
- const stageClickPoint = this.getStageClickPoint(pointerPos);
3805
- this.contextMenuVisible = true;
3806
- this.instance.emitEvent("onNodeContextMenu", {
3807
- selection: nodes,
3808
- contextMenuPoint,
3809
- clickPoint: pointerPos,
3810
- stageClickPoint,
3811
- visible: true
3812
- });
3813
- }
3814
- }
3815
- closeContextMenu() {
3816
- this.contextMenuVisible = false;
3817
- this.instance.emitEvent("onNodeContextMenu", {
3818
- selection: [],
3819
- contextMenuPoint: {
3820
- x: 0,
3821
- y: 0
3822
- },
3823
- clickPoint: {
3824
- x: 0,
3825
- y: 0
3826
- },
3827
- stageClickPoint: {
3828
- x: 0,
3829
- y: 0
3830
- },
3831
- visible: false
3832
- });
3833
- }
3834
- getSelectionPlugin() {
3835
- const selectionPlugin = this.instance.getPlugin(WEAVE_NODES_SELECTION_KEY);
3836
- return selectionPlugin;
3837
- }
3838
- cancelLongPressTimer() {
3839
- if (this.timer) {
3840
- clearTimeout(this.timer);
3841
- this.timer = null;
3842
- }
3843
- }
3844
- initEvents() {
3845
- const stage = this.instance.getStage();
3846
- stage.on("pointerdown", (e) => {
3847
- this.setTapStart(e);
3848
- this.pointers[e.evt.pointerId] = e.evt;
3849
- if (e.evt.buttons === 0) return;
3850
- if (e.evt.pointerType === "mouse") return;
3851
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
3852
- if (this.timer) return;
3853
- this.timer = setTimeout(() => {
3854
- this.tapHold = true;
3855
- const actualActions = this.instance.getActiveAction();
3856
- if (actualActions !== SELECTION_TOOL_ACTION_NAME) return;
3857
- delete this.pointers[e.evt.pointerId];
3858
- const selectedGroup = getTargetedNode(this.instance);
3859
- this.triggerContextMenu(e.target, selectedGroup);
3860
- }, this.tapHoldTimeout);
3861
- });
3862
- stage.on("pointerup", (e) => {
3863
- delete this.pointers[e.evt.pointerId];
3864
- if (e.evt.pointerType === "mouse") return;
3865
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length + 1 > 1) return;
3866
- if (this.timer) {
3867
- clearTimeout(this.timer);
3868
- this.timer = null;
3869
- this.tapHold = false;
3870
- }
3871
- });
3872
- stage.on("contextmenu", (e) => {
3873
- e.evt.preventDefault();
3874
- if (!this.enabled) return;
3875
- const selectedGroup = getTargetedNode(this.instance);
3876
- this.triggerContextMenu(e.target, selectedGroup);
3877
- });
3878
- this.instance.addEventListener("onStageSelection", () => {
3879
- if (this.tapHold) return;
3880
- const containerRect = stage.container().getBoundingClientRect();
3881
- const pointerPos = stage.getPointerPosition();
3882
- if (containerRect && pointerPos) {
3883
- const contextMenuPoint = {
3884
- x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
3885
- y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
3886
- };
3887
- const stageClickPoint = this.getStageClickPoint(pointerPos);
3888
- this.instance.emitEvent("onNodeContextMenu", {
3889
- selection: [],
3890
- contextMenuPoint,
3891
- clickPoint: pointerPos,
3892
- stageClickPoint,
3893
- visible: false
3894
- });
3895
- }
3896
- });
3897
- }
3898
- getStageClickPoint(pointerPos) {
3899
- const stage = this.instance.getStage();
3900
- const scale = stage.scale();
3901
- const position = stage.position();
3902
- const stageClickPoint = {
3903
- x: (pointerPos.x - position.x) / scale.x,
3904
- y: (pointerPos.y - position.y) / scale.y
3905
- };
3906
- return stageClickPoint;
3907
- }
3908
- isContextMenuVisible() {
3909
- return this.contextMenuVisible;
3910
- }
3911
- isTapHold() {
3912
- return this.tapHold;
3913
- }
3914
- enable() {
3915
- this.enabled = true;
3916
- }
3917
- disable() {
3918
- this.enabled = false;
3919
- }
3920
- };
3921
-
3922
3698
  //#endregion
3923
3699
  //#region src/plugins/users-selection/constants.ts
3924
3700
  const WEAVE_USERS_SELECTION_KEY = "usersSelection";
@@ -4076,7 +3852,7 @@ var require_toNumber = __commonJS({ "../../node_modules/lodash/toNumber.js"(expo
4076
3852
  var require_debounce = __commonJS({ "../../node_modules/lodash/debounce.js"(exports, module) {
4077
3853
  var isObject$2 = require_isObject(), now = require_now(), toNumber = require_toNumber();
4078
3854
  /** Error message constants. */
4079
- var FUNC_ERROR_TEXT$3 = "Expected a function";
3855
+ var FUNC_ERROR_TEXT$2 = "Expected a function";
4080
3856
  var nativeMax = Math.max, nativeMin = Math.min;
4081
3857
  /**
4082
3858
  * Creates a debounced function that delays invoking `func` until after `wait`
@@ -4134,7 +3910,7 @@ var require_debounce = __commonJS({ "../../node_modules/lodash/debounce.js"(expo
4134
3910
  */
4135
3911
  function debounce$1(func, wait, options) {
4136
3912
  var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true;
4137
- if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$3);
3913
+ if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$2);
4138
3914
  wait = toNumber(wait) || 0;
4139
3915
  if (isObject$2(options)) {
4140
3916
  leading = !!options.leading;
@@ -4209,7 +3985,7 @@ var require_debounce = __commonJS({ "../../node_modules/lodash/debounce.js"(expo
4209
3985
  var require_throttle = __commonJS({ "../../node_modules/lodash/throttle.js"(exports, module) {
4210
3986
  var debounce = require_debounce(), isObject$1 = require_isObject();
4211
3987
  /** Error message constants. */
4212
- var FUNC_ERROR_TEXT$2 = "Expected a function";
3988
+ var FUNC_ERROR_TEXT$1 = "Expected a function";
4213
3989
  /**
4214
3990
  * Creates a throttled function that only invokes `func` at most once per
4215
3991
  * every `wait` milliseconds. The throttled function comes with a `cancel`
@@ -4256,7 +4032,7 @@ var require_throttle = __commonJS({ "../../node_modules/lodash/throttle.js"(expo
4256
4032
  */
4257
4033
  function throttle(func, wait, options) {
4258
4034
  var leading = true, trailing = true;
4259
- if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$2);
4035
+ if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$1);
4260
4036
  if (isObject$1(options)) {
4261
4037
  leading = "leading" in options ? !!options.leading : leading;
4262
4038
  trailing = "trailing" in options ? !!options.trailing : trailing;
@@ -4277,170 +4053,310 @@ const WEAVE_STAGE_NODE_TYPE = "stage";
4277
4053
  const WEAVE_STAGE_DEFAULT_MODE = "default";
4278
4054
 
4279
4055
  //#endregion
4280
- //#region src/plugins/stage-grid/constants.ts
4281
- const WEAVE_STAGE_GRID_PLUGIN_KEY = "stageGrid";
4282
- const WEAVE_GRID_TYPES = {
4283
- ["LINES"]: "lines",
4284
- ["DOTS"]: "dots"
4056
+ //#region src/actions/selection-tool/constants.ts
4057
+ const SELECTION_TOOL_ACTION_NAME = "selectionTool";
4058
+ const SELECTION_TOOL_STATE = {
4059
+ ["IDLE"]: "idle",
4060
+ ["SELECTING"]: "selection"
4285
4061
  };
4286
- const WEAVE_GRID_DOT_TYPES = {
4287
- ["SQUARE"]: "square",
4288
- ["CIRCLE"]: "circle"
4062
+
4063
+ //#endregion
4064
+ //#region src/constants.ts
4065
+ const DEFAULT_THROTTLE_MS = 50;
4066
+ const DEFAULT_ADD_NODE_OPTIONS = { emitUserChangeEvent: false };
4067
+ const DEFAULT_UPDATE_NODE_OPTIONS = { emitUserChangeEvent: false };
4068
+ const DEFAULT_REMOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4069
+ const DEFAULT_MOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4070
+ const WEAVE_DEFAULT_CONFIG = {
4071
+ behaviors: { axisLockThreshold: 5 },
4072
+ performance: { upscale: { enabled: false } }
4289
4073
  };
4290
- const WEAVE_GRID_DEFAULT_CONFIG = {
4291
- type: WEAVE_GRID_TYPES.LINES,
4292
- gridColor: "#b3b3b3",
4293
- gridMajorColor: "#b3b3b3",
4294
- gridOriginColor: "#ff746c",
4295
- gridSize: 20,
4296
- gridMajorEvery: 10,
4297
- gridMajorRatio: 2,
4298
- gridStroke: 1,
4299
- gridDotType: WEAVE_GRID_DOT_TYPES.CIRCLE,
4300
- gridDotRadius: 1,
4301
- gridDotRectSize: 2
4302
- };
4303
- const WEAVE_GRID_LAYER_ID = "gridLayer";
4304
4074
 
4305
4075
  //#endregion
4306
- //#region src/plugins/stage-panning/constants.ts
4307
- const WEAVE_STAGE_PANNING_KEY = "stagePanning";
4308
- const WEAVE_STAGE_PANNING_THROTTLE_MS = 20;
4309
- const WEAVE_STAGE_PANNING_DEFAULT_CONFIG = { edgePan: {
4310
- offset: 25,
4311
- speed: 20
4312
- } };
4313
-
4314
- //#endregion
4315
- //#region src/plugins/nodes-multi-selection-feedback/constants.ts
4316
- const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY = "nodesMultiSelectionFeedback";
4317
- const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID = "selectionLayer";
4318
- const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG = { style: {
4319
- stroke: "#ff2c2cff",
4320
- strokeWidth: 2,
4321
- fill: "transparent"
4322
- } };
4323
-
4324
- //#endregion
4325
- //#region src/constants.ts
4326
- const DEFAULT_THROTTLE_MS = 50;
4327
- const DEFAULT_ADD_NODE_OPTIONS = { emitUserChangeEvent: false };
4328
- const DEFAULT_UPDATE_NODE_OPTIONS = { emitUserChangeEvent: false };
4329
- const DEFAULT_REMOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4330
- const DEFAULT_MOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4331
- const WEAVE_DEFAULT_CONFIG = {
4332
- behaviors: { axisLockThreshold: 5 },
4333
- performance: { upscale: { enabled: false } }
4076
+ //#region src/plugins/nodes-selection/gesture-detector.ts
4077
+ const MOVED_DISTANCE = 5;
4078
+ const DOUBLE_TAP_DISTANCE = 10;
4079
+ const DOUBLE_TAP_TIME = 300;
4080
+ /**
4081
+ * Tracks single-tap, double-tap, and drag-move gesture state for the
4082
+ * nodes-selection plugin. Has no dependency on Weave or Konva internals.
4083
+ */
4084
+ var GestureDetector = class {
4085
+ taps = 0;
4086
+ tapStart = null;
4087
+ previousTap = null;
4088
+ tapTimeoutId = null;
4089
+ isDoubleTap = false;
4090
+ /** Call on every pointerdown to record the tap origin. */
4091
+ setTapStart(clientX, clientY) {
4092
+ this.taps += 1;
4093
+ this.tapStart = {
4094
+ x: clientX,
4095
+ y: clientY,
4096
+ time: performance.now()
4097
+ };
4098
+ }
4099
+ /** Returns true if the pointer moved more than the move threshold since tap start. */
4100
+ checkMoved(clientX, clientY) {
4101
+ if (!this.tapStart) return false;
4102
+ const dist = Math.hypot(clientX - this.tapStart.x, clientY - this.tapStart.y);
4103
+ return dist > MOVED_DISTANCE;
4104
+ }
4105
+ /** Returns true if a drag moved further than the move threshold between two stage positions. */
4106
+ checkMovedDrag(init, actual) {
4107
+ if (!this.tapStart) return false;
4108
+ const dist = Math.hypot(actual.x - init.x, actual.y - init.y);
4109
+ return dist > MOVED_DISTANCE;
4110
+ }
4111
+ /**
4112
+ * Call on pointerup after setTapStart to detect a double-tap.
4113
+ * Sets isDoubleTap = true when two taps occur close in time and space.
4114
+ */
4115
+ checkDoubleTap(clientX, clientY) {
4116
+ if (!this.previousTap) return;
4117
+ const now$2 = performance.now();
4118
+ const dist = Math.hypot(clientX - this.previousTap.x, clientY - this.previousTap.y);
4119
+ if (this.tapTimeoutId) clearTimeout(this.tapTimeoutId);
4120
+ this.tapTimeoutId = setTimeout(() => {
4121
+ this.taps = 0;
4122
+ }, DOUBLE_TAP_TIME + 5);
4123
+ if (this.taps > 1 && now$2 - this.previousTap.time < DOUBLE_TAP_TIME && dist < DOUBLE_TAP_DISTANCE) {
4124
+ this.taps = 0;
4125
+ this.tapStart = null;
4126
+ this.isDoubleTap = true;
4127
+ }
4128
+ }
4129
+ /** Call after checkDoubleTap on pointerup to advance the tap history. */
4130
+ commitTap() {
4131
+ this.previousTap = this.tapStart;
4132
+ }
4133
+ resetDoubleTap() {
4134
+ this.isDoubleTap = false;
4135
+ }
4136
+ reset() {
4137
+ this.taps = 0;
4138
+ this.tapStart = null;
4139
+ this.previousTap = null;
4140
+ this.isDoubleTap = false;
4141
+ if (this.tapTimeoutId) {
4142
+ clearTimeout(this.tapTimeoutId);
4143
+ this.tapTimeoutId = null;
4144
+ }
4145
+ }
4334
4146
  };
4335
4147
 
4336
4148
  //#endregion
4337
- //#region src/plugins/users-presence/constants.ts
4338
- const WEAVE_USER_PRESENCE_KEY = "userPresence";
4339
- const WEAVE_USERS_PRESENCE_PLUGIN_KEY = "usersPresence";
4340
- const WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS = { awarenessThrottleMs: DEFAULT_THROTTLE_MS };
4341
-
4342
- //#endregion
4343
- //#region src/plugins/nodes-selection/nodes-selection.ts
4344
- var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4345
- selectionStart = null;
4346
- panSpeed = {
4149
+ //#region src/plugins/nodes-selection/edge-panning.ts
4150
+ /**
4151
+ * Handles the rAF-driven auto-pan loop that scrolls the canvas when the
4152
+ * pointer is held near an edge during area selection.
4153
+ */
4154
+ var EdgePanning = class {
4155
+ panLoopId = null;
4156
+ direction = {
4347
4157
  x: 0,
4348
4158
  y: 0
4349
4159
  };
4350
- panDirection = {
4160
+ speed = {
4351
4161
  x: 0,
4352
4162
  y: 0
4353
4163
  };
4354
- panLoopId = null;
4355
- prevSelectedNodes = [];
4356
- handledClickOrTap = false;
4357
- dragInProcess = false;
4358
- dragSelectedNodes = [];
4359
- transformInProcess = false;
4360
- serializedSelectedNodes = [];
4361
- constructor(params) {
4362
- super();
4363
- this.config = mergeExceptArrays(WEAVE_NODES_SELECTION_DEFAULT_CONFIG, params?.config ?? {});
4364
- this.initialize();
4164
+ constructor(config, callbacks) {
4165
+ this.config = config;
4166
+ this.callbacks = callbacks;
4365
4167
  }
4366
- initialize() {
4367
- this.defaultEnabledAnchors = this.config.selection?.enabledAnchors ?? [
4368
- "top-left",
4369
- "top-center",
4370
- "top-right",
4371
- "middle-right",
4372
- "middle-left",
4373
- "bottom-left",
4374
- "bottom-center",
4375
- "bottom-right"
4376
- ];
4377
- this.taps = 0;
4378
- this.isSpaceKeyPressed = false;
4379
- this.isDoubleTap = false;
4380
- this.tapStart = null;
4381
- this.previousTap = null;
4382
- this.active = false;
4383
- this.didMove = false;
4384
- this.selecting = false;
4385
- this.initialized = false;
4386
- this.enabled = false;
4387
- this.pointers = {};
4388
- this.panLoopId = null;
4389
- this.tapTimeoutId = null;
4390
- this.dragSelectedNodes = [];
4391
- this.dragInProcess = false;
4168
+ /** Start the panning rAF loop. */
4169
+ start() {
4170
+ this.panLoopId = requestAnimationFrame(() => this.loop());
4392
4171
  }
4393
- getName() {
4394
- return WEAVE_NODES_SELECTION_KEY;
4172
+ /** Stop the panning rAF loop. */
4173
+ stop() {
4174
+ if (this.panLoopId !== null) {
4175
+ cancelAnimationFrame(this.panLoopId);
4176
+ this.panLoopId = null;
4177
+ }
4395
4178
  }
4396
- getLayerName() {
4397
- return WEAVE_NODES_SELECTION_LAYER_ID;
4179
+ /** Reset direction and speed vectors to zero. */
4180
+ reset() {
4181
+ this.direction.x = 0;
4182
+ this.direction.y = 0;
4183
+ this.speed = {
4184
+ x: 0,
4185
+ y: 0
4186
+ };
4398
4187
  }
4399
- getConfiguration() {
4400
- return this.config;
4188
+ /**
4189
+ * Recalculate pan direction and speed based on current pointer position.
4190
+ * Should be called on every pointermove during area selection.
4191
+ */
4192
+ updateDirection() {
4193
+ const stage = this.callbacks.getStage();
4194
+ const pos = stage.getPointerPosition();
4195
+ const viewWidth = stage.width();
4196
+ const viewHeight = stage.height();
4197
+ if (!pos) return;
4198
+ const distLeft = pos.x;
4199
+ const distRight = viewWidth - pos.x;
4200
+ const distTop = pos.y;
4201
+ const distBottom = viewHeight - pos.y;
4202
+ this.direction.x = 0;
4203
+ this.direction.y = 0;
4204
+ this.speed = {
4205
+ x: 0,
4206
+ y: 0
4207
+ };
4208
+ if (distLeft < this.config.edgeThreshold) {
4209
+ this.direction.x = 1;
4210
+ this.speed.x = this.getSpeedFromEdge(distLeft);
4211
+ } else if (distRight < this.config.edgeThreshold) {
4212
+ this.direction.x = -1;
4213
+ this.speed.x = this.getSpeedFromEdge(distRight);
4214
+ }
4215
+ if (distTop < this.config.edgeThreshold) {
4216
+ this.direction.y = 1;
4217
+ this.speed.y = this.getSpeedFromEdge(distTop);
4218
+ } else if (distBottom < this.config.edgeThreshold) {
4219
+ this.direction.y = -1;
4220
+ this.speed.y = this.getSpeedFromEdge(distBottom);
4221
+ }
4401
4222
  }
4402
- initLayer() {
4403
- const stage = this.instance.getStage();
4404
- const layer = new Konva.Layer({ id: this.getLayerName() });
4405
- stage.add(layer);
4223
+ getSpeedFromEdge(distanceFromEdge) {
4224
+ const stage = this.callbacks.getStage();
4225
+ const scaledDistance = distanceFromEdge / stage.scaleX();
4226
+ if (scaledDistance < this.config.edgeThreshold) {
4227
+ const factor = 1 - scaledDistance / this.config.edgeThreshold;
4228
+ return this.config.minScrollSpeed + (this.config.maxScrollSpeed - this.config.minScrollSpeed) * factor;
4229
+ }
4230
+ return 0;
4406
4231
  }
4407
- isPasting() {
4408
- const copyPastePlugin = this.instance.getPlugin("copyPasteNodes");
4409
- if (!copyPastePlugin) return false;
4410
- return copyPastePlugin.isPasting();
4232
+ loop() {
4233
+ const stage = this.callbacks.getStage();
4234
+ if (this.callbacks.isSelecting() && (this.direction.x !== 0 || this.direction.y !== 0)) {
4235
+ const scale = stage.scaleX();
4236
+ const stepX = (this.speed.x || 0) / scale;
4237
+ const stepY = (this.speed.y || 0) / scale;
4238
+ stage.x(stage.x() + this.direction.x * stepX);
4239
+ stage.y(stage.y() + this.direction.y * stepY);
4240
+ this.callbacks.onTick(this.direction.x * stepX, this.direction.y * stepY);
4241
+ }
4242
+ if (this.callbacks.isSelecting()) this.panLoopId = requestAnimationFrame(() => this.loop());
4411
4243
  }
4412
- isAreaSelecting() {
4413
- return this.selecting;
4244
+ };
4245
+
4246
+ //#endregion
4247
+ //#region src/plugins/nodes-selection/area-selection.ts
4248
+ /**
4249
+ * Manages the visual selection-rectangle drawn while the user drags an area
4250
+ * selection, plus the coordinate state (x1/y1/x2/y2) that tracks its bounds.
4251
+ */
4252
+ var AreaSelector = class {
4253
+ x1 = 0;
4254
+ y1 = 0;
4255
+ x2 = 0;
4256
+ y2 = 0;
4257
+ /** The stage-space anchor point when area selection started (updated by edge panning). */
4258
+ selectionStart = null;
4259
+ /**
4260
+ * Create and add the selection Konva.Rect to the given layer.
4261
+ * Must be called once during plugin initialisation.
4262
+ */
4263
+ init(layer, config, scaleX) {
4264
+ this.rect = new Konva.Rect({
4265
+ ...config,
4266
+ ...config.strokeWidth && { strokeWidth: config.strokeWidth / scaleX },
4267
+ ...config.dash && { dash: config.dash.map((d) => d / scaleX) },
4268
+ visible: false,
4269
+ listening: false
4270
+ });
4271
+ layer.add(this.rect);
4414
4272
  }
4415
- isSelecting() {
4416
- return this.instance.getActiveAction() === SELECTION_TOOL_ACTION_NAME;
4273
+ getRect() {
4274
+ return this.rect;
4417
4275
  }
4418
- isNodeSelected(ele) {
4419
- let selected = false;
4420
- if (this.getSelectedNodes().length === 1 && this.getSelectedNodes()[0].getAttrs().id === ele.getAttrs().id) selected = true;
4421
- return selected;
4276
+ /** Returns the screen-space bounding box of the selection rectangle. */
4277
+ getBox() {
4278
+ return this.rect.getClientRect();
4422
4279
  }
4423
- onInit() {
4424
- const stage = this.instance.getStage();
4425
- const selectionLayer = this.getLayer();
4426
- stage.container().tabIndex = 1;
4427
- stage.container().focus();
4428
- const selectionRectangle = new Konva.Rect({
4429
- ...this.config.selectionArea,
4430
- ...this.config.selectionArea.strokeWidth && { strokeWidth: this.config.selectionArea.strokeWidth / stage.scaleX() },
4431
- ...this.config.selectionArea.dash && { dash: this.config.selectionArea.dash.map((d) => d / stage.scaleX()) },
4432
- visible: false,
4433
- listening: false
4280
+ /** Set the anchor corner when area selection begins. */
4281
+ setStart(x, y) {
4282
+ this.x1 = x;
4283
+ this.y1 = y;
4284
+ this.x2 = x;
4285
+ this.y2 = y;
4286
+ this.selectionStart = {
4287
+ x,
4288
+ y
4289
+ };
4290
+ }
4291
+ /**
4292
+ * Adjust stroke and dash to compensate for stage scale, reset dimensions.
4293
+ * Call when area selection starts so the rect looks pixel-perfect at any zoom.
4294
+ */
4295
+ resetForScale(scaleX, config) {
4296
+ this.rect.strokeWidth(config.strokeWidth / scaleX);
4297
+ this.rect.dash(config.dash?.map((d) => d / scaleX) ?? []);
4298
+ this.rect.width(0);
4299
+ this.rect.height(0);
4300
+ }
4301
+ /**
4302
+ * Recalculate x2/y2 from the current pointer position and repaint the rect.
4303
+ * @param selectNone — Callback that clears the transformer selection; called
4304
+ * before updating the rect so previously selected nodes are deselected.
4305
+ */
4306
+ update(stage, selectNone) {
4307
+ this.x2 = stage.getRelativePointerPosition()?.x ?? 0;
4308
+ this.y2 = stage.getRelativePointerPosition()?.y ?? 0;
4309
+ selectNone();
4310
+ this.rect.setAttrs({
4311
+ visible: true,
4312
+ x: Math.min(this.x1, this.x2),
4313
+ y: Math.min(this.y1, this.y2),
4314
+ width: Math.abs(this.x2 - this.x1),
4315
+ height: Math.abs(this.y2 - this.y1)
4434
4316
  });
4435
- selectionLayer?.add(selectionRectangle);
4436
- const tr = new Konva.Transformer({
4317
+ }
4318
+ hide() {
4319
+ this.rect.setAttrs({
4320
+ width: 0,
4321
+ height: 0,
4322
+ visible: false
4323
+ });
4324
+ }
4325
+ };
4326
+
4327
+ //#endregion
4328
+ //#region src/plugins/nodes-selection/transformer-controller.ts
4329
+ /**
4330
+ * Creates and owns both Konva.Transformer instances (selection + hover) and
4331
+ * registers all transformer-level event handlers. Business-logic callbacks are
4332
+ * injected to keep this class decoupled from WeaveNodesSelectionPlugin internals.
4333
+ */
4334
+ var TransformerController = class {
4335
+ dragInProcess = false;
4336
+ transformInProcess = false;
4337
+ didMove = false;
4338
+ initialPos = null;
4339
+ originalNodes = {};
4340
+ originalContainers = {};
4341
+ currentDragSelectedNodes = [];
4342
+ /** Mirrors the previous transformer node list for undo/redo handling. */
4343
+ prevSelectedNodes = [];
4344
+ constructor(instance, config, gesture, callbacks) {
4345
+ this.instance = instance;
4346
+ this.config = config;
4347
+ this.gesture = gesture;
4348
+ this.callbacks = callbacks;
4349
+ }
4350
+ /** Create transformers, add to layer, and register all events. Must be called once during onInit. */
4351
+ setup(layer) {
4352
+ this.tr = new Konva.Transformer({
4437
4353
  id: "selectionTransformer",
4438
4354
  ...this.config.selection,
4439
4355
  listening: true,
4440
4356
  shouldOverdrawWholeArea: true
4441
4357
  });
4442
- selectionLayer?.add(tr);
4443
- const trHover = new Konva.Transformer({
4358
+ layer.add(this.tr);
4359
+ this.trHover = new Konva.Transformer({
4444
4360
  id: "hoverTransformer",
4445
4361
  ...this.config.hover,
4446
4362
  ignoreStroke: true,
@@ -4449,94 +4365,87 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4449
4365
  enabledAnchors: [],
4450
4366
  listening: false
4451
4367
  });
4452
- selectionLayer?.add(trHover);
4368
+ layer.add(this.trHover);
4369
+ this.registerStagePointerMove();
4370
+ this.registerTransformerEvents();
4371
+ this.registerInstanceEvents();
4372
+ }
4373
+ getTransformer() {
4374
+ return this.tr;
4375
+ }
4376
+ getHoverTransformer() {
4377
+ return this.trHover;
4378
+ }
4379
+ isDragging() {
4380
+ return this.dragInProcess;
4381
+ }
4382
+ isTransforming() {
4383
+ return this.transformInProcess;
4384
+ }
4385
+ getStage() {
4386
+ return this.instance.getStage();
4387
+ }
4388
+ registerStagePointerMove() {
4389
+ const stage = this.getStage();
4453
4390
  const handlePointerMoveInit = () => {
4454
4391
  if (this.dragInProcess) return;
4455
- if (tr.nodes().length === 1 && tr.nodes()[0].getAttrs().isContainerPrincipal) {
4392
+ if (this.tr.nodes().length === 1 && this.tr.nodes()[0].getAttrs().isContainerPrincipal) {
4456
4393
  const pos = stage.getPointerPosition();
4457
4394
  if (!pos) return;
4458
4395
  const shapeUnder = stage.getIntersection(pos);
4459
4396
  if (!shapeUnder) {
4460
- tr.setAttrs({ listening: true });
4461
- tr.forceUpdate();
4397
+ this.tr.setAttrs({ listening: true });
4398
+ this.tr.forceUpdate();
4462
4399
  }
4463
- if (shapeUnder && tr.getChildren().includes(shapeUnder) && shapeUnder.name() === "back") {
4464
- tr.setAttrs({ listening: false });
4465
- tr.forceUpdate();
4400
+ if (shapeUnder && this.tr.getChildren().includes(shapeUnder) && shapeUnder.name() === "back") {
4401
+ this.tr.setAttrs({ listening: false });
4402
+ this.tr.forceUpdate();
4466
4403
  }
4467
- if (shapeUnder && tr.nodes()[0].getChildren().includes(shapeUnder)) {
4468
- tr.setAttrs({ listening: false });
4469
- tr.forceUpdate();
4404
+ if (shapeUnder && this.tr.nodes()[0].getChildren().includes(shapeUnder)) {
4405
+ this.tr.setAttrs({ listening: false });
4406
+ this.tr.forceUpdate();
4470
4407
  }
4471
- if (shapeUnder && !tr.getChildren().includes(shapeUnder) && tr.nodes()[0].getChildren().includes(shapeUnder)) {
4472
- tr.setAttrs({ listening: true });
4473
- tr.forceUpdate();
4408
+ if (shapeUnder && !this.tr.getChildren().includes(shapeUnder) && this.tr.nodes()[0].getChildren().includes(shapeUnder)) {
4409
+ this.tr.setAttrs({ listening: true });
4410
+ this.tr.forceUpdate();
4474
4411
  }
4475
4412
  }
4476
4413
  };
4477
4414
  stage.on("pointermove", (0, import_throttle.default)(handlePointerMoveInit, DEFAULT_THROTTLE_MS));
4478
- tr.on("transformstart", (e) => {
4415
+ }
4416
+ registerTransformerEvents() {
4417
+ const stage = this.getStage();
4418
+ let nodeHovered = void 0;
4419
+ this.tr.on("transformstart", (e) => {
4479
4420
  this.transformInProcess = true;
4480
- this.triggerSelectedNodesEvent();
4481
- const selectedNodes$1 = tr.nodes();
4482
- for (const node of selectedNodes$1) node.handleMouseout(e);
4483
- if (this.getSelectedNodes().length > 1) this.instance.setMutexLock({
4484
- nodeIds: selectedNodes$1.map((node) => node.id()),
4421
+ this.callbacks.triggerSelectedNodesEvent();
4422
+ const selectedNodes = this.tr.nodes();
4423
+ for (const node of selectedNodes) node.handleMouseout(e);
4424
+ if (selectedNodes.length > 1) this.instance.setMutexLock({
4425
+ nodeIds: selectedNodes.map((node) => node.id()),
4485
4426
  operation: "nodes-transform"
4486
4427
  });
4487
4428
  this.instance.getHooks().callHook("weave:onTransformerTransformStart", {
4488
4429
  e,
4489
- nodes: selectedNodes$1
4430
+ nodes: selectedNodes
4490
4431
  });
4491
4432
  });
4492
- let nodeHovered = void 0;
4493
- tr.on("mousemove", (e) => {
4494
- if (this.dragInProcess) return;
4495
- const pointerPos = stage.getPointerPosition();
4496
- if (!pointerPos) return;
4497
- this.disable();
4498
- const shape = stage.getIntersection(pointerPos);
4499
- this.enable();
4500
- if (shape) {
4501
- const targetNode = this.instance.getInstanceRecursive(shape);
4502
- if (targetNode && targetNode !== nodeHovered) {
4503
- this.instance.getStage().handleMouseover(e);
4504
- nodeHovered?.handleMouseout?.(e);
4505
- targetNode?.handleMouseover?.(e);
4506
- nodeHovered = targetNode;
4507
- }
4508
- targetNode?.handleMouseover?.(e);
4509
- } else nodeHovered?.handleMouseout?.(e);
4510
- });
4511
- tr.on("mouseover", () => {
4512
- const nodesSelected = tr.nodes();
4513
- if (nodesSelected.length > 1) stage.container().style.cursor = "grab";
4514
- });
4515
- tr.on("mouseout", (e) => {
4516
- this.instance.getStage().handleMouseover?.(e);
4517
- nodeHovered = void 0;
4518
- });
4519
- window.addEventListener("mouseout", (e) => {
4520
- if (nodeHovered) {
4521
- nodeHovered.handleMouseout?.(e);
4522
- nodeHovered = void 0;
4523
- }
4524
- this.instance.getStage().handleMouseover?.(e);
4525
- }, { signal: this.instance.getEventsController()?.signal });
4526
4433
  const handleTransform = (e) => {
4527
- const moved = this.checkMoved(e);
4528
- if (moved) this.getContextMenuPlugin()?.cancelLongPressTimer();
4529
- this.triggerSelectedNodesEvent();
4434
+ const moved = this.gesture.checkMoved(e.evt.clientX, e.evt.clientY);
4435
+ if (moved) this.callbacks.getContextMenuPlugin()?.cancelLongPressTimer();
4436
+ this.callbacks.triggerSelectedNodesEvent();
4437
+ const selectedNodes = this.tr.nodes();
4530
4438
  this.instance.getHooks().callHook("weave:onTransformerTransform", {
4531
4439
  e,
4532
4440
  nodes: selectedNodes
4533
4441
  });
4534
- if (this.getUsersPresencePlugin()) {
4535
- for (const node of tr.nodes()) {
4442
+ const usersPresence = this.callbacks.getUsersPresencePlugin();
4443
+ if (usersPresence) {
4444
+ for (const node of this.tr.nodes()) {
4536
4445
  let parentId = node.getParent()?.id() ?? "";
4537
4446
  const parent = node.getParent();
4538
4447
  if (parent?.getAttrs().nodeId) parentId = parent.getAttrs().nodeId;
4539
- this.getUsersPresencePlugin()?.setPresence(node.id(), parentId, {
4448
+ usersPresence.setPresence(node.id(), parentId, {
4540
4449
  x: node.x(),
4541
4450
  y: node.y(),
4542
4451
  width: node.width(),
@@ -4547,65 +4456,92 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4547
4456
  strokeScaleEnabled: false
4548
4457
  }, false);
4549
4458
  }
4550
- this.getUsersPresencePlugin()?.forceSendPresence();
4459
+ usersPresence.forceSendPresence();
4551
4460
  }
4552
4461
  };
4553
- tr.on("transform", (0, import_throttle.default)(handleTransform, DEFAULT_THROTTLE_MS));
4554
- tr.on("transformend", (e) => {
4462
+ this.tr.on("transform", (0, import_throttle.default)(handleTransform, DEFAULT_THROTTLE_MS));
4463
+ this.tr.on("transformend", (e) => {
4555
4464
  this.transformInProcess = false;
4556
- if (this.getSelectedNodes().length > 1) this.instance.releaseMutexLock();
4557
- const selectedNodes$1 = tr.nodes();
4558
- for (const node of selectedNodes$1) {
4465
+ const selectedNodes = this.tr.nodes();
4466
+ if (selectedNodes.length > 1) this.instance.releaseMutexLock();
4467
+ for (const node of selectedNodes) {
4559
4468
  node.handleDeselectNode();
4560
4469
  node.handleSelectNode();
4561
4470
  }
4562
- tr.forceUpdate();
4563
- this.triggerSelectedNodesEvent();
4471
+ this.tr.forceUpdate();
4472
+ this.callbacks.triggerSelectedNodesEvent();
4564
4473
  this.instance.getHooks().callHook("weave:onTransformerTransformEnd", {
4565
4474
  e,
4566
- nodes: selectedNodes$1
4475
+ nodes: selectedNodes
4567
4476
  });
4568
4477
  });
4569
- let initialPos = null;
4570
- let originalNodes = {};
4571
- let originalContainers = {};
4572
- let selectedNodes = [];
4573
- tr.on("dragstart", (e) => {
4478
+ this.tr.on("mousemove", (e) => {
4479
+ if (this.dragInProcess) return;
4480
+ const pointerPos = stage.getPointerPosition();
4481
+ if (!pointerPos) return;
4482
+ this.callbacks.disablePlugin();
4483
+ const shape = stage.getIntersection(pointerPos);
4484
+ this.callbacks.enablePlugin();
4485
+ if (shape) {
4486
+ const targetNode = this.instance.getInstanceRecursive(shape);
4487
+ if (targetNode && targetNode !== nodeHovered) {
4488
+ this.instance.getStage().handleMouseover(e);
4489
+ nodeHovered?.handleMouseout?.(e);
4490
+ targetNode?.handleMouseover?.(e);
4491
+ nodeHovered = targetNode;
4492
+ }
4493
+ targetNode?.handleMouseover?.(e);
4494
+ } else nodeHovered?.handleMouseout?.(e);
4495
+ });
4496
+ this.tr.on("mouseover", () => {
4497
+ const nodesSelected = this.tr.nodes();
4498
+ if (nodesSelected.length > 1) stage.container().style.cursor = "grab";
4499
+ });
4500
+ this.tr.on("mouseout", (e) => {
4501
+ this.instance.getStage().handleMouseover?.(e);
4502
+ nodeHovered = void 0;
4503
+ });
4504
+ window.addEventListener("mouseout", (e) => {
4505
+ if (nodeHovered) {
4506
+ nodeHovered.handleMouseout?.(e);
4507
+ nodeHovered = void 0;
4508
+ }
4509
+ this.instance.getStage().handleMouseover?.(e);
4510
+ }, { signal: this.instance.getEventsController().signal });
4511
+ this.tr.on("dragstart", (e) => {
4574
4512
  this.dragInProcess = true;
4575
4513
  if (!e?.evt) return;
4576
- let isWheelMousePressed = false;
4577
- if (e.evt?.button === 1) isWheelMousePressed = true;
4514
+ const isWheelMousePressed = e.evt?.button === 1;
4578
4515
  const mainLayer = this.instance.getMainLayer();
4579
4516
  if (!mainLayer) return;
4580
- initialPos = {
4517
+ this.initialPos = {
4581
4518
  x: e.target.x(),
4582
4519
  y: e.target.y()
4583
4520
  };
4584
4521
  this.didMove = false;
4585
- const stage$1 = this.instance.getStage();
4586
- this.saveDragSelectedNodes();
4587
- this.setNodesOpacityOnDrag();
4588
- selectedNodes = tr.nodes();
4522
+ this.callbacks.saveDragSelectedNodes();
4523
+ this.callbacks.setNodesOpacityOnDrag();
4524
+ this.currentDragSelectedNodes = this.tr.nodes();
4589
4525
  if (isWheelMousePressed) {
4590
4526
  e.cancelBubble = true;
4591
4527
  e.target.stopDrag();
4592
4528
  return;
4593
4529
  }
4594
- for (const node of selectedNodes) {
4530
+ for (const node of this.currentDragSelectedNodes) {
4595
4531
  const originalNode = node.clone();
4596
4532
  let originalContainer = node.getParent();
4597
- if (originalContainer?.getAttrs().nodeId) originalContainer = stage$1.findOne(`#${originalContainer.getAttrs().nodeId}`);
4598
- originalNodes[node.getAttrs().id ?? ""] = originalNode;
4599
- originalContainers[node.getAttrs().id ?? ""] = originalContainer;
4533
+ if (originalContainer?.getAttrs().nodeId) originalContainer = stage.findOne(`#${originalContainer.getAttrs().nodeId}`);
4534
+ this.originalNodes[node.getAttrs().id ?? ""] = originalNode;
4535
+ this.originalContainers[node.getAttrs().id ?? ""] = originalContainer;
4600
4536
  }
4601
4537
  e.cancelBubble = true;
4602
4538
  this.instance.getHooks().callHook("weave:onTransformerDragStart", {
4603
4539
  e,
4604
- nodes: selectedNodes
4540
+ nodes: this.currentDragSelectedNodes
4605
4541
  });
4606
- tr.forceUpdate();
4607
- if (selectedNodes.length > 1) this.instance.setMutexLock({
4608
- nodeIds: selectedNodes.map((node) => node.id()),
4542
+ this.tr.forceUpdate();
4543
+ if (this.currentDragSelectedNodes.length > 1) this.instance.setMutexLock({
4544
+ nodeIds: this.currentDragSelectedNodes.map((node) => node.id()),
4609
4545
  operation: "nodes-drag"
4610
4546
  });
4611
4547
  });
@@ -4614,16 +4550,15 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4614
4550
  x: e.target.x(),
4615
4551
  y: e.target.y()
4616
4552
  };
4617
- let isWheelMousePressed = false;
4618
- if (e.evt?.button === 1) isWheelMousePressed = true;
4553
+ const isWheelMousePressed = e.evt?.button === 1;
4619
4554
  e.cancelBubble = true;
4620
4555
  this.instance.getHooks().callHook("weave:onTransformerDragMove", {
4621
4556
  e,
4622
- nodes: selectedNodes
4557
+ nodes: this.currentDragSelectedNodes
4623
4558
  });
4624
- if (initialPos) {
4625
- const moved = this.checkMovedDrag(initialPos, actualPos);
4626
- if (moved) this.getContextMenuPlugin()?.cancelLongPressTimer();
4559
+ if (this.initialPos) {
4560
+ const moved = this.gesture.checkMovedDrag(this.initialPos, actualPos);
4561
+ if (moved) this.callbacks.getContextMenuPlugin()?.cancelLongPressTimer();
4627
4562
  }
4628
4563
  if (isWheelMousePressed) {
4629
4564
  e.cancelBubble = true;
@@ -4632,64 +4567,65 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4632
4567
  }
4633
4568
  this.didMove = true;
4634
4569
  let selectionContainsFrames = false;
4635
- for (let i = 0; i < selectedNodes.length; i++) {
4636
- const node = selectedNodes[i];
4570
+ for (let i = 0; i < this.currentDragSelectedNodes.length; i++) {
4571
+ const node = this.currentDragSelectedNodes[i];
4637
4572
  selectionContainsFrames = selectionContainsFrames || hasFrames(node);
4638
4573
  node.updatePosition(node.getAbsolutePosition());
4639
4574
  }
4640
- if (selectedNodes.length === 1) {
4641
- originalNodes = {};
4642
- originalContainers = {};
4575
+ if (this.currentDragSelectedNodes.length === 1) {
4576
+ this.originalNodes = {};
4577
+ this.originalContainers = {};
4643
4578
  }
4644
- if (this.isSelecting() && selectedNodes.length > 1) {
4579
+ if (this.callbacks.isSelecting() && this.currentDragSelectedNodes.length > 1) {
4645
4580
  clearContainerTargets(this.instance);
4646
- const layerToMove = containerOverCursor(this.instance, selectedNodes);
4647
- if (this.getUsersPresencePlugin() && this.dragInProcess) {
4648
- for (const node of selectedNodes) {
4581
+ const layerToMove = containerOverCursor(this.instance, this.currentDragSelectedNodes);
4582
+ const usersPresence = this.callbacks.getUsersPresencePlugin();
4583
+ if (usersPresence && this.dragInProcess) {
4584
+ for (const node of this.currentDragSelectedNodes) {
4649
4585
  let parentId = node.getParent()?.id() ?? "";
4650
4586
  const parent = node.getParent();
4651
4587
  if (parent?.getAttrs().nodeId) parentId = parent.getAttrs().nodeId;
4652
- this.getUsersPresencePlugin()?.setPresence(node.id(), parentId, {
4588
+ usersPresence.setPresence(node.id(), parentId, {
4653
4589
  x: node.x(),
4654
4590
  y: node.y()
4655
4591
  }, false);
4656
4592
  }
4657
- this.getUsersPresencePlugin()?.forceSendPresence();
4593
+ usersPresence.forceSendPresence();
4658
4594
  }
4659
4595
  if (layerToMove && !selectionContainsFrames) layerToMove.fire(WEAVE_NODE_CUSTOM_EVENTS.onTargetEnter, { bubbles: true });
4660
4596
  }
4661
- tr.forceUpdate();
4597
+ this.tr.forceUpdate();
4662
4598
  };
4663
- tr.on("dragmove", handleDragMove);
4664
- tr.on("dragend", (e) => {
4599
+ this.tr.on("dragmove", handleDragMove);
4600
+ this.tr.on("dragend", (e) => {
4665
4601
  this.dragInProcess = false;
4666
4602
  const mainLayer = this.instance.getMainLayer();
4667
4603
  if (!mainLayer) return;
4668
4604
  this.instance.getSelectionLayer()?.hitGraphEnabled(true);
4669
4605
  this.instance.getMainLayer()?.hitGraphEnabled(true);
4670
4606
  if (!this.didMove) return;
4671
- if (selectedNodes.length > 1) this.instance.releaseMutexLock();
4607
+ if (this.currentDragSelectedNodes.length > 1) this.instance.releaseMutexLock();
4672
4608
  e.cancelBubble = true;
4673
4609
  this.instance.getHooks().callHook("weave:onTransformerDragEnd", {
4674
4610
  e,
4675
- nodes: selectedNodes
4611
+ nodes: this.currentDragSelectedNodes
4676
4612
  });
4677
4613
  this.instance.getCloningManager().cleanupClones();
4678
- this.getStagePanningPlugin()?.cleanupEdgeMoveIntervals();
4614
+ this.callbacks.getStagePanningPlugin()?.cleanupEdgeMoveIntervals();
4679
4615
  let selectionContainsFrames = false;
4680
- for (let i = 0; i < selectedNodes.length; i++) {
4681
- const node = selectedNodes[i];
4616
+ for (let i = 0; i < this.currentDragSelectedNodes.length; i++) {
4617
+ const node = this.currentDragSelectedNodes[i];
4682
4618
  selectionContainsFrames = selectionContainsFrames || hasFrames(node);
4683
4619
  node.updatePosition(node.getAbsolutePosition());
4684
4620
  }
4685
- if (this.isSelecting() && selectedNodes.length > 1) {
4621
+ if (this.callbacks.isSelecting() && this.currentDragSelectedNodes.length > 1) {
4686
4622
  const toSelect = [];
4687
4623
  const toUpdate = [];
4688
4624
  this.instance.stateTransactional(() => {
4689
4625
  const actualCursor = stage.container().style.cursor;
4690
4626
  stage.container().style.cursor = "wait";
4691
4627
  clearContainerTargets(this.instance);
4692
- const layerToMove = containerOverCursor(this.instance, selectedNodes);
4628
+ const layerToMove = containerOverCursor(this.instance, this.currentDragSelectedNodes);
4693
4629
  const nodeUpdate = (node) => {
4694
4630
  const isLockedToContainer = node.getAttrs().lockToContainer;
4695
4631
  let moved = false;
@@ -4699,18 +4635,17 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4699
4635
  let containerToMove = this.instance.getMainLayer();
4700
4636
  if (layerToMove) containerToMove = layerToMove;
4701
4637
  if (containerToMove && !selectionContainsFrames) {
4702
- moved = moveNodeToContainerNT(this.instance, node, containerToMove, originalNodes[node.getAttrs().id ?? ""], originalContainers[node.getAttrs().id ?? ""]);
4638
+ moved = moveNodeToContainerNT(this.instance, node, containerToMove, this.originalNodes[node.getAttrs().id ?? ""], this.originalContainers[node.getAttrs().id ?? ""]);
4703
4639
  if (moved) this.instance.emitEvent("onNodeChangedContainer", {
4704
- originalNode: originalNodes[node.getAttrs().id ?? ""] ?? null,
4705
- originalContainer: originalContainers[node.getAttrs().id ?? ""] ?? null,
4640
+ originalNode: this.originalNodes[node.getAttrs().id ?? ""] ?? null,
4641
+ originalContainer: this.originalContainers[node.getAttrs().id ?? ""] ?? null,
4706
4642
  newNode: node,
4707
4643
  newContainer: containerToMove
4708
4644
  });
4709
4645
  toSelect.push(node.getAttrs().id ?? "");
4710
- delete originalNodes[node.getAttrs().id ?? ""];
4711
- delete originalContainers[node.getAttrs().id ?? ""];
4712
- } else if (node.getAttrs().nodeId) toSelect.push(node.getAttrs().nodeId ?? "");
4713
- else toSelect.push(node.getAttrs().id ?? "");
4646
+ delete this.originalNodes[node.getAttrs().id ?? ""];
4647
+ delete this.originalContainers[node.getAttrs().id ?? ""];
4648
+ } else toSelect.push(node.getAttrs().nodeId ? node.getAttrs().nodeId ?? "" : node.getAttrs().id ?? "");
4714
4649
  if (containerToMove) containerToMove.fire(WEAVE_NODE_CUSTOM_EVENTS.onTargetLeave, { bubbles: true });
4715
4650
  if (!nodeHandler) return;
4716
4651
  if (!moved) toUpdate.push(nodeHandler.serialize(node));
@@ -4722,14 +4657,14 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4722
4657
  toUpdate.push(nodeHandler.serialize(node));
4723
4658
  }
4724
4659
  };
4725
- for (let i = 0; i < selectedNodes.length; i++) nodeUpdate(selectedNodes[i]);
4660
+ for (let i = 0; i < this.currentDragSelectedNodes.length; i++) nodeUpdate(this.currentDragSelectedNodes[i]);
4726
4661
  if (toUpdate.length > 0) this.instance.updateNodesNT(toUpdate);
4727
4662
  this.instance.runPhaseHooks("onMoveNodesToContainer", (hook) => {
4728
- hook({ nodes: selectedNodes });
4663
+ hook({ nodes: this.currentDragSelectedNodes });
4729
4664
  });
4730
4665
  stage.container().style.cursor = actualCursor;
4731
4666
  });
4732
- for (const node of selectedNodes) node.setAttrs({ isCloned: void 0 });
4667
+ for (const node of this.currentDragSelectedNodes) node.setAttrs({ isCloned: void 0 });
4733
4668
  const finalSelectedNodes = [];
4734
4669
  for (const nodeId of toSelect) {
4735
4670
  const actNode = this.instance.getStage().findOne(`#${nodeId}`);
@@ -4739,17 +4674,19 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4739
4674
  actNode.handleSelectNode();
4740
4675
  }
4741
4676
  }
4742
- this.setSelectedNodes(finalSelectedNodes);
4743
- tr.forceUpdate();
4677
+ this.callbacks.setSelectedNodes(finalSelectedNodes);
4678
+ this.tr.forceUpdate();
4744
4679
  }
4745
4680
  });
4681
+ }
4682
+ registerInstanceEvents() {
4746
4683
  this.instance.addEventListener("onNodesChange", () => {
4747
- const currentSelectedNodes = tr.nodes();
4684
+ const currentSelectedNodes = this.tr.nodes();
4748
4685
  const unselectedNodes = this.prevSelectedNodes.filter((node) => !currentSelectedNodes.map((node1) => node1.getAttrs().id).includes(node.getAttrs().id));
4749
4686
  if (currentSelectedNodes.length > 1) for (const node of currentSelectedNodes) node.handleSelectNode();
4750
4687
  if (currentSelectedNodes.length === 1) currentSelectedNodes[0]?.handleDeselectNode?.();
4751
4688
  for (const node of unselectedNodes) node.handleDeselectNode();
4752
- this.prevSelectedNodes = tr.nodes();
4689
+ this.prevSelectedNodes = this.tr.nodes();
4753
4690
  });
4754
4691
  this.instance.addEventListener("onUndoChange", () => {
4755
4692
  this.handleUndoRedoSelectionChange();
@@ -4757,9 +4694,541 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4757
4694
  this.instance.addEventListener("onRedoChange", () => {
4758
4695
  this.handleUndoRedoSelectionChange();
4759
4696
  });
4760
- this.tr = tr;
4761
- this.trHover = trHover;
4762
- this.selectionRectangle = selectionRectangle;
4697
+ }
4698
+ handleUndoRedoSelectionChange() {
4699
+ const selectionLayer = this.instance.getSelectionLayer();
4700
+ const selectionFeedbackPlugin = this.callbacks.getNodesSelectionFeedbackPlugin();
4701
+ if (selectionLayer && selectionFeedbackPlugin) {
4702
+ selectionLayer.find(`.selection-halo`).forEach((node) => node.destroy());
4703
+ selectionFeedbackPlugin.cleanupSelectedHalos();
4704
+ const currentSelectedNodes = this.tr.nodes();
4705
+ if (currentSelectedNodes.length > 1) for (const node of currentSelectedNodes) node.handleSelectNode();
4706
+ if (currentSelectedNodes.length === 1) currentSelectedNodes[0].handleDeselectNode();
4707
+ this.prevSelectedNodes = currentSelectedNodes;
4708
+ }
4709
+ }
4710
+ };
4711
+
4712
+ //#endregion
4713
+ //#region src/plugins/context-menu/constants.ts
4714
+ const WEAVE_CONTEXT_MENU_PLUGIN_KEY = "contextMenu";
4715
+ const WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT = 4;
4716
+ const WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT = 4;
4717
+ const WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT = 500;
4718
+
4719
+ //#endregion
4720
+ //#region src/plugins/stage-grid/constants.ts
4721
+ const WEAVE_STAGE_GRID_PLUGIN_KEY = "stageGrid";
4722
+ const WEAVE_GRID_TYPES = {
4723
+ ["LINES"]: "lines",
4724
+ ["DOTS"]: "dots"
4725
+ };
4726
+ const WEAVE_GRID_DOT_TYPES = {
4727
+ ["SQUARE"]: "square",
4728
+ ["CIRCLE"]: "circle"
4729
+ };
4730
+ const WEAVE_GRID_DEFAULT_CONFIG = {
4731
+ type: WEAVE_GRID_TYPES.LINES,
4732
+ gridColor: "#b3b3b3",
4733
+ gridMajorColor: "#b3b3b3",
4734
+ gridOriginColor: "#ff746c",
4735
+ gridSize: 20,
4736
+ gridMajorEvery: 10,
4737
+ gridMajorRatio: 2,
4738
+ gridStroke: 1,
4739
+ gridDotType: WEAVE_GRID_DOT_TYPES.CIRCLE,
4740
+ gridDotRadius: 1,
4741
+ gridDotRectSize: 2
4742
+ };
4743
+ const WEAVE_GRID_LAYER_ID = "gridLayer";
4744
+
4745
+ //#endregion
4746
+ //#region src/plugins/stage-panning/constants.ts
4747
+ const WEAVE_STAGE_PANNING_KEY = "stagePanning";
4748
+ const WEAVE_STAGE_PANNING_THROTTLE_MS = 20;
4749
+ const WEAVE_STAGE_PANNING_DEFAULT_CONFIG = { edgePan: {
4750
+ offset: 25,
4751
+ speed: 20
4752
+ } };
4753
+
4754
+ //#endregion
4755
+ //#region src/plugins/nodes-multi-selection-feedback/constants.ts
4756
+ const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY = "nodesMultiSelectionFeedback";
4757
+ const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID = "selectionLayer";
4758
+ const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG = { style: {
4759
+ stroke: "#ff2c2cff",
4760
+ strokeWidth: 2,
4761
+ fill: "transparent"
4762
+ } };
4763
+
4764
+ //#endregion
4765
+ //#region src/plugins/users-presence/constants.ts
4766
+ const WEAVE_USER_PRESENCE_KEY = "userPresence";
4767
+ const WEAVE_USERS_PRESENCE_PLUGIN_KEY = "usersPresence";
4768
+ const WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS = { awarenessThrottleMs: DEFAULT_THROTTLE_MS };
4769
+
4770
+ //#endregion
4771
+ //#region src/plugins/nodes-selection/plugin-accessors.ts
4772
+ function getContextMenuPlugin(instance) {
4773
+ return instance.getPlugin(WEAVE_CONTEXT_MENU_PLUGIN_KEY);
4774
+ }
4775
+ function getStageGridPlugin(instance) {
4776
+ return instance.getPlugin(WEAVE_STAGE_GRID_PLUGIN_KEY);
4777
+ }
4778
+ function getStagePanningPlugin(instance) {
4779
+ return instance.getPlugin(WEAVE_STAGE_PANNING_KEY);
4780
+ }
4781
+ function getNodesSelectionFeedbackPlugin(instance) {
4782
+ return instance.getPlugin(WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY);
4783
+ }
4784
+ function getUsersPresencePlugin(instance) {
4785
+ return instance.getPlugin(WEAVE_USERS_PRESENCE_PLUGIN_KEY);
4786
+ }
4787
+
4788
+ //#endregion
4789
+ //#region src/plugins/nodes-selection/events/click-tap.ts
4790
+ /**
4791
+ * Handles a single click or tap on the canvas: resolves the targeted node,
4792
+ * applies single/multi-selection logic, and triggers the selection-change
4793
+ * event. Called from both pointerdown (immediate click) and pointerup
4794
+ * (after area-selection ends with a tap).
4795
+ */
4796
+ function handleClickOrTap(ctx, e) {
4797
+ const weave = ctx.getWeaveInstance();
4798
+ const stage = weave.getStage();
4799
+ const tr = ctx.getTransformerController().getTransformer();
4800
+ ctx.setClickOrTapHandled(true);
4801
+ e.cancelBubble = true;
4802
+ if (!ctx.isEnabled()) return;
4803
+ if (weave.getActiveAction() !== SELECTION_TOOL_ACTION_NAME) return;
4804
+ const contextMenuPlugin = ctx.getContextMenuPlugin();
4805
+ if (contextMenuPlugin?.isContextMenuVisible()) ctx.getEdgePanning().stop();
4806
+ ctx.hideHoverState();
4807
+ const selectedGroup = getTargetedNode(weave);
4808
+ if (!ctx.isInitialized()) return;
4809
+ if (e.evt.pointerType === "mouse" && e.evt?.button && e.evt?.button !== 0) return;
4810
+ let areNodesSelected = false;
4811
+ let nodeTargeted = selectedGroup && !(selectedGroup.getAttrs().active ?? false) ? selectedGroup : e.target;
4812
+ if (e.target === weave.getStage()) {
4813
+ ctx.getGesture().resetDoubleTap();
4814
+ ctx.getNodesSelectionFeedbackPlugin()?.cleanupSelectedHalos();
4815
+ return;
4816
+ }
4817
+ nodeTargeted = weave.getRealSelectedNode(nodeTargeted);
4818
+ if (!nodeTargeted.getAttrs().nodeType) {
4819
+ ctx.getGesture().resetDoubleTap();
4820
+ return;
4821
+ }
4822
+ const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
4823
+ const nodeSelectedIndex = tr.nodes().findIndex((node) => {
4824
+ return node.getAttrs().id === nodeTargeted.getAttrs().id;
4825
+ });
4826
+ const isSelected = nodeSelectedIndex !== -1;
4827
+ const user = weave.getStore().getUser();
4828
+ const isLocked = nodeTargeted.getAttrs().locked ?? false;
4829
+ const isMutexLocked = nodeTargeted.getAttrs().mutexLocked && nodeTargeted.getAttrs().mutexUserId !== user.id;
4830
+ if (isLocked || isMutexLocked) {
4831
+ const parent = weave.getInstanceRecursive(nodeTargeted.getParent());
4832
+ const mainLayer = weave.getMainLayer();
4833
+ const isStage = parent instanceof Konva.Stage;
4834
+ const isMainLayer = parent === mainLayer;
4835
+ const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
4836
+ if (isStage || isMainLayer || isContainerEmptyArea) ctx.setSelectedNodes([]);
4837
+ return;
4838
+ }
4839
+ if (nodeTargeted.getAttrs().nodeId) {
4840
+ const realNode = stage.findOne(`#${nodeTargeted.getAttrs().nodeId}`);
4841
+ if (realNode) nodeTargeted = realNode;
4842
+ }
4843
+ if (typeof nodeTargeted.getAttrs().isContainerPrincipal !== "undefined" && !nodeTargeted.getAttrs().isContainerPrincipal) return;
4844
+ if (ctx.getGesture().isDoubleTap && !metaPressed) {
4845
+ ctx.getGesture().resetDoubleTap();
4846
+ nodeTargeted.dblClick();
4847
+ return;
4848
+ }
4849
+ const isCtrlOrCmdPressed = e.evt.ctrlKey || e.evt.metaKey;
4850
+ if (isCtrlOrCmdPressed) return;
4851
+ if (!metaPressed) {
4852
+ tr.nodes([nodeTargeted]);
4853
+ tr.show();
4854
+ areNodesSelected = true;
4855
+ }
4856
+ if (metaPressed && isSelected) {
4857
+ const nodes = tr.nodes().slice();
4858
+ nodes.splice(nodes.indexOf(nodeTargeted), 1);
4859
+ tr.nodes(nodes);
4860
+ areNodesSelected = true;
4861
+ }
4862
+ if (metaPressed && !isSelected) {
4863
+ tr.nodes(tr.nodes().concat([nodeTargeted]));
4864
+ areNodesSelected = true;
4865
+ }
4866
+ ctx.handleMultipleSelectionBehavior();
4867
+ ctx.handleBehaviors();
4868
+ if (areNodesSelected) {
4869
+ stage.container().tabIndex = 1;
4870
+ stage.container().focus();
4871
+ stage.container().style.cursor = (typeof nodeTargeted?.defineMousePointer === "function" ? nodeTargeted.defineMousePointer() : null) ?? "grab";
4872
+ }
4873
+ ctx.triggerSelectedNodesEvent();
4874
+ }
4875
+
4876
+ //#endregion
4877
+ //#region src/plugins/nodes-selection/events/keyboard.ts
4878
+ /**
4879
+ * Registers keydown/keyup listeners on the stage container.
4880
+ * Space key toggles the panning-override flag; Backspace/Delete removes
4881
+ * the currently selected nodes.
4882
+ */
4883
+ function registerKeyboardHandlers(ctx) {
4884
+ const stage = ctx.getWeaveInstance().getStage();
4885
+ const signal = ctx.getWeaveInstance().getEventsController().signal;
4886
+ stage.container().addEventListener("keydown", (e) => {
4887
+ if (e.code === "Space") ctx.setSpaceKeyPressed(true);
4888
+ if (e.code === "Backspace" || e.code === "Delete") {
4889
+ Promise.resolve().then(() => {
4890
+ ctx.removeSelectedNodes();
4891
+ });
4892
+ return;
4893
+ }
4894
+ }, { signal });
4895
+ stage.container().addEventListener("keyup", (e) => {
4896
+ if (e.code === "Space") ctx.setSpaceKeyPressed(false);
4897
+ }, { signal });
4898
+ }
4899
+
4900
+ //#endregion
4901
+ //#region src/plugins/nodes-selection/events/pointer-down.ts
4902
+ /**
4903
+ * Handles the stage `pointerdown` event: records pointer state, decides
4904
+ * whether to start an area-selection or delegate to a click/tap handler.
4905
+ */
4906
+ function handlePointerDown(ctx, e) {
4907
+ ctx.getGesture().setTapStart(e.evt.clientX, e.evt.clientY);
4908
+ if (e.target.getClassName().includes("custom-snap-guide")) return;
4909
+ ctx.setClickOrTapHandled(false);
4910
+ ctx.registerPointer(e.evt.pointerId, e.evt);
4911
+ if (e.evt.pointerType === "touch" && ctx.getPointerCount() > 1) return;
4912
+ if (e.evt.pointerType === "mouse" && e.evt?.button !== 0) return;
4913
+ if (e.evt.pointerType === "pen" && e.evt?.pressure <= .05) return;
4914
+ if (!ctx.isInitialized()) return;
4915
+ if (!ctx.isActive()) return;
4916
+ const stage = ctx.getWeaveInstance().getStage();
4917
+ if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
4918
+ const selectedGroup = getTargetedNode(ctx.getWeaveInstance());
4919
+ if (selectedGroup?.getParent() instanceof Konva.Transformer) {
4920
+ ctx.setAreaSelecting(false);
4921
+ ctx.getEdgePanning().stop();
4922
+ ctx.getAreaSelector().hide();
4923
+ return;
4924
+ }
4925
+ const isStage = e.target instanceof Konva.Stage;
4926
+ const isTransformer = e.target?.getParent() instanceof Konva.Transformer;
4927
+ const canBeTargeted = e.target.getAttrs().canBeTargeted !== false;
4928
+ const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
4929
+ if (isTransformer) return;
4930
+ if (!isStage && !isContainerEmptyArea && canBeTargeted) {
4931
+ ctx.setAreaSelecting(false);
4932
+ ctx.getEdgePanning().stop();
4933
+ ctx.getAreaSelector().hide();
4934
+ handleClickOrTap(ctx, e);
4935
+ return;
4936
+ }
4937
+ ctx.getEdgePanning().reset();
4938
+ const relPos = stage.getRelativePointerPosition() ?? {
4939
+ x: 0,
4940
+ y: 0
4941
+ };
4942
+ ctx.getAreaSelector().setStart(relPos.x, relPos.y);
4943
+ ctx.getAreaSelector().resetForScale(stage.scaleX(), ctx.getConfiguration().selectionArea);
4944
+ ctx.setAreaSelecting(true);
4945
+ const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
4946
+ if (isCtrlOrMetaPressed) {
4947
+ const tr = ctx.getTransformerController().getTransformer();
4948
+ const nodesSelected = tr.nodes();
4949
+ for (const node of nodesSelected) node.fire("onSelectionCleared", { bubbles: true });
4950
+ }
4951
+ ctx.selectNone();
4952
+ ctx.getWeaveInstance().emitEvent("onSelectionState", true);
4953
+ ctx.getEdgePanning().start();
4954
+ }
4955
+
4956
+ //#endregion
4957
+ //#region src/plugins/nodes-selection/events/pointer-move.ts
4958
+ /**
4959
+ * Handles the stage `pointermove` event: cancels long-press timers when
4960
+ * the pointer moves, hides the selection rect when no movement, and
4961
+ * updates the area-selection rectangle and edge-panning direction while
4962
+ * a selection drag is in progress.
4963
+ */
4964
+ function handlePointerMove(ctx, e) {
4965
+ if (!e?.evt) return;
4966
+ const moved = ctx.getGesture().checkMoved(e.evt.clientX, e.evt.clientY);
4967
+ if (e.evt?.buttons === 0) return;
4968
+ if (e.evt.pointerType === "touch" && ctx.getPointerCount() > 1) return;
4969
+ if (!ctx.isInitialized()) return;
4970
+ if (!ctx.isActive()) return;
4971
+ const contextMenuPlugin = ctx.getContextMenuPlugin();
4972
+ if (moved) contextMenuPlugin?.cancelLongPressTimer();
4973
+ else ctx.getAreaSelector().hide();
4974
+ if (contextMenuPlugin?.isContextMenuVisible()) ctx.getEdgePanning().stop();
4975
+ if (ctx.getSpaceKeyPressedState()) return;
4976
+ if (!ctx.isAreaSelecting()) return;
4977
+ ctx.getAreaSelector().update(ctx.getWeaveInstance().getStage(), () => ctx.selectNone());
4978
+ ctx.getEdgePanning().updateDirection();
4979
+ }
4980
+
4981
+ //#endregion
4982
+ //#region src/plugins/nodes-selection/events/pointer-up.ts
4983
+ /**
4984
+ * Handles the stage `pointerup` event: ends any in-progress area-selection
4985
+ * (including the node-filtering/commit step), or delegates to the click/tap
4986
+ * handler for point interactions.
4987
+ */
4988
+ function handlePointerUp(ctx, e) {
4989
+ const weave = ctx.getWeaveInstance();
4990
+ const stage = weave.getStage();
4991
+ const store = weave.getStore();
4992
+ const actUser = store.getUser();
4993
+ const tr = ctx.getTransformerController().getTransformer();
4994
+ tr.setAttrs({ listening: true });
4995
+ ctx.setAreaSelecting(false);
4996
+ ctx.getEdgePanning().stop();
4997
+ const moved = ctx.getGesture().checkMoved(e.evt.clientX, e.evt.clientY);
4998
+ ctx.getGesture().checkDoubleTap(e.evt.clientX, e.evt.clientY);
4999
+ ctx.unregisterPointer(e.evt.pointerId);
5000
+ ctx.getGesture().commitTap();
5001
+ if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
5002
+ const contextMenuPlugin = ctx.getContextMenuPlugin();
5003
+ if (!ctx.isInitialized()) {
5004
+ ctx.getAreaSelector().hide();
5005
+ return;
5006
+ }
5007
+ if (!ctx.isActive()) {
5008
+ ctx.getAreaSelector().hide();
5009
+ return;
5010
+ }
5011
+ weave.emitEvent("onSelectionState", false);
5012
+ if (ctx.getGesture().isDoubleTap) {
5013
+ ctx.getAreaSelector().hide();
5014
+ handleClickOrTap(ctx, e);
5015
+ return;
5016
+ }
5017
+ const isStage = e.target instanceof Konva.Stage;
5018
+ const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5019
+ if ((isStage || isContainerEmptyArea) && !moved) {
5020
+ ctx.setAreaSelecting(false);
5021
+ ctx.getEdgePanning().stop();
5022
+ ctx.getAreaSelector().hide();
5023
+ ctx.setSelectedNodes([]);
5024
+ return;
5025
+ }
5026
+ if (e.evt.pointerType === "touch" && ctx.getPointerCount() + 1 > 1) {
5027
+ ctx.getAreaSelector().hide();
5028
+ return;
5029
+ }
5030
+ if (contextMenuPlugin?.isContextMenuVisible()) ctx.getEdgePanning().stop();
5031
+ const selectedGroup = getTargetedNode(weave);
5032
+ if (!moved && selectedGroup?.getParent() instanceof Konva.Transformer && !ctx.wasClickOrTapHandled()) {
5033
+ ctx.setAreaSelecting(false);
5034
+ ctx.getEdgePanning().stop();
5035
+ ctx.getAreaSelector().hide();
5036
+ handleClickOrTap(ctx, e);
5037
+ return;
5038
+ }
5039
+ if (!ctx.getAreaSelector().getRect().visible()) {
5040
+ ctx.getAreaSelector().hide();
5041
+ return;
5042
+ }
5043
+ const shapes = stage.find((node) => {
5044
+ return ["Shape", "Group"].includes(node.getType()) && typeof node.getAttrs().id !== "undefined";
5045
+ });
5046
+ const box = ctx.getAreaSelector().getBox();
5047
+ ctx.getAreaSelector().getRect().visible(false);
5048
+ const selected = shapes.filter((shape) => {
5049
+ const shapeMutex = weave.getNodeMutexLock(shape.id());
5050
+ if (shapeMutex && shapeMutex.user.id !== actUser.id) return false;
5051
+ let parent = weave.getInstanceRecursive(shape.getParent());
5052
+ if (parent.getAttrs().nodeId) parent = stage.findOne(`#${parent.getAttrs().nodeId}`);
5053
+ if (shape.getAttrs().nodeType && shape.getAttrs().nodeType === "frame") {
5054
+ const frameBox = shape.getClientRect();
5055
+ return frameBox.x >= box.x && frameBox.y >= box.y && frameBox.x + frameBox.width <= box.x + box.width && frameBox.y + frameBox.height <= box.y + box.height;
5056
+ }
5057
+ if (shape.getAttrs().nodeType && shape?.getAttrs().nodeType === "group" && ["layer", "frame"].includes(parent?.getAttrs().nodeType)) return shape.getAttrs().nodeType && Konva.Util.haveIntersection(box, shape.getClientRect());
5058
+ if (shape.getAttrs().nodeType && shape.getAttrs().nodeType !== "group" && ["layer", "frame"].includes(parent?.getAttrs().nodeType)) return shape.getAttrs().nodeType && Konva.Util.haveIntersection(box, shape.getClientRect());
5059
+ return false;
5060
+ });
5061
+ const selectedNodes = new Set();
5062
+ const containerNodesIds = [];
5063
+ const otherNodes = [];
5064
+ for (const node of selected) {
5065
+ let realNode = node;
5066
+ if (node.getAttrs().nodeId) realNode = stage.findOne(`#${node.getAttrs().nodeId}`);
5067
+ if (!realNode) continue;
5068
+ const isContainer = typeof realNode.getAttrs().isContainerPrincipal !== "undefined" && realNode.getAttrs().isContainerPrincipal;
5069
+ if (isContainer) {
5070
+ containerNodesIds.push(realNode.getAttrs().id ?? "");
5071
+ if (!realNode.getAttrs().locked) selectedNodes.add(realNode);
5072
+ } else otherNodes.push(realNode);
5073
+ }
5074
+ for (const node of otherNodes) {
5075
+ let parent = weave.getInstanceRecursive(node.getParent());
5076
+ if (parent?.getAttrs().nodeId) parent = stage.findOne(`#${parent.getAttrs().nodeId}`);
5077
+ if (parent && !containerNodesIds.includes(parent?.getAttrs().id ?? "") && !node.getAttrs().locked) selectedNodes.add(node);
5078
+ }
5079
+ ctx.setAreaSelecting(false);
5080
+ ctx.getEdgePanning().stop();
5081
+ tr.nodes([...selectedNodes]);
5082
+ ctx.handleMultipleSelectionBehavior();
5083
+ ctx.handleBehaviors();
5084
+ if (tr.nodes().length > 0) {
5085
+ stage.container().tabIndex = 1;
5086
+ stage.container().focus();
5087
+ }
5088
+ ctx.triggerSelectedNodesEvent();
5089
+ }
5090
+
5091
+ //#endregion
5092
+ //#region src/plugins/nodes-selection/nodes-selection.ts
5093
+ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5094
+ gesture = new GestureDetector();
5095
+ _handledClickOrTap = false;
5096
+ dragSelectedNodes = [];
5097
+ constructor(params) {
5098
+ super();
5099
+ this.config = mergeExceptArrays(WEAVE_NODES_SELECTION_DEFAULT_CONFIG, params?.config ?? {});
5100
+ this.initialize();
5101
+ }
5102
+ initialize() {
5103
+ this._defaultEnabledAnchors = this.config.selection?.enabledAnchors ?? [
5104
+ "top-left",
5105
+ "top-center",
5106
+ "top-right",
5107
+ "middle-right",
5108
+ "middle-left",
5109
+ "bottom-left",
5110
+ "bottom-center",
5111
+ "bottom-right"
5112
+ ];
5113
+ this.gesture.reset();
5114
+ this._isSpaceKeyPressed = false;
5115
+ this.active = false;
5116
+ this.selecting = false;
5117
+ this.initialized = false;
5118
+ this.enabled = false;
5119
+ this.pointers = {};
5120
+ this.dragSelectedNodes = [];
5121
+ }
5122
+ getName() {
5123
+ return WEAVE_NODES_SELECTION_KEY;
5124
+ }
5125
+ getLayerName() {
5126
+ return WEAVE_NODES_SELECTION_LAYER_ID;
5127
+ }
5128
+ getConfiguration() {
5129
+ return this.config;
5130
+ }
5131
+ getWeaveInstance() {
5132
+ return this.instance;
5133
+ }
5134
+ getGesture() {
5135
+ return this.gesture;
5136
+ }
5137
+ getAreaSelector() {
5138
+ return this.areaSelector;
5139
+ }
5140
+ getEdgePanning() {
5141
+ return this.edgePanning;
5142
+ }
5143
+ getTransformerController() {
5144
+ return this.transformerCtrl;
5145
+ }
5146
+ getDefaultEnabledAnchors() {
5147
+ return this._defaultEnabledAnchors;
5148
+ }
5149
+ isInitialized() {
5150
+ return this.initialized;
5151
+ }
5152
+ isActive() {
5153
+ return this.active;
5154
+ }
5155
+ getSpaceKeyPressedState() {
5156
+ return this._isSpaceKeyPressed;
5157
+ }
5158
+ setSpaceKeyPressed(val) {
5159
+ this._isSpaceKeyPressed = val;
5160
+ }
5161
+ getPointerCount() {
5162
+ return Object.keys(this.pointers).length;
5163
+ }
5164
+ registerPointer(id, evt) {
5165
+ this.pointers[id] = evt;
5166
+ }
5167
+ unregisterPointer(id) {
5168
+ delete this.pointers[id];
5169
+ }
5170
+ wasClickOrTapHandled() {
5171
+ return this._handledClickOrTap;
5172
+ }
5173
+ setClickOrTapHandled(val) {
5174
+ this._handledClickOrTap = val;
5175
+ }
5176
+ setAreaSelecting(val) {
5177
+ this.selecting = val;
5178
+ }
5179
+ initLayer() {
5180
+ const stage = this.instance.getStage();
5181
+ const layer = new Konva.Layer({ id: this.getLayerName() });
5182
+ stage.add(layer);
5183
+ }
5184
+ isPasting() {
5185
+ const copyPastePlugin = this.instance.getPlugin("copyPasteNodes");
5186
+ if (!copyPastePlugin) return false;
5187
+ return copyPastePlugin.isPasting();
5188
+ }
5189
+ isAreaSelecting() {
5190
+ return this.selecting;
5191
+ }
5192
+ isSelecting() {
5193
+ return this.instance.getActiveAction() === SELECTION_TOOL_ACTION_NAME;
5194
+ }
5195
+ isNodeSelected(ele) {
5196
+ return this.getSelectedNodes().length === 1 && this.getSelectedNodes()[0].getAttrs().id === ele.getAttrs().id;
5197
+ }
5198
+ onInit() {
5199
+ const stage = this.instance.getStage();
5200
+ const selectionLayer = this.getLayer();
5201
+ stage.container().tabIndex = 1;
5202
+ stage.container().focus();
5203
+ this.areaSelector = new AreaSelector();
5204
+ this.areaSelector.init(selectionLayer, this.config.selectionArea, stage.scaleX());
5205
+ this.edgePanning = new EdgePanning(this.config.panningWhenSelection, {
5206
+ getStage: () => this.instance.getStage(),
5207
+ isSelecting: () => this.isAreaSelecting(),
5208
+ onTick: (dx, dy) => {
5209
+ if (this.areaSelector.selectionStart) {
5210
+ this.areaSelector.selectionStart.x += dx;
5211
+ this.areaSelector.selectionStart.y += dy;
5212
+ }
5213
+ this.getStageGridPlugin()?.onRender();
5214
+ this.areaSelector.update(this.instance.getStage(), () => this.selectNone());
5215
+ }
5216
+ });
5217
+ const callbacks = {
5218
+ isSelecting: () => this.isSelecting(),
5219
+ setSelectedNodes: (nodes) => this.setSelectedNodes(nodes),
5220
+ triggerSelectedNodesEvent: () => this.triggerSelectedNodesEvent(),
5221
+ saveDragSelectedNodes: () => this.saveDragSelectedNodes(),
5222
+ setNodesOpacityOnDrag: () => this.setNodesOpacityOnDrag(),
5223
+ disablePlugin: () => this.disable(),
5224
+ enablePlugin: () => this.enable(),
5225
+ getContextMenuPlugin: () => this.getContextMenuPlugin(),
5226
+ getUsersPresencePlugin: () => this.getUsersPresencePlugin(),
5227
+ getStagePanningPlugin: () => this.getStagePanningPlugin(),
5228
+ getNodesSelectionFeedbackPlugin: () => this.getNodesSelectionFeedbackPlugin()
5229
+ };
5230
+ this.transformerCtrl = new TransformerController(this.instance, this.config, this.gesture, callbacks);
5231
+ this.transformerCtrl.setup(selectionLayer);
4763
5232
  this.initEvents();
4764
5233
  this.initialized = true;
4765
5234
  this.instance.addEventListener("onActiveActionChange", (activeAction) => {
@@ -4770,39 +5239,21 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4770
5239
  this.active = true;
4771
5240
  });
4772
5241
  this.instance.addEventListener("onNodeRemoved", (node) => {
4773
- const selectedNodes$1 = this.getSelectedNodes();
4774
- const newSelectedNodes = selectedNodes$1.filter((actNode) => {
4775
- return actNode.getAttrs().id !== node.id;
4776
- });
5242
+ const selectedNodes = this.getSelectedNodes();
5243
+ const newSelectedNodes = selectedNodes.filter((actNode) => actNode.getAttrs().id !== node.id);
4777
5244
  this.setSelectedNodes(newSelectedNodes);
4778
5245
  stage.container().tabIndex = 1;
4779
5246
  stage.container().focus();
4780
- stage.container().style.cursor = "default";
4781
- });
4782
- }
4783
- handleUndoRedoSelectionChange() {
4784
- const selectionLayer = this.instance.getSelectionLayer();
4785
- const selectionFeedbackPlugin = this.getNodesSelectionFeedbackPlugin();
4786
- if (selectionLayer && selectionFeedbackPlugin) {
4787
- selectionLayer.find(`.selection-halo`).forEach((node) => node.destroy());
4788
- selectionFeedbackPlugin.cleanupSelectedHalos();
4789
- const currentSelectedNodes = this.tr.nodes();
4790
- if (currentSelectedNodes.length > 1) for (const node of currentSelectedNodes) node.handleSelectNode();
4791
- if (currentSelectedNodes.length === 1) currentSelectedNodes[0].handleDeselectNode();
4792
- this.prevSelectedNodes = currentSelectedNodes;
4793
- }
5247
+ stage.container().style.cursor = "default";
5248
+ });
4794
5249
  }
4795
5250
  getLayer() {
4796
5251
  const stage = this.instance.getStage();
4797
5252
  return stage.findOne(`#${this.getLayerName()}`);
4798
5253
  }
4799
5254
  triggerSelectedNodesEvent() {
4800
- this.serializeSelectedNodes();
4801
- this.triggerSelectionAwarenessEvent();
4802
- this.triggerOnNodesChangeEvent();
4803
- }
4804
- serializeSelectedNodes() {
4805
- const selectedNodes = this.tr.getNodes().map((node) => {
5255
+ const tr = this.transformerCtrl.getTransformer();
5256
+ const selectedNodes = tr.getNodes().map((node) => {
4806
5257
  const nodeType = node.getAttr("nodeType");
4807
5258
  const nodeHandler = this.instance.getNodeHandler(nodeType);
4808
5259
  return {
@@ -4810,17 +5261,12 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4810
5261
  node: nodeHandler?.serialize(node)
4811
5262
  };
4812
5263
  });
4813
- this.serializedSelectedNodes = selectedNodes;
4814
- }
4815
- triggerSelectionAwarenessEvent() {
4816
5264
  const usersSelectionPlugin = this.instance.getPlugin(WEAVE_USERS_SELECTION_KEY);
4817
5265
  if (usersSelectionPlugin) requestAnimationFrame(() => {
4818
- usersSelectionPlugin.sendSelectionAwarenessInfo(this.tr);
5266
+ usersSelectionPlugin.sendSelectionAwarenessInfo(tr);
4819
5267
  });
4820
- }
4821
- triggerOnNodesChangeEvent() {
4822
5268
  requestAnimationFrame(() => {
4823
- this.instance.emitEvent("onNodesChange", this.serializedSelectedNodes);
5269
+ this.instance.emitEvent("onNodesChange", selectedNodes);
4824
5270
  });
4825
5271
  }
4826
5272
  removeElement(element) {
@@ -4840,334 +5286,13 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4840
5286
  this.selectNone();
4841
5287
  this.triggerSelectedNodesEvent();
4842
5288
  }
4843
- updateSelectionRect() {
4844
- const stage = this.instance.getStage();
4845
- this.x2 = stage.getRelativePointerPosition()?.x ?? 0;
4846
- this.y2 = stage.getRelativePointerPosition()?.y ?? 0;
4847
- this.selectNone();
4848
- this.selectionRectangle.setAttrs({
4849
- visible: true,
4850
- x: Math.min(this.x1, this.x2),
4851
- y: Math.min(this.y1, this.y2),
4852
- width: Math.abs(this.x2 - this.x1),
4853
- height: Math.abs(this.y2 - this.y1)
4854
- });
4855
- }
4856
- getSpeedFromEdge(distanceFromEdge) {
4857
- const stage = this.instance.getStage();
4858
- const scaledDistance = distanceFromEdge / stage.scaleX();
4859
- if (scaledDistance < this.config.panningWhenSelection.edgeThreshold) {
4860
- const factor = 1 - scaledDistance / this.config.panningWhenSelection.edgeThreshold;
4861
- return this.config.panningWhenSelection.minScrollSpeed + (this.config.panningWhenSelection.maxScrollSpeed - this.config.panningWhenSelection.minScrollSpeed) * factor;
4862
- }
4863
- return 0;
4864
- }
4865
- updatePanDirection() {
4866
- const stage = this.instance.getStage();
4867
- const pos = stage.getPointerPosition();
4868
- const viewWidth = stage.width();
4869
- const viewHeight = stage.height();
4870
- if (!pos) return;
4871
- const distLeft = pos.x;
4872
- const distRight = viewWidth - pos.x;
4873
- const distTop = pos.y;
4874
- const distBottom = viewHeight - pos.y;
4875
- this.panDirection.x = 0;
4876
- this.panDirection.y = 0;
4877
- this.panSpeed = {
4878
- x: 0,
4879
- y: 0
4880
- };
4881
- if (distLeft < this.config.panningWhenSelection.edgeThreshold) {
4882
- this.panDirection.x = 1;
4883
- this.panSpeed.x = this.getSpeedFromEdge(distLeft);
4884
- } else if (distRight < this.config.panningWhenSelection.edgeThreshold) {
4885
- this.panDirection.x = -1;
4886
- this.panSpeed.x = this.getSpeedFromEdge(distRight);
4887
- }
4888
- if (distTop < this.config.panningWhenSelection.edgeThreshold) {
4889
- this.panDirection.y = 1;
4890
- this.panSpeed.y = this.getSpeedFromEdge(distTop);
4891
- } else if (distBottom < this.config.panningWhenSelection.edgeThreshold) {
4892
- this.panDirection.y = -1;
4893
- this.panSpeed.y = this.getSpeedFromEdge(distBottom);
4894
- }
4895
- }
4896
- stopPanLoop() {
4897
- if (this.panLoopId) {
4898
- cancelAnimationFrame(this.panLoopId);
4899
- this.panLoopId = null;
4900
- }
4901
- }
4902
- panLoop() {
4903
- const stage = this.instance.getStage();
4904
- if (this.isAreaSelecting() && (this.panDirection.x !== 0 || this.panDirection.y !== 0)) {
4905
- const scale = stage.scaleX();
4906
- const stepX = (this.panSpeed.x || 0) / scale;
4907
- const stepY = (this.panSpeed.y || 0) / scale;
4908
- stage.x(stage.x() + this.panDirection.x * stepX);
4909
- stage.y(stage.y() + this.panDirection.y * stepY);
4910
- if (this.selectionStart) {
4911
- this.selectionStart.x += this.panDirection.x * stepX;
4912
- this.selectionStart.y += this.panDirection.y * stepY;
4913
- }
4914
- this.getStageGridPlugin()?.onRender();
4915
- this.updateSelectionRect();
4916
- }
4917
- if (this.isAreaSelecting()) this.panLoopId = requestAnimationFrame(() => this.panLoop());
4918
- }
4919
- setTapStart(e) {
4920
- this.taps = this.taps + 1;
4921
- this.tapStart = {
4922
- x: e.evt.clientX,
4923
- y: e.evt.clientY,
4924
- time: performance.now()
4925
- };
4926
- }
4927
- checkMovedDrag(init, actual) {
4928
- if (!this.tapStart) return false;
4929
- const dx = actual.x - init.x;
4930
- const dy = actual.y - init.y;
4931
- const dist = Math.hypot(dx, dy);
4932
- const MOVED_DISTANCE = 5;
4933
- if (dist <= MOVED_DISTANCE) return false;
4934
- return true;
4935
- }
4936
- checkMoved(e) {
4937
- if (!this.tapStart) return false;
4938
- const dx = e.evt.clientX - this.tapStart.x;
4939
- const dy = e.evt.clientY - this.tapStart.y;
4940
- const dist = Math.hypot(dx, dy);
4941
- const MOVED_DISTANCE = 5;
4942
- if (dist <= MOVED_DISTANCE) return false;
4943
- return true;
4944
- }
4945
- checkDoubleTap(e) {
4946
- if (!this.previousTap) return;
4947
- const now$2 = performance.now();
4948
- const dx = e.evt.clientX - this.previousTap.x;
4949
- const dy = e.evt.clientY - this.previousTap.y;
4950
- const dist = Math.hypot(dx, dy);
4951
- const DOUBLE_TAP_DISTANCE = 10;
4952
- const DOUBLE_TAP_TIME = 300;
4953
- if (this.tapTimeoutId) clearTimeout(this.tapTimeoutId);
4954
- this.tapTimeoutId = setTimeout(() => {
4955
- this.taps = 0;
4956
- }, DOUBLE_TAP_TIME + 5);
4957
- if (this.taps > 1 && now$2 - this.previousTap.time < DOUBLE_TAP_TIME && dist < DOUBLE_TAP_DISTANCE) {
4958
- this.taps = 0;
4959
- this.tapStart = null;
4960
- this.isDoubleTap = true;
4961
- }
4962
- }
4963
- hideSelectorArea() {
4964
- this.selectionRectangle.setAttrs({
4965
- width: 0,
4966
- height: 0,
4967
- visible: false
4968
- });
4969
- }
4970
5289
  initEvents() {
4971
5290
  this.selecting = false;
4972
5291
  const stage = this.instance.getStage();
4973
- stage.container().addEventListener("keydown", (e) => {
4974
- if (e.code === "Space") this.isSpaceKeyPressed = true;
4975
- if (e.code === "Backspace" || e.code === "Delete") {
4976
- Promise.resolve().then(() => {
4977
- this.removeSelectedNodes();
4978
- });
4979
- return;
4980
- }
4981
- }, { signal: this.instance.getEventsController()?.signal });
4982
- stage.container().addEventListener("keyup", (e) => {
4983
- if (e.code === "Space") this.isSpaceKeyPressed = false;
4984
- }, { signal: this.instance.getEventsController()?.signal });
4985
- stage.on("pointerdown", (e) => {
4986
- this.setTapStart(e);
4987
- if (e.target.getClassName().includes("custom-snap-guide")) return;
4988
- this.handledClickOrTap = false;
4989
- this.pointers[e.evt.pointerId] = e.evt;
4990
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
4991
- if (e.evt.pointerType === "mouse" && e.evt?.button !== 0) return;
4992
- if (e.evt.pointerType === "pen" && e.evt?.pressure <= .05) return;
4993
- if (!this.initialized) return;
4994
- if (!this.active) return;
4995
- if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
4996
- const selectedGroup = getTargetedNode(this.instance);
4997
- if (selectedGroup?.getParent() instanceof Konva.Transformer) {
4998
- this.selecting = false;
4999
- this.stopPanLoop();
5000
- this.hideSelectorArea();
5001
- return;
5002
- }
5003
- const isStage = e.target instanceof Konva.Stage;
5004
- const isTransformer = e.target?.getParent() instanceof Konva.Transformer;
5005
- const canBeTargeted = e.target.getAttrs().canBeTargeted !== false;
5006
- const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5007
- if (isTransformer) return;
5008
- if (!isStage && !isContainerEmptyArea && canBeTargeted) {
5009
- this.selecting = false;
5010
- this.stopPanLoop();
5011
- this.hideSelectorArea();
5012
- this.handleClickOrTap(e);
5013
- return;
5014
- }
5015
- if (isStage || isContainerEmptyArea) {
5016
- this.setSelectedNodes([]);
5017
- this.serializeSelectedNodes();
5018
- this.triggerOnNodesChangeEvent();
5019
- }
5020
- this.panDirection.x = 0;
5021
- this.panDirection.y = 0;
5022
- this.panSpeed = {
5023
- x: 0,
5024
- y: 0
5025
- };
5026
- const intStage = this.instance.getStage();
5027
- this.x1 = intStage.getRelativePointerPosition()?.x ?? 0;
5028
- this.y1 = intStage.getRelativePointerPosition()?.y ?? 0;
5029
- this.x2 = intStage.getRelativePointerPosition()?.x ?? 0;
5030
- this.y2 = intStage.getRelativePointerPosition()?.y ?? 0;
5031
- this.selectionStart = {
5032
- x: this.x1,
5033
- y: this.y1
5034
- };
5035
- this.selectionRectangle.strokeWidth(this.config.selectionArea.strokeWidth / stage.scaleX());
5036
- this.selectionRectangle.dash(this.config.selectionArea.dash?.map((d) => d / stage.scaleX()) ?? []);
5037
- this.selectionRectangle.width(0);
5038
- this.selectionRectangle.height(0);
5039
- this.selecting = true;
5040
- const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
5041
- if (isCtrlOrMetaPressed) {
5042
- const nodesSelected = this.tr.nodes();
5043
- for (const node of nodesSelected) node.fire("onSelectionCleared", { bubbles: true });
5044
- }
5045
- this.selectNone();
5046
- this.instance.emitEvent("onSelectionState", true);
5047
- this.panLoopId = requestAnimationFrame(() => this.panLoop());
5048
- });
5049
- const handleMouseMove = (e) => {
5050
- if (!e?.evt) return;
5051
- const moved = this.checkMoved(e);
5052
- if (e.evt?.buttons === 0) return;
5053
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
5054
- if (!this.initialized) return;
5055
- if (!this.active) return;
5056
- const contextMenuPlugin = this.getContextMenuPlugin();
5057
- if (moved) contextMenuPlugin?.cancelLongPressTimer();
5058
- else this.hideSelectorArea();
5059
- if (contextMenuPlugin?.isContextMenuVisible()) this.stopPanLoop();
5060
- if (this.isSpaceKeyPressed) return;
5061
- if (!this.selecting) return;
5062
- this.updateSelectionRect();
5063
- this.updatePanDirection();
5064
- };
5065
- stage.on("pointermove", (0, import_throttle.default)(handleMouseMove, DEFAULT_THROTTLE_MS));
5066
- this.panLoop();
5067
- stage.on("pointerup", (e) => {
5068
- const store = this.instance.getStore();
5069
- const actUser = store.getUser();
5070
- this.tr.setAttrs({ listening: true });
5071
- this.selecting = false;
5072
- this.stopPanLoop();
5073
- const moved = this.checkMoved(e);
5074
- this.checkDoubleTap(e);
5075
- delete this.pointers[e.evt.pointerId];
5076
- this.previousTap = this.tapStart;
5077
- if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
5078
- const contextMenuPlugin = this.getContextMenuPlugin();
5079
- if (!this.initialized) {
5080
- this.hideSelectorArea();
5081
- return;
5082
- }
5083
- if (!this.active) {
5084
- this.hideSelectorArea();
5085
- return;
5086
- }
5087
- this.instance.emitEvent("onSelectionState", false);
5088
- if (this.isDoubleTap) {
5089
- this.hideSelectorArea();
5090
- this.handleClickOrTap(e);
5091
- return;
5092
- }
5093
- const isStage = e.target instanceof Konva.Stage;
5094
- const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5095
- if ((isStage || isContainerEmptyArea) && !moved) {
5096
- this.selecting = false;
5097
- this.stopPanLoop();
5098
- this.hideSelectorArea();
5099
- this.getSelectionPlugin()?.setSelectedNodes([]);
5100
- return;
5101
- }
5102
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length + 1 > 1) {
5103
- this.hideSelectorArea();
5104
- return;
5105
- }
5106
- if (contextMenuPlugin?.isContextMenuVisible()) this.stopPanLoop();
5107
- const selectedGroup = getTargetedNode(this.instance);
5108
- if (!moved && selectedGroup?.getParent() instanceof Konva.Transformer && !this.handledClickOrTap) {
5109
- this.selecting = false;
5110
- this.stopPanLoop();
5111
- this.hideSelectorArea();
5112
- this.handleClickOrTap(e);
5113
- return;
5114
- }
5115
- if (!this.selectionRectangle.visible()) {
5116
- this.hideSelectorArea();
5117
- return;
5118
- }
5119
- const shapes = stage.find((node) => {
5120
- return ["Shape", "Group"].includes(node.getType()) && typeof node.getAttrs().id !== "undefined";
5121
- });
5122
- const box = this.selectionRectangle.getClientRect();
5123
- this.selectionRectangle.visible(false);
5124
- const selected = shapes.filter((shape) => {
5125
- const shapeMutex = this.instance.getNodeMutexLock(shape.id());
5126
- if (shapeMutex && shapeMutex.user.id !== actUser.id) return false;
5127
- let parent = this.instance.getInstanceRecursive(shape.getParent());
5128
- if (parent.getAttrs().nodeId) parent = this.instance.getStage().findOne(`#${parent.getAttrs().nodeId}`);
5129
- if (shape.getAttrs().nodeType && shape.getAttrs().nodeType === "frame") {
5130
- const frameBox = shape.getClientRect();
5131
- const isContained = frameBox.x >= box.x && frameBox.y >= box.y && frameBox.x + frameBox.width <= box.x + box.width && frameBox.y + frameBox.height <= box.y + box.height;
5132
- return isContained;
5133
- }
5134
- if (shape.getAttrs().nodeType && shape?.getAttrs().nodeType === "group" && ["layer", "frame"].includes(parent?.getAttrs().nodeType)) return shape.getAttrs().nodeType && Konva.Util.haveIntersection(box, shape.getClientRect());
5135
- if (shape.getAttrs().nodeType && shape.getAttrs().nodeType !== "group" && ["layer", "frame"].includes(parent?.getAttrs().nodeType)) return shape.getAttrs().nodeType && Konva.Util.haveIntersection(box, shape.getClientRect());
5136
- return false;
5137
- });
5138
- const selectedNodes = new Set();
5139
- const uniqueContainerNodesIds = new Set();
5140
- const containerNodesIds = [];
5141
- const containerNodes = [];
5142
- const otherNodes = [];
5143
- for (const node of selected) {
5144
- let realNode = node;
5145
- if (node.getAttrs().nodeId) realNode = stage.findOne(`#${node.getAttrs().nodeId}`);
5146
- if (!realNode) continue;
5147
- const isContainer = typeof realNode.getAttrs().isContainerPrincipal !== "undefined" && realNode.getAttrs().isContainerPrincipal;
5148
- if (isContainer) {
5149
- containerNodes.push(realNode);
5150
- containerNodesIds.push(realNode.getAttrs().id ?? "");
5151
- uniqueContainerNodesIds.add(realNode.getAttrs().id ?? "");
5152
- if (!realNode.getAttrs().locked) selectedNodes.add(realNode);
5153
- } else otherNodes.push(realNode);
5154
- }
5155
- for (const node of otherNodes) {
5156
- let parent = this.instance.getInstanceRecursive(node.getParent());
5157
- if (parent?.getAttrs().nodeId) parent = this.instance.getStage().findOne(`#${parent.getAttrs().nodeId}`);
5158
- if (parent && !containerNodesIds.includes(parent?.getAttrs().id ?? "") && !node.getAttrs().locked) selectedNodes.add(node);
5159
- }
5160
- this.selecting = false;
5161
- this.stopPanLoop();
5162
- this.tr.nodes([...selectedNodes]);
5163
- this.handleMultipleSelectionBehavior();
5164
- this.handleBehaviors();
5165
- if (this.tr.nodes().length > 0) {
5166
- stage.container().tabIndex = 1;
5167
- stage.container().focus();
5168
- }
5169
- this.triggerSelectedNodesEvent();
5170
- });
5292
+ registerKeyboardHandlers(this);
5293
+ stage.on("pointerdown", (e) => handlePointerDown(this, e));
5294
+ stage.on("pointermove", (0, import_throttle.default)((e) => handlePointerMove(this, e), DEFAULT_THROTTLE_MS));
5295
+ stage.on("pointerup", (e) => handlePointerUp(this, e));
5171
5296
  this.instance.addEventListener("onStateChange", () => {
5172
5297
  requestAnimationFrame(() => {
5173
5298
  this.syncSelection();
@@ -5180,129 +5305,53 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5180
5305
  });
5181
5306
  }
5182
5307
  handleMultipleSelectionBehavior() {
5183
- if (this.tr.nodes().length > 1 && this.config.behaviors?.onMultipleSelection) {
5184
- const selectionBehavior = this.config.behaviors?.onMultipleSelection?.(this.tr.nodes());
5185
- this.tr.setAttrs(selectionBehavior);
5186
- this.tr.forceUpdate();
5308
+ const tr = this.transformerCtrl.getTransformer();
5309
+ if (tr.nodes().length > 1 && this.config.behaviors?.onMultipleSelection) {
5310
+ const selectionBehavior = this.config.behaviors.onMultipleSelection(tr.nodes());
5311
+ tr.setAttrs(selectionBehavior);
5312
+ tr.forceUpdate();
5187
5313
  }
5188
5314
  }
5189
5315
  syncSelection() {
5190
5316
  const stageMode = this.instance.getStage().mode();
5191
5317
  if (![WEAVE_STAGE_DEFAULT_MODE].includes(stageMode)) return;
5318
+ const tr = this.transformerCtrl.getTransformer();
5192
5319
  const newSelectedNodes = [];
5193
- const actualSelectedNodes = this.tr.nodes();
5320
+ const actualSelectedNodes = tr.nodes();
5194
5321
  for (const node of actualSelectedNodes) {
5195
5322
  const existNode = this.instance.getStage().findOne(`#${node.getAttrs().id}`);
5196
5323
  if (existNode) newSelectedNodes.push(existNode);
5197
5324
  }
5198
- this.tr.nodes([...newSelectedNodes]);
5199
- if (newSelectedNodes.length > 0) this.tr.forceUpdate();
5325
+ tr.nodes([...newSelectedNodes]);
5326
+ if (newSelectedNodes.length > 0) tr.forceUpdate();
5200
5327
  this.triggerSelectedNodesEvent();
5201
5328
  }
5202
5329
  getSelectionPlugin() {
5203
- const selectionPlugin = this.instance.getPlugin("nodesSelection");
5204
- return selectionPlugin;
5330
+ return this.instance.getPlugin("nodesSelection");
5205
5331
  }
5206
5332
  hideHoverState() {
5207
5333
  const selectionPlugin = this.getSelectionPlugin();
5208
5334
  if (!selectionPlugin) return;
5209
5335
  selectionPlugin.getHoverTransformer().nodes([]);
5210
5336
  }
5211
- handleClickOrTap(e) {
5212
- const stage = this.instance.getStage();
5213
- this.handledClickOrTap = true;
5214
- e.cancelBubble = true;
5215
- if (!this.enabled) return;
5216
- if (this.instance.getActiveAction() !== SELECTION_TOOL_ACTION_NAME) return;
5217
- const contextMenuPlugin = this.getContextMenuPlugin();
5218
- if (contextMenuPlugin?.isContextMenuVisible()) this.stopPanLoop();
5219
- this.hideHoverState();
5220
- const selectedGroup = getTargetedNode(this.instance);
5221
- if (!this.initialized) return;
5222
- if (e.evt.pointerType === "mouse" && e.evt?.button && e.evt?.button !== 0) return;
5223
- let areNodesSelected = false;
5224
- let nodeTargeted = selectedGroup && !(selectedGroup.getAttrs().active ?? false) ? selectedGroup : e.target;
5225
- if (e.target === this.instance.getStage()) {
5226
- this.isDoubleTap = false;
5227
- this.getNodesSelectionFeedbackPlugin()?.cleanupSelectedHalos();
5228
- return;
5229
- }
5230
- nodeTargeted = this.instance.getRealSelectedNode(nodeTargeted);
5231
- if (!nodeTargeted.getAttrs().nodeType) {
5232
- this.isDoubleTap = false;
5233
- return;
5234
- }
5235
- const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
5236
- const nodeSelectedIndex = this.tr.nodes().findIndex((node) => {
5237
- return node.getAttrs().id === nodeTargeted.getAttrs().id;
5238
- });
5239
- const isSelected = nodeSelectedIndex !== -1;
5240
- const user = this.instance.getStore().getUser();
5241
- const isLocked = nodeTargeted.getAttrs().locked ?? false;
5242
- const isMutexLocked = nodeTargeted.getAttrs().mutexLocked && nodeTargeted.getAttrs().mutexUserId !== user.id;
5243
- if (isLocked || isMutexLocked) {
5244
- const parent = this.instance.getInstanceRecursive(nodeTargeted.getParent());
5245
- const mainLayer = this.instance.getMainLayer();
5246
- const isStage = parent instanceof Konva.Stage;
5247
- const isMainLayer = parent === mainLayer;
5248
- const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5249
- if (isStage || isMainLayer || isContainerEmptyArea) this.getSelectionPlugin()?.setSelectedNodes([]);
5250
- return;
5251
- }
5252
- if (nodeTargeted.getAttrs().nodeId) {
5253
- const realNode = stage.findOne(`#${nodeTargeted.getAttrs().nodeId}`);
5254
- if (realNode) nodeTargeted = realNode;
5255
- }
5256
- if (typeof nodeTargeted.getAttrs().isContainerPrincipal !== "undefined" && !nodeTargeted.getAttrs().isContainerPrincipal) return;
5257
- if (this.isDoubleTap && !metaPressed) {
5258
- this.isDoubleTap = false;
5259
- nodeTargeted.dblClick();
5260
- return;
5261
- }
5262
- const isCtrlOrCmdPressed = e.evt.ctrlKey || e.evt.metaKey;
5263
- if (isCtrlOrCmdPressed) return;
5264
- if (!metaPressed) {
5265
- this.tr.nodes([nodeTargeted]);
5266
- this.tr.show();
5267
- areNodesSelected = true;
5268
- }
5269
- if (metaPressed && isSelected) {
5270
- const nodes = this.tr.nodes().slice();
5271
- nodes.splice(nodes.indexOf(nodeTargeted), 1);
5272
- this.tr.nodes(nodes);
5273
- areNodesSelected = true;
5274
- }
5275
- if (metaPressed && !isSelected) {
5276
- const nodes = this.tr.nodes().concat([nodeTargeted]);
5277
- this.tr.nodes(nodes);
5278
- areNodesSelected = true;
5279
- }
5280
- this.handleMultipleSelectionBehavior();
5281
- this.handleBehaviors();
5282
- if (areNodesSelected) {
5283
- stage.container().tabIndex = 1;
5284
- stage.container().focus();
5285
- stage.container().style.cursor = (typeof nodeTargeted?.defineMousePointer === "function" ? nodeTargeted.defineMousePointer() : null) ?? "grab";
5286
- }
5287
- this.triggerSelectedNodesEvent();
5288
- }
5289
5337
  getTransformer() {
5290
- return this.tr;
5338
+ return this.transformerCtrl.getTransformer();
5291
5339
  }
5292
5340
  getHoverTransformer() {
5293
- return this.trHover;
5341
+ return this.transformerCtrl.getHoverTransformer();
5294
5342
  }
5295
5343
  handleBehaviors() {
5344
+ const tr = this.transformerCtrl.getTransformer();
5296
5345
  const nodes = this.getSelectedNodes();
5297
5346
  const nodesSelected = nodes.length;
5298
- if (nodesSelected > 1 && !this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && !this.config.behaviors.singleSelection.enabled) this.tr.enabledAnchors([]);
5299
- if (nodesSelected > 1 && this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && this.config.behaviors.singleSelection.enabled) this.tr.enabledAnchors(this.defaultEnabledAnchors);
5347
+ if (nodesSelected > 1 && !this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && !this.config.behaviors.singleSelection.enabled) tr.enabledAnchors([]);
5348
+ if (nodesSelected > 1 && this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && this.config.behaviors.singleSelection.enabled) tr.enabledAnchors(this._defaultEnabledAnchors);
5300
5349
  let transformerAttrs = { ...this.config.selection };
5301
- if (this.tr && this.tr.nodes().length > 0) {
5302
- const currentAttrs = this.tr.getAttrs();
5350
+ if (tr && tr.nodes().length > 0) {
5351
+ const currentAttrs = tr.getAttrs();
5303
5352
  Object.keys(currentAttrs).forEach((key) => {
5304
- if (["rotationSnaps", "enabledAnchors"].includes(key)) this.tr.setAttr(key, []);
5305
- else this.tr.setAttr(key, void 0);
5353
+ if (["rotationSnaps", "enabledAnchors"].includes(key)) tr.setAttr(key, []);
5354
+ else tr.setAttr(key, void 0);
5306
5355
  });
5307
5356
  }
5308
5357
  if (nodesSelected === 1) {
@@ -5312,31 +5361,32 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5312
5361
  if (nodesSelected > 1) {
5313
5362
  const anchorsArrays = [];
5314
5363
  for (const node of nodes) anchorsArrays.push(node?.allowedAnchors?.() ?? []);
5315
- const enabledAnchors = intersectArrays(anchorsArrays);
5316
- transformerAttrs.enabledAnchors = enabledAnchors;
5364
+ transformerAttrs.enabledAnchors = intersectArrays(anchorsArrays);
5317
5365
  }
5318
- if (this.tr && this.tr.nodes().length > 0) {
5366
+ if (tr && tr.nodes().length > 0) {
5319
5367
  if (transformerAttrs.enabledAnchors?.length === 0) transformerAttrs.resizeEnabled = false;
5320
- this.tr.setAttrs(transformerAttrs);
5321
- this.tr.forceUpdate();
5322
- this.tr.getLayer()?.batchDraw();
5368
+ tr.setAttrs(transformerAttrs);
5369
+ tr.forceUpdate();
5370
+ tr.getLayer()?.batchDraw();
5323
5371
  }
5324
5372
  }
5325
5373
  setSelectedNodes(nodes) {
5326
- this.tr.setNodes(nodes);
5374
+ const tr = this.transformerCtrl.getTransformer();
5375
+ tr.setNodes(nodes);
5327
5376
  this.handleBehaviors();
5328
5377
  if (nodes.length === 0) this.getNodesSelectionFeedbackPlugin()?.cleanupSelectedHalos();
5329
5378
  const usersSelectionPlugin = this.instance.getPlugin(WEAVE_USERS_SELECTION_KEY);
5330
5379
  if (usersSelectionPlugin) requestAnimationFrame(() => {
5331
- usersSelectionPlugin.sendSelectionAwarenessInfo(this.tr);
5380
+ usersSelectionPlugin.sendSelectionAwarenessInfo(tr);
5332
5381
  });
5333
5382
  }
5334
5383
  getSelectedNodes() {
5335
- if (!this.tr) return [];
5336
- return this.tr.nodes();
5384
+ if (!this.transformerCtrl) return [];
5385
+ return this.transformerCtrl.getTransformer().nodes();
5337
5386
  }
5338
5387
  getSelectedNodesExtended() {
5339
- const selectedNodes = this.tr.getNodes().map((node) => {
5388
+ const tr = this.transformerCtrl.getTransformer();
5389
+ return tr.getNodes().map((node) => {
5340
5390
  const nodeType = node.getAttr("nodeType");
5341
5391
  const nodeHandler = this.instance.getNodeHandler(nodeType);
5342
5392
  return {
@@ -5344,17 +5394,13 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5344
5394
  node: nodeHandler?.serialize(node)
5345
5395
  };
5346
5396
  });
5347
- return selectedNodes;
5348
5397
  }
5349
5398
  selectAll() {
5350
5399
  const mainLayer = this.instance.getMainLayer();
5351
- if (mainLayer) {
5352
- const nodes = mainLayer.getChildren();
5353
- this.tr.nodes(nodes);
5354
- }
5400
+ if (mainLayer) this.transformerCtrl.getTransformer().nodes(mainLayer.getChildren());
5355
5401
  }
5356
5402
  selectNone() {
5357
- this.tr.nodes([]);
5403
+ this.transformerCtrl.getTransformer().nodes([]);
5358
5404
  }
5359
5405
  enable() {
5360
5406
  this.getLayer()?.show();
@@ -5365,36 +5411,31 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5365
5411
  this.enabled = false;
5366
5412
  }
5367
5413
  getNodesSelectionFeedbackPlugin() {
5368
- const selectionFeedbackPlugin = this.instance.getPlugin(WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY);
5369
- return selectionFeedbackPlugin;
5414
+ return getNodesSelectionFeedbackPlugin(this.instance);
5370
5415
  }
5371
5416
  getContextMenuPlugin() {
5372
- const contextMenuPlugin = this.instance.getPlugin(WEAVE_CONTEXT_MENU_PLUGIN_KEY);
5373
- return contextMenuPlugin;
5417
+ return getContextMenuPlugin(this.instance);
5374
5418
  }
5375
5419
  getStageGridPlugin() {
5376
- const gridPlugin = this.instance.getPlugin(WEAVE_STAGE_GRID_PLUGIN_KEY);
5377
- return gridPlugin;
5420
+ return getStageGridPlugin(this.instance);
5378
5421
  }
5379
5422
  getStagePanningPlugin() {
5380
- const stagePanning = this.instance.getPlugin(WEAVE_STAGE_PANNING_KEY);
5381
- return stagePanning;
5423
+ return getStagePanningPlugin(this.instance);
5382
5424
  }
5383
5425
  getUsersPresencePlugin() {
5384
- const usersPresencePlugin = this.instance.getPlugin(WEAVE_USERS_PRESENCE_PLUGIN_KEY);
5385
- return usersPresencePlugin;
5426
+ return getUsersPresencePlugin(this.instance);
5386
5427
  }
5387
5428
  isTransforming() {
5388
- return this.transformInProcess;
5429
+ return this.transformerCtrl.isTransforming();
5389
5430
  }
5390
5431
  isDragging() {
5391
- return this.dragInProcess;
5432
+ return this.transformerCtrl.isDragging();
5392
5433
  }
5393
5434
  getSelectorConfig() {
5394
5435
  return this.config.selection;
5395
5436
  }
5396
5437
  saveDragSelectedNodes() {
5397
- this.dragSelectedNodes = this.tr.nodes();
5438
+ this.dragSelectedNodes = this.transformerCtrl.getTransformer().nodes();
5398
5439
  }
5399
5440
  getDragSelectedNodes() {
5400
5441
  return this.dragSelectedNodes;
@@ -5472,30 +5513,30 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
5472
5513
  this.initEvents();
5473
5514
  }
5474
5515
  writeClipboardImage(base64Data) {
5475
- return new Promise((resolve, reject$1) => {
5516
+ return new Promise((resolve, reject) => {
5476
5517
  setTimeout(async () => {
5477
- if (navigator.clipboard === void 0) return reject$1(new Error("Clipboard API not supported"));
5518
+ if (navigator.clipboard === void 0) return reject(new Error("Clipboard API not supported"));
5478
5519
  const res = await fetch(base64Data);
5479
5520
  const imageBlob = await res.blob();
5480
5521
  const item = new ClipboardItem({ [imageBlob.type]: imageBlob });
5481
5522
  navigator.clipboard.write([item]).then(() => {
5482
5523
  resolve();
5483
5524
  }).catch((error) => {
5484
- reject$1(error);
5525
+ reject(error);
5485
5526
  });
5486
5527
  });
5487
5528
  });
5488
5529
  }
5489
5530
  writeClipboardData(data) {
5490
- return new Promise((resolve, reject$1) => {
5531
+ return new Promise((resolve, reject) => {
5491
5532
  setTimeout(async () => {
5492
- if (navigator.clipboard === void 0) return reject$1(new Error("Clipboard API not supported"));
5533
+ if (navigator.clipboard === void 0) return reject(new Error("Clipboard API not supported"));
5493
5534
  const textBlob = new Blob([data], { type: "text/plain" });
5494
5535
  const item = new ClipboardItem({ [textBlob.type]: textBlob });
5495
5536
  navigator.clipboard.write([item]).then(() => {
5496
5537
  resolve();
5497
5538
  }).catch((error) => {
5498
- reject$1(error);
5539
+ reject(error);
5499
5540
  });
5500
5541
  });
5501
5542
  });
@@ -5565,7 +5606,7 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
5565
5606
  this.focusPasteCatcher();
5566
5607
  if (!this.enabled) return;
5567
5608
  }
5568
- }, { signal: this.instance.getEventsController()?.signal });
5609
+ }, { signal: this.instance.getEventsController().signal });
5569
5610
  if (catcher) catcher.addEventListener("paste", async (e) => {
5570
5611
  e.preventDefault();
5571
5612
  let items = void 0;
@@ -5584,7 +5625,7 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
5584
5625
  return;
5585
5626
  }
5586
5627
  this.sendExternalPasteEvent(void 0, items);
5587
- }, { signal: this.instance.getEventsController()?.signal });
5628
+ }, { signal: this.instance.getEventsController().signal });
5588
5629
  }
5589
5630
  sendExternalPasteEvent(dataList, items) {
5590
5631
  const stage = this.instance.getStage();
@@ -6827,7 +6868,7 @@ var require__arrayMap = __commonJS({ "../../node_modules/lodash/_arrayMap.js"(ex
6827
6868
  //#endregion
6828
6869
  //#region ../../node_modules/lodash/_isKey.js
6829
6870
  var require__isKey = __commonJS({ "../../node_modules/lodash/_isKey.js"(exports, module) {
6830
- var isArray$9 = require_isArray(), isSymbol$3 = require_isSymbol();
6871
+ var isArray$8 = require_isArray(), isSymbol$3 = require_isSymbol();
6831
6872
  /** Used to match property names within property paths. */
6832
6873
  var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/;
6833
6874
  /**
@@ -6839,7 +6880,7 @@ var require__isKey = __commonJS({ "../../node_modules/lodash/_isKey.js"(exports,
6839
6880
  * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
6840
6881
  */
6841
6882
  function isKey$3(value, object) {
6842
- if (isArray$9(value)) return false;
6883
+ if (isArray$8(value)) return false;
6843
6884
  var type = typeof value;
6844
6885
  if (type == "number" || type == "symbol" || type == "boolean" || value == null || isSymbol$3(value)) return true;
6845
6886
  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object(object);
@@ -6852,7 +6893,7 @@ var require__isKey = __commonJS({ "../../node_modules/lodash/_isKey.js"(exports,
6852
6893
  var require_memoize = __commonJS({ "../../node_modules/lodash/memoize.js"(exports, module) {
6853
6894
  var MapCache$1 = require__MapCache();
6854
6895
  /** Error message constants. */
6855
- var FUNC_ERROR_TEXT$1 = "Expected a function";
6896
+ var FUNC_ERROR_TEXT = "Expected a function";
6856
6897
  /**
6857
6898
  * Creates a function that memoizes the result of `func`. If `resolver` is
6858
6899
  * provided, it determines the cache key for storing the result based on the
@@ -6898,7 +6939,7 @@ var require_memoize = __commonJS({ "../../node_modules/lodash/memoize.js"(export
6898
6939
  * _.memoize.Cache = WeakMap;
6899
6940
  */
6900
6941
  function memoize$2(func, resolver) {
6901
- if (typeof func != "function" || resolver != null && typeof resolver != "function") throw new TypeError(FUNC_ERROR_TEXT$1);
6942
+ if (typeof func != "function" || resolver != null && typeof resolver != "function") throw new TypeError(FUNC_ERROR_TEXT);
6902
6943
  var memoized = function() {
6903
6944
  var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
6904
6945
  if (cache.has(key)) return cache.get(key);
@@ -6967,7 +7008,7 @@ var require__stringToPath = __commonJS({ "../../node_modules/lodash/_stringToPat
6967
7008
  //#endregion
6968
7009
  //#region ../../node_modules/lodash/_baseToString.js
6969
7010
  var require__baseToString = __commonJS({ "../../node_modules/lodash/_baseToString.js"(exports, module) {
6970
- var Symbol$2 = require__Symbol(), arrayMap$1 = require__arrayMap(), isArray$8 = require_isArray(), isSymbol$2 = require_isSymbol();
7011
+ var Symbol$2 = require__Symbol(), arrayMap$1 = require__arrayMap(), isArray$7 = require_isArray(), isSymbol$2 = require_isSymbol();
6971
7012
  /** Used as references for various `Number` constants. */
6972
7013
  var INFINITY$1 = Infinity;
6973
7014
  /** Used to convert symbols to primitives and strings. */
@@ -6982,7 +7023,7 @@ var require__baseToString = __commonJS({ "../../node_modules/lodash/_baseToStrin
6982
7023
  */
6983
7024
  function baseToString$1(value) {
6984
7025
  if (typeof value == "string") return value;
6985
- if (isArray$8(value)) return arrayMap$1(value, baseToString$1) + "";
7026
+ if (isArray$7(value)) return arrayMap$1(value, baseToString$1) + "";
6986
7027
  if (isSymbol$2(value)) return symbolToString ? symbolToString.call(value) : "";
6987
7028
  var result = value + "";
6988
7029
  return result == "0" && 1 / value == -INFINITY$1 ? "-0" : result;
@@ -7024,7 +7065,7 @@ var require_toString = __commonJS({ "../../node_modules/lodash/toString.js"(expo
7024
7065
  //#endregion
7025
7066
  //#region ../../node_modules/lodash/_castPath.js
7026
7067
  var require__castPath = __commonJS({ "../../node_modules/lodash/_castPath.js"(exports, module) {
7027
- var isArray$7 = require_isArray(), isKey$2 = require__isKey(), stringToPath = require__stringToPath(), toString = require_toString();
7068
+ var isArray$6 = require_isArray(), isKey$2 = require__isKey(), stringToPath = require__stringToPath(), toString = require_toString();
7028
7069
  /**
7029
7070
  * Casts `value` to a path array if it's not one.
7030
7071
  *
@@ -7034,7 +7075,7 @@ var require__castPath = __commonJS({ "../../node_modules/lodash/_castPath.js"(ex
7034
7075
  * @returns {Array} Returns the cast property path array.
7035
7076
  */
7036
7077
  function castPath$2(value, object) {
7037
- if (isArray$7(value)) return value;
7078
+ if (isArray$6(value)) return value;
7038
7079
  return isKey$2(value, object) ? [value] : stringToPath(toString(value));
7039
7080
  }
7040
7081
  module.exports = castPath$2;
@@ -7361,7 +7402,7 @@ var require__arrayPush = __commonJS({ "../../node_modules/lodash/_arrayPush.js"(
7361
7402
  //#endregion
7362
7403
  //#region ../../node_modules/lodash/_baseGetAllKeys.js
7363
7404
  var require__baseGetAllKeys = __commonJS({ "../../node_modules/lodash/_baseGetAllKeys.js"(exports, module) {
7364
- var arrayPush = require__arrayPush(), isArray$6 = require_isArray();
7405
+ var arrayPush = require__arrayPush(), isArray$5 = require_isArray();
7365
7406
  /**
7366
7407
  * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
7367
7408
  * `keysFunc` and `symbolsFunc` to get the enumerable property names and
@@ -7375,7 +7416,7 @@ var require__baseGetAllKeys = __commonJS({ "../../node_modules/lodash/_baseGetAl
7375
7416
  */
7376
7417
  function baseGetAllKeys$1(object, keysFunc, symbolsFunc) {
7377
7418
  var result = keysFunc(object);
7378
- return isArray$6(object) ? result : arrayPush(result, symbolsFunc(object));
7419
+ return isArray$5(object) ? result : arrayPush(result, symbolsFunc(object));
7379
7420
  }
7380
7421
  module.exports = baseGetAllKeys$1;
7381
7422
  } });
@@ -7392,7 +7433,7 @@ var require__arrayFilter = __commonJS({ "../../node_modules/lodash/_arrayFilter.
7392
7433
  * @param {Function} predicate The function invoked per iteration.
7393
7434
  * @returns {Array} Returns the new filtered array.
7394
7435
  */
7395
- function arrayFilter$2(array, predicate) {
7436
+ function arrayFilter$1(array, predicate) {
7396
7437
  var index = -1, length = array == null ? 0 : array.length, resIndex = 0, result = [];
7397
7438
  while (++index < length) {
7398
7439
  var value = array[index];
@@ -7400,7 +7441,7 @@ var require__arrayFilter = __commonJS({ "../../node_modules/lodash/_arrayFilter.
7400
7441
  }
7401
7442
  return result;
7402
7443
  }
7403
- module.exports = arrayFilter$2;
7444
+ module.exports = arrayFilter$1;
7404
7445
  } });
7405
7446
 
7406
7447
  //#endregion
@@ -7433,7 +7474,7 @@ var require_stubArray = __commonJS({ "../../node_modules/lodash/stubArray.js"(ex
7433
7474
  //#endregion
7434
7475
  //#region ../../node_modules/lodash/_getSymbols.js
7435
7476
  var require__getSymbols = __commonJS({ "../../node_modules/lodash/_getSymbols.js"(exports, module) {
7436
- var arrayFilter$1 = require__arrayFilter(), stubArray = require_stubArray();
7477
+ var arrayFilter = require__arrayFilter(), stubArray = require_stubArray();
7437
7478
  /** Used for built-in method references. */
7438
7479
  var objectProto$2 = Object.prototype;
7439
7480
  /** Built-in value references. */
@@ -7449,7 +7490,7 @@ var require__getSymbols = __commonJS({ "../../node_modules/lodash/_getSymbols.js
7449
7490
  var getSymbols$1 = !nativeGetSymbols ? stubArray : function(object) {
7450
7491
  if (object == null) return [];
7451
7492
  object = Object(object);
7452
- return arrayFilter$1(nativeGetSymbols(object), function(symbol) {
7493
+ return arrayFilter(nativeGetSymbols(object), function(symbol) {
7453
7494
  return propertyIsEnumerable.call(object, symbol);
7454
7495
  });
7455
7496
  };
@@ -7573,7 +7614,7 @@ var require__equalObjects = __commonJS({ "../../node_modules/lodash/_equalObject
7573
7614
  //#endregion
7574
7615
  //#region ../../node_modules/lodash/_baseIsEqualDeep.js
7575
7616
  var require__baseIsEqualDeep = __commonJS({ "../../node_modules/lodash/_baseIsEqualDeep.js"(exports, module) {
7576
- var Stack$1 = require__Stack(), equalArrays = require__equalArrays(), equalByTag = require__equalByTag(), equalObjects = require__equalObjects(), getTag = require__getTag(), isArray$5 = require_isArray(), isBuffer = require_isBuffer(), isTypedArray = require_isTypedArray();
7617
+ var Stack$1 = require__Stack(), equalArrays = require__equalArrays(), equalByTag = require__equalByTag(), equalObjects = require__equalObjects(), getTag = require__getTag(), isArray$4 = require_isArray(), isBuffer = require_isBuffer(), isTypedArray = require_isTypedArray();
7577
7618
  /** Used to compose bitmasks for value comparisons. */
7578
7619
  var COMPARE_PARTIAL_FLAG$2 = 1;
7579
7620
  /** `Object#toString` result references. */
@@ -7597,7 +7638,7 @@ var require__baseIsEqualDeep = __commonJS({ "../../node_modules/lodash/_baseIsEq
7597
7638
  * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
7598
7639
  */
7599
7640
  function baseIsEqualDeep$1(object, other, bitmask, customizer, equalFunc, stack) {
7600
- var objIsArr = isArray$5(object), othIsArr = isArray$5(other), objTag = objIsArr ? arrayTag : getTag(object), othTag = othIsArr ? arrayTag : getTag(other);
7641
+ var objIsArr = isArray$4(object), othIsArr = isArray$4(other), objTag = objIsArr ? arrayTag : getTag(object), othTag = othIsArr ? arrayTag : getTag(other);
7601
7642
  objTag = objTag == argsTag ? objectTag : objTag;
7602
7643
  othTag = othTag == argsTag ? objectTag : othTag;
7603
7644
  var objIsObj = objTag == objectTag, othIsObj = othTag == objectTag, isSameTag = objTag == othTag;
@@ -7833,7 +7874,7 @@ var require__baseHasIn = __commonJS({ "../../node_modules/lodash/_baseHasIn.js"(
7833
7874
  //#endregion
7834
7875
  //#region ../../node_modules/lodash/_hasPath.js
7835
7876
  var require__hasPath = __commonJS({ "../../node_modules/lodash/_hasPath.js"(exports, module) {
7836
- var castPath = require__castPath(), isArguments = require_isArguments(), isArray$4 = require_isArray(), isIndex = require__isIndex(), isLength = require_isLength(), toKey$2 = require__toKey();
7877
+ var castPath = require__castPath(), isArguments = require_isArguments(), isArray$3 = require_isArray(), isIndex = require__isIndex(), isLength = require_isLength(), toKey$2 = require__toKey();
7837
7878
  /**
7838
7879
  * Checks if `path` exists on `object`.
7839
7880
  *
@@ -7853,7 +7894,7 @@ var require__hasPath = __commonJS({ "../../node_modules/lodash/_hasPath.js"(expo
7853
7894
  }
7854
7895
  if (result || ++index != length) return result;
7855
7896
  length = object == null ? 0 : object.length;
7856
- return !!length && isLength(length) && isIndex(key, length) && (isArray$4(object) || isArguments(object));
7897
+ return !!length && isLength(length) && isIndex(key, length) && (isArray$3(object) || isArguments(object));
7857
7898
  }
7858
7899
  module.exports = hasPath$1;
7859
7900
  } });
@@ -7990,7 +8031,7 @@ var require_property = __commonJS({ "../../node_modules/lodash/property.js"(expo
7990
8031
  //#endregion
7991
8032
  //#region ../../node_modules/lodash/_baseIteratee.js
7992
8033
  var require__baseIteratee = __commonJS({ "../../node_modules/lodash/_baseIteratee.js"(exports, module) {
7993
- var baseMatches = require__baseMatches(), baseMatchesProperty = require__baseMatchesProperty(), identity$1 = require_identity(), isArray$3 = require_isArray(), property = require_property();
8034
+ var baseMatches = require__baseMatches(), baseMatchesProperty = require__baseMatchesProperty(), identity$1 = require_identity(), isArray$2 = require_isArray(), property = require_property();
7994
8035
  /**
7995
8036
  * The base implementation of `_.iteratee`.
7996
8037
  *
@@ -7998,13 +8039,13 @@ var require__baseIteratee = __commonJS({ "../../node_modules/lodash/_baseIterate
7998
8039
  * @param {*} [value=_.identity] The value to convert to an iteratee.
7999
8040
  * @returns {Function} Returns the iteratee.
8000
8041
  */
8001
- function baseIteratee$2(value) {
8042
+ function baseIteratee$1(value) {
8002
8043
  if (typeof value == "function") return value;
8003
8044
  if (value == null) return identity$1;
8004
- if (typeof value == "object") return isArray$3(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value);
8045
+ if (typeof value == "object") return isArray$2(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value);
8005
8046
  return property(value);
8006
8047
  }
8007
- module.exports = baseIteratee$2;
8048
+ module.exports = baseIteratee$1;
8008
8049
  } });
8009
8050
 
8010
8051
  //#endregion
@@ -8061,14 +8102,14 @@ var require__baseEach = __commonJS({ "../../node_modules/lodash/_baseEach.js"(ex
8061
8102
  * @param {Function} iteratee The function invoked per iteration.
8062
8103
  * @returns {Array|Object} Returns `collection`.
8063
8104
  */
8064
- var baseEach$2 = createBaseEach(baseForOwn);
8065
- module.exports = baseEach$2;
8105
+ var baseEach$1 = createBaseEach(baseForOwn);
8106
+ module.exports = baseEach$1;
8066
8107
  } });
8067
8108
 
8068
8109
  //#endregion
8069
8110
  //#region ../../node_modules/lodash/_baseMap.js
8070
8111
  var require__baseMap = __commonJS({ "../../node_modules/lodash/_baseMap.js"(exports, module) {
8071
- var baseEach$1 = require__baseEach(), isArrayLike = require_isArrayLike();
8112
+ var baseEach = require__baseEach(), isArrayLike = require_isArrayLike();
8072
8113
  /**
8073
8114
  * The base implementation of `_.map` without support for iteratee shorthands.
8074
8115
  *
@@ -8079,7 +8120,7 @@ var require__baseMap = __commonJS({ "../../node_modules/lodash/_baseMap.js"(expo
8079
8120
  */
8080
8121
  function baseMap$1(collection, iteratee) {
8081
8122
  var index = -1, result = isArrayLike(collection) ? Array(collection.length) : [];
8082
- baseEach$1(collection, function(value, key, collection$1) {
8123
+ baseEach(collection, function(value, key, collection$1) {
8083
8124
  result[++index] = iteratee(value, key, collection$1);
8084
8125
  });
8085
8126
  return result;
@@ -8169,7 +8210,7 @@ var require__compareMultiple = __commonJS({ "../../node_modules/lodash/_compareM
8169
8210
  //#endregion
8170
8211
  //#region ../../node_modules/lodash/_baseOrderBy.js
8171
8212
  var require__baseOrderBy = __commonJS({ "../../node_modules/lodash/_baseOrderBy.js"(exports, module) {
8172
- var arrayMap = require__arrayMap(), baseGet = require__baseGet(), baseIteratee$1 = require__baseIteratee(), baseMap = require__baseMap(), baseSortBy = require__baseSortBy(), baseUnary = require__baseUnary(), compareMultiple = require__compareMultiple(), identity = require_identity(), isArray$2 = require_isArray();
8213
+ var arrayMap = require__arrayMap(), baseGet = require__baseGet(), baseIteratee = require__baseIteratee(), baseMap = require__baseMap(), baseSortBy = require__baseSortBy(), baseUnary = require__baseUnary(), compareMultiple = require__compareMultiple(), identity = require_identity(), isArray$1 = require_isArray();
8173
8214
  /**
8174
8215
  * The base implementation of `_.orderBy` without param guards.
8175
8216
  *
@@ -8181,14 +8222,14 @@ var require__baseOrderBy = __commonJS({ "../../node_modules/lodash/_baseOrderBy.
8181
8222
  */
8182
8223
  function baseOrderBy$1(collection, iteratees, orders) {
8183
8224
  if (iteratees.length) iteratees = arrayMap(iteratees, function(iteratee) {
8184
- if (isArray$2(iteratee)) return function(value) {
8225
+ if (isArray$1(iteratee)) return function(value) {
8185
8226
  return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
8186
8227
  };
8187
8228
  return iteratee;
8188
8229
  });
8189
8230
  else iteratees = [identity];
8190
8231
  var index = -1;
8191
- iteratees = arrayMap(iteratees, baseUnary(baseIteratee$1));
8232
+ iteratees = arrayMap(iteratees, baseUnary(baseIteratee));
8192
8233
  var result = baseMap(collection, function(value, key, collection$1) {
8193
8234
  var criteria = arrayMap(iteratees, function(iteratee) {
8194
8235
  return iteratee(value);
@@ -8209,7 +8250,7 @@ var require__baseOrderBy = __commonJS({ "../../node_modules/lodash/_baseOrderBy.
8209
8250
  //#endregion
8210
8251
  //#region ../../node_modules/lodash/orderBy.js
8211
8252
  var require_orderBy = __commonJS({ "../../node_modules/lodash/orderBy.js"(exports, module) {
8212
- var baseOrderBy = require__baseOrderBy(), isArray$1 = require_isArray();
8253
+ var baseOrderBy = require__baseOrderBy(), isArray = require_isArray();
8213
8254
  /**
8214
8255
  * This method is like `_.sortBy` except that it allows specifying the sort
8215
8256
  * orders of the iteratees to sort by. If `orders` is unspecified, all values
@@ -8241,9 +8282,9 @@ var require_orderBy = __commonJS({ "../../node_modules/lodash/orderBy.js"(export
8241
8282
  */
8242
8283
  function orderBy(collection, iteratees, orders, guard) {
8243
8284
  if (collection == null) return [];
8244
- if (!isArray$1(iteratees)) iteratees = iteratees == null ? [] : [iteratees];
8285
+ if (!isArray(iteratees)) iteratees = iteratees == null ? [] : [iteratees];
8245
8286
  orders = guard ? void 0 : orders;
8246
- if (!isArray$1(orders)) orders = orders == null ? [] : [orders];
8287
+ if (!isArray(orders)) orders = orders == null ? [] : [orders];
8247
8288
  return baseOrderBy(collection, iteratees, orders);
8248
8289
  }
8249
8290
  module.exports = orderBy;
@@ -8311,8 +8352,7 @@ var WeaveGroupsManager = class {
8311
8352
  tr.hide();
8312
8353
  selectionPlugin.setSelectedNodes([]);
8313
8354
  }
8314
- let parentNodeId = parentId ?? WEAVE_NODE_LAYER_ID;
8315
- if (typeof parentNodeId === "undefined") parentNodeId = WEAVE_NODE_LAYER_ID;
8355
+ const parentNodeId = parentId ?? WEAVE_NODE_LAYER_ID;
8316
8356
  const parentLayer = stage.findOne(`#${parentNodeId}`);
8317
8357
  const groupId = v4_default();
8318
8358
  const groupInstance = new Konva.Group({
@@ -9441,7 +9481,7 @@ var WeaveRegisterManager = class {
9441
9481
 
9442
9482
  //#endregion
9443
9483
  //#region package.json
9444
- var version = "5.0.0-SNAPSHOT.342.1";
9484
+ var version = "5.0.0-SNAPSHOT.366.1";
9445
9485
 
9446
9486
  //#endregion
9447
9487
  //#region src/managers/setup.ts
@@ -9638,143 +9678,34 @@ var WeaveActionsManager = class {
9638
9678
  actionsHandlers[actionName].cleanup?.();
9639
9679
  this.instance.emitEvent("onActiveActionChange", this.activeAction);
9640
9680
  }
9641
- cancelActionCallback(actionName) {
9642
- return () => {
9643
- this.cancelAction(actionName);
9644
- };
9645
- }
9646
- };
9647
-
9648
- //#endregion
9649
- //#region src/managers/store.ts
9650
- var WeaveStoreManager = class {
9651
- constructor(instance) {
9652
- this.instance = instance;
9653
- this.logger = this.instance.getChildLogger("store-manager");
9654
- this.logger.debug("Store manager created");
9655
- }
9656
- getStore() {
9657
- return this.store;
9658
- }
9659
- registerStore(store) {
9660
- if (typeof this.store !== "undefined") {
9661
- const msg = `Store already registered`;
9662
- this.logger.error(msg);
9663
- throw new Error(msg);
9664
- }
9665
- const storeInstance = store.register(this.instance);
9666
- this.store = storeInstance;
9667
- }
9668
- };
9669
-
9670
- //#endregion
9671
- //#region ../../node_modules/lodash/_baseFilter.js
9672
- var require__baseFilter = __commonJS({ "../../node_modules/lodash/_baseFilter.js"(exports, module) {
9673
- var baseEach = require__baseEach();
9674
- /**
9675
- * The base implementation of `_.filter` without support for iteratee shorthands.
9676
- *
9677
- * @private
9678
- * @param {Array|Object} collection The collection to iterate over.
9679
- * @param {Function} predicate The function invoked per iteration.
9680
- * @returns {Array} Returns the new filtered array.
9681
- */
9682
- function baseFilter$1(collection, predicate) {
9683
- var result = [];
9684
- baseEach(collection, function(value, index, collection$1) {
9685
- if (predicate(value, index, collection$1)) result.push(value);
9686
- });
9687
- return result;
9688
- }
9689
- module.exports = baseFilter$1;
9690
- } });
9691
-
9692
- //#endregion
9693
- //#region ../../node_modules/lodash/negate.js
9694
- var require_negate = __commonJS({ "../../node_modules/lodash/negate.js"(exports, module) {
9695
- /** Error message constants. */
9696
- var FUNC_ERROR_TEXT = "Expected a function";
9697
- /**
9698
- * Creates a function that negates the result of the predicate `func`. The
9699
- * `func` predicate is invoked with the `this` binding and arguments of the
9700
- * created function.
9701
- *
9702
- * @static
9703
- * @memberOf _
9704
- * @since 3.0.0
9705
- * @category Function
9706
- * @param {Function} predicate The predicate to negate.
9707
- * @returns {Function} Returns the new negated function.
9708
- * @example
9709
- *
9710
- * function isEven(n) {
9711
- * return n % 2 == 0;
9712
- * }
9713
- *
9714
- * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
9715
- * // => [1, 3, 5]
9716
- */
9717
- function negate$1(predicate) {
9718
- if (typeof predicate != "function") throw new TypeError(FUNC_ERROR_TEXT);
9719
- return function() {
9720
- var args = arguments;
9721
- switch (args.length) {
9722
- case 0: return !predicate.call(this);
9723
- case 1: return !predicate.call(this, args[0]);
9724
- case 2: return !predicate.call(this, args[0], args[1]);
9725
- case 3: return !predicate.call(this, args[0], args[1], args[2]);
9726
- }
9727
- return !predicate.apply(this, args);
9728
- };
9729
- }
9730
- module.exports = negate$1;
9731
- } });
9732
-
9733
- //#endregion
9734
- //#region ../../node_modules/lodash/reject.js
9735
- var require_reject = __commonJS({ "../../node_modules/lodash/reject.js"(exports, module) {
9736
- var arrayFilter = require__arrayFilter(), baseFilter = require__baseFilter(), baseIteratee = require__baseIteratee(), isArray = require_isArray(), negate = require_negate();
9737
- /**
9738
- * The opposite of `_.filter`; this method returns the elements of `collection`
9739
- * that `predicate` does **not** return truthy for.
9740
- *
9741
- * @static
9742
- * @memberOf _
9743
- * @since 0.1.0
9744
- * @category Collection
9745
- * @param {Array|Object} collection The collection to iterate over.
9746
- * @param {Function} [predicate=_.identity] The function invoked per iteration.
9747
- * @returns {Array} Returns the new filtered array.
9748
- * @see _.filter
9749
- * @example
9750
- *
9751
- * var users = [
9752
- * { 'user': 'barney', 'age': 36, 'active': false },
9753
- * { 'user': 'fred', 'age': 40, 'active': true }
9754
- * ];
9755
- *
9756
- * _.reject(users, function(o) { return !o.active; });
9757
- * // => objects for ['fred']
9758
- *
9759
- * // The `_.matches` iteratee shorthand.
9760
- * _.reject(users, { 'age': 40, 'active': true });
9761
- * // => objects for ['barney']
9762
- *
9763
- * // The `_.matchesProperty` iteratee shorthand.
9764
- * _.reject(users, ['active', false]);
9765
- * // => objects for ['fred']
9766
- *
9767
- * // The `_.property` iteratee shorthand.
9768
- * _.reject(users, 'active');
9769
- * // => objects for ['barney']
9770
- */
9771
- function reject(collection, predicate) {
9772
- var func = isArray(collection) ? arrayFilter : baseFilter;
9773
- return func(collection, negate(baseIteratee(predicate, 3)));
9774
- }
9775
- module.exports = reject;
9776
- } });
9777
- var import_reject = __toESM(require_reject(), 1);
9681
+ cancelActionCallback(actionName) {
9682
+ return () => {
9683
+ this.cancelAction(actionName);
9684
+ };
9685
+ }
9686
+ };
9687
+
9688
+ //#endregion
9689
+ //#region src/managers/store.ts
9690
+ var WeaveStoreManager = class {
9691
+ constructor(instance) {
9692
+ this.instance = instance;
9693
+ this.logger = this.instance.getChildLogger("store-manager");
9694
+ this.logger.debug("Store manager created");
9695
+ }
9696
+ getStore() {
9697
+ return this.store;
9698
+ }
9699
+ registerStore(store) {
9700
+ if (typeof this.store !== "undefined") {
9701
+ const msg = `Store already registered`;
9702
+ this.logger.error(msg);
9703
+ throw new Error(msg);
9704
+ }
9705
+ const storeInstance = store.register(this.instance);
9706
+ this.store = storeInstance;
9707
+ }
9708
+ };
9778
9709
 
9779
9710
  //#endregion
9780
9711
  //#region src/managers/export/export.ts
@@ -9784,6 +9715,155 @@ var WeaveExportManager = class {
9784
9715
  this.logger = this.instance.getChildLogger("export-manager");
9785
9716
  this.logger.debug("Export manager created");
9786
9717
  }
9718
+ parseExportOptions(options) {
9719
+ return {
9720
+ format: options.format ?? WEAVE_EXPORT_FORMATS.PNG,
9721
+ padding: options.padding ?? 0,
9722
+ pixelRatio: options.pixelRatio ?? 1,
9723
+ backgroundColor: options.backgroundColor ?? WEAVE_EXPORT_BACKGROUND_COLOR
9724
+ };
9725
+ }
9726
+ saveAndDisablePlugins() {
9727
+ const nodesSelectionPluginPrev = this.getNodesSelectionPlugin()?.isEnabled();
9728
+ const nodesStageGridPluginPrev = this.getStageGridPlugin()?.isEnabled();
9729
+ this.getNodesSelectionPlugin()?.disable();
9730
+ this.getStageGridPlugin()?.disable();
9731
+ return {
9732
+ nodesSelectionPluginPrev,
9733
+ nodesStageGridPluginPrev
9734
+ };
9735
+ }
9736
+ restorePlugins(nodesSelectionPluginPrev, nodesStageGridPluginPrev) {
9737
+ if (nodesSelectionPluginPrev) this.getNodesSelectionPlugin()?.enable();
9738
+ if (nodesStageGridPluginPrev) this.getStageGridPlugin()?.enable();
9739
+ }
9740
+ saveAndResetStage(resetPosition = false) {
9741
+ const stage = this.instance.getStage();
9742
+ const originalPosition = {
9743
+ x: stage.x(),
9744
+ y: stage.y()
9745
+ };
9746
+ const originalScale = {
9747
+ x: stage.scaleX(),
9748
+ y: stage.scaleY()
9749
+ };
9750
+ stage.scale({
9751
+ x: 1,
9752
+ y: 1
9753
+ });
9754
+ if (resetPosition) stage.position({
9755
+ x: 0,
9756
+ y: 0
9757
+ });
9758
+ return {
9759
+ stage,
9760
+ originalPosition,
9761
+ originalScale
9762
+ };
9763
+ }
9764
+ restoreStage(stage, originalPosition, originalScale) {
9765
+ stage.position(originalPosition);
9766
+ stage.scale(originalScale);
9767
+ stage.batchDraw();
9768
+ }
9769
+ buildNodesExportGroup(nodes, boundingNodes, stage, mainLayer, padding, backgroundColor) {
9770
+ const bounds = getExportBoundingBox(boundingNodes(nodes));
9771
+ const scaleX = stage.scaleX();
9772
+ const scaleY = stage.scaleY();
9773
+ const unscaledBounds = {
9774
+ x: bounds.x / scaleX,
9775
+ y: bounds.y / scaleY,
9776
+ width: bounds.width / scaleX,
9777
+ height: bounds.height / scaleY
9778
+ };
9779
+ const exportGroup = new Konva.Group();
9780
+ const background = new Konva.Rect({
9781
+ x: unscaledBounds.x - padding,
9782
+ y: unscaledBounds.y - padding,
9783
+ width: unscaledBounds.width + 2 * padding,
9784
+ height: unscaledBounds.height + 2 * padding,
9785
+ strokeWidth: 0,
9786
+ fill: backgroundColor
9787
+ });
9788
+ exportGroup.add(background);
9789
+ for (const node of nodes) {
9790
+ const clonedNode = node.clone({ id: v4_default() });
9791
+ const absPos = node.getAbsolutePosition();
9792
+ clonedNode.absolutePosition({
9793
+ x: absPos.x / scaleX,
9794
+ y: absPos.y / scaleY
9795
+ });
9796
+ exportGroup.add(clonedNode);
9797
+ }
9798
+ mainLayer.add(exportGroup);
9799
+ const backgroundRect = background.getClientRect();
9800
+ stage.batchDraw();
9801
+ return {
9802
+ exportGroup,
9803
+ background,
9804
+ backgroundRect
9805
+ };
9806
+ }
9807
+ buildAreaBackground(area, stage, mainLayer, padding, backgroundColor, relativeToStage = false) {
9808
+ const bounds = area;
9809
+ const scaleX = stage.scaleX();
9810
+ const scaleY = stage.scaleY();
9811
+ const unscaledBounds = {
9812
+ x: bounds.x / scaleX,
9813
+ y: bounds.y / scaleY,
9814
+ width: bounds.width / scaleX,
9815
+ height: bounds.height / scaleY
9816
+ };
9817
+ const background = new Konva.Rect({
9818
+ x: unscaledBounds.x - padding,
9819
+ y: unscaledBounds.y - padding,
9820
+ width: unscaledBounds.width + 2 * padding,
9821
+ height: unscaledBounds.height + 2 * padding,
9822
+ strokeWidth: 0,
9823
+ fill: backgroundColor
9824
+ });
9825
+ mainLayer.add(background);
9826
+ background.moveToBottom();
9827
+ stage.batchDraw();
9828
+ const backgroundRect = relativeToStage ? background.getClientRect({ relativeTo: stage }) : background.getClientRect();
9829
+ return {
9830
+ background,
9831
+ backgroundRect
9832
+ };
9833
+ }
9834
+ async renderTiles(source, backgroundRect, format, pixelRatio, quality) {
9835
+ const composites = [];
9836
+ const imageWidth = Math.round(backgroundRect.width);
9837
+ const imageHeight = Math.round(backgroundRect.height);
9838
+ const maxRenderSize = 1920;
9839
+ const cols = Math.ceil(imageWidth / maxRenderSize);
9840
+ const rows = Math.ceil(imageHeight / maxRenderSize);
9841
+ const tileWidth = Math.floor(imageWidth / cols);
9842
+ const tileHeight = Math.floor(imageHeight / rows);
9843
+ for (let y = 0; y < imageHeight; y += tileHeight) for (let x = 0; x < imageWidth; x += tileWidth) {
9844
+ const width = Math.min(tileWidth, imageWidth - x);
9845
+ const height = Math.min(tileHeight, imageHeight - y);
9846
+ const canvas = await source.toCanvas({
9847
+ x: Math.round(backgroundRect.x) + x,
9848
+ y: Math.round(backgroundRect.y) + y,
9849
+ width,
9850
+ height,
9851
+ mimeType: format,
9852
+ pixelRatio,
9853
+ quality
9854
+ });
9855
+ let buffer = null;
9856
+ if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.CANVAS) buffer = canvas.toBuffer();
9857
+ if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.SKIA) buffer = await canvas.toBuffer();
9858
+ if (!buffer) throw new Error("Failed to generate image buffer");
9859
+ composites.push({
9860
+ top: y * pixelRatio,
9861
+ left: x * pixelRatio,
9862
+ input: buffer
9863
+ });
9864
+ }
9865
+ return { composites };
9866
+ }
9787
9867
  fitKonvaPixelRatio(sw, sh, targetPR = 1, maxArea = 16777216) {
9788
9868
  if (sw <= 0 || sh <= 0) return {
9789
9869
  pixelRatio: 0,
@@ -9893,7 +9973,7 @@ var WeaveExportManager = class {
9893
9973
  });
9894
9974
  }
9895
9975
  exportNodesAsBlob(nodes, boundingNodes, options) {
9896
- return new Promise((resolve) => {
9976
+ return new Promise((resolve, reject) => {
9897
9977
  const { format = WEAVE_EXPORT_FORMATS.PNG } = options;
9898
9978
  const { stage, mainLayer, originalScale: { scaleX, scaleY } } = this.cloneStageForExport();
9899
9979
  if (mainLayer) {
@@ -9919,7 +9999,7 @@ var WeaveExportManager = class {
9919
9999
  exportGroup.destroy();
9920
10000
  stage.destroy();
9921
10001
  if (!blob) {
9922
- (0, import_reject.default)(new Error("Failed to generate image blob"));
10002
+ reject(new Error("Failed to generate image blob"));
9923
10003
  return;
9924
10004
  }
9925
10005
  resolve(blob);
@@ -9992,7 +10072,7 @@ var WeaveExportManager = class {
9992
10072
  });
9993
10073
  }
9994
10074
  exportAreaAsBlob(area, options) {
9995
- return new Promise((resolve) => {
10075
+ return new Promise((resolve, reject) => {
9996
10076
  const { format = WEAVE_EXPORT_FORMATS.PNG } = options;
9997
10077
  const { stage, mainLayer, originalScale: { scaleX, scaleY } } = this.cloneStageForExport();
9998
10078
  if (mainLayer) {
@@ -10017,7 +10097,7 @@ var WeaveExportManager = class {
10017
10097
  callback: (blob) => {
10018
10098
  stage.destroy();
10019
10099
  if (!blob) {
10020
- (0, import_reject.default)(new Error("Failed to generate image blob"));
10100
+ reject(new Error("Failed to generate image blob"));
10021
10101
  return;
10022
10102
  }
10023
10103
  resolve(blob);
@@ -10058,24 +10138,11 @@ var WeaveExportManager = class {
10058
10138
  });
10059
10139
  }
10060
10140
  async exportNodesServerSide(nodes, boundingNodes, options) {
10061
- const { format = WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = WEAVE_EXPORT_BACKGROUND_COLOR } = options;
10062
- this.getNodesSelectionPlugin()?.disable();
10063
- this.getStageGridPlugin()?.disable();
10064
- const stage = this.instance.getStage();
10141
+ const { format, padding, pixelRatio, backgroundColor } = this.parseExportOptions(options);
10142
+ const { nodesSelectionPluginPrev, nodesStageGridPluginPrev } = this.saveAndDisablePlugins();
10143
+ const { stage, originalPosition, originalScale } = this.saveAndResetStage();
10065
10144
  const mainLayer = this.instance.getMainLayer();
10066
10145
  if (!mainLayer) throw new Error("Main layer not found");
10067
- const originalPosition = {
10068
- x: stage.x(),
10069
- y: stage.y()
10070
- };
10071
- const originalScale = {
10072
- x: stage.scaleX(),
10073
- y: stage.scaleY()
10074
- };
10075
- stage.scale({
10076
- x: 1,
10077
- y: 1
10078
- });
10079
10146
  let realNodes = [...nodes];
10080
10147
  if (nodes.length === 0) realNodes = mainLayer.getChildren().map((node) => node.getAttrs().id ?? "") ?? [];
10081
10148
  const konvaNodes = [];
@@ -10083,153 +10150,32 @@ var WeaveExportManager = class {
10083
10150
  const node = stage.findOne(`#${nodeId}`);
10084
10151
  if (node) konvaNodes.push(node);
10085
10152
  }
10086
- const bounds = getExportBoundingBox(boundingNodes(konvaNodes));
10087
- const scaleX = stage.scaleX();
10088
- const scaleY = stage.scaleY();
10089
- const unscaledBounds = {
10090
- x: bounds.x / scaleX,
10091
- y: bounds.y / scaleY,
10092
- width: bounds.width / scaleX,
10093
- height: bounds.height / scaleY
10094
- };
10095
- const exportGroup = new Konva.Group();
10096
- const background = new Konva.Rect({
10097
- x: unscaledBounds.x - padding,
10098
- y: unscaledBounds.y - padding,
10099
- width: unscaledBounds.width + 2 * padding,
10100
- height: unscaledBounds.height + 2 * padding,
10101
- strokeWidth: 0,
10102
- fill: backgroundColor
10103
- });
10104
- exportGroup.add(background);
10105
- for (const node of konvaNodes) {
10106
- const clonedNode = node.clone({ id: v4_default() });
10107
- const absPos = node.getAbsolutePosition();
10108
- clonedNode.absolutePosition({
10109
- x: absPos.x / scaleX,
10110
- y: absPos.y / scaleY
10111
- });
10112
- exportGroup.add(clonedNode);
10113
- }
10114
- mainLayer.add(exportGroup);
10115
- const backgroundRect = background.getClientRect();
10116
- const composites = [];
10153
+ const { exportGroup, backgroundRect } = this.buildNodesExportGroup(konvaNodes, boundingNodes, stage, mainLayer, padding, backgroundColor);
10154
+ const { composites } = await this.renderTiles(exportGroup, backgroundRect, format, pixelRatio, options.quality ?? 1);
10117
10155
  const imageWidth = Math.round(backgroundRect.width);
10118
10156
  const imageHeight = Math.round(backgroundRect.height);
10119
- const maxRenderSize = 1920;
10120
- const cols = Math.ceil(imageWidth / maxRenderSize);
10121
- const rows = Math.ceil(imageHeight / maxRenderSize);
10122
- const tileWidth = Math.floor(imageWidth / cols);
10123
- const tileHeight = Math.floor(imageHeight / rows);
10124
- for (let y = 0; y < imageHeight; y += tileHeight) for (let x = 0; x < imageWidth; x += tileWidth) {
10125
- const width = Math.min(tileWidth, imageWidth - x);
10126
- const height = Math.min(tileHeight, imageHeight - y);
10127
- const canvas = await exportGroup.toCanvas({
10128
- x: Math.round(backgroundRect.x) + x,
10129
- y: Math.round(backgroundRect.y) + y,
10130
- width,
10131
- height,
10132
- mimeType: format,
10133
- pixelRatio,
10134
- quality: options.quality ?? 1
10135
- });
10136
- let buffer = null;
10137
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.CANVAS) buffer = canvas.toBuffer();
10138
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.SKIA) buffer = await canvas.toBuffer();
10139
- if (!buffer) throw new Error("Failed to generate image buffer");
10140
- composites.push({
10141
- top: y * pixelRatio,
10142
- left: x * pixelRatio,
10143
- input: buffer
10144
- });
10145
- }
10146
10157
  exportGroup.destroy();
10147
- stage.position(originalPosition);
10148
- stage.scale(originalScale);
10149
- stage.batchDraw();
10150
- this.getNodesSelectionPlugin()?.enable();
10151
- this.getStageGridPlugin()?.enable();
10152
- return {
10153
- composites,
10154
- width: imageWidth * pixelRatio,
10155
- height: imageHeight * pixelRatio
10156
- };
10157
- }
10158
- async exportAreaServerSide(area, options) {
10159
- const { format = WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = WEAVE_EXPORT_BACKGROUND_COLOR } = options;
10160
- this.getNodesSelectionPlugin()?.disable();
10161
- this.getStageGridPlugin()?.disable();
10162
- const stage = this.instance.getStage();
10163
- const mainLayer = this.instance.getMainLayer();
10164
- if (!mainLayer) throw new Error("Main layer not found");
10165
- const originalPosition = {
10166
- x: stage.x(),
10167
- y: stage.y()
10168
- };
10169
- const originalScale = {
10170
- x: stage.scaleX(),
10171
- y: stage.scaleY()
10172
- };
10173
- stage.scale({
10174
- x: 1,
10175
- y: 1
10176
- });
10177
- const bounds = area;
10178
- const scaleX = stage.scaleX();
10179
- const scaleY = stage.scaleY();
10180
- const unscaledBounds = {
10181
- x: bounds.x / scaleX,
10182
- y: bounds.y / scaleY,
10183
- width: bounds.width / scaleX,
10184
- height: bounds.height / scaleY
10158
+ this.restoreStage(stage, originalPosition, originalScale);
10159
+ this.restorePlugins(nodesSelectionPluginPrev, nodesStageGridPluginPrev);
10160
+ return {
10161
+ composites,
10162
+ width: imageWidth * pixelRatio,
10163
+ height: imageHeight * pixelRatio
10185
10164
  };
10186
- const background = new Konva.Rect({
10187
- x: unscaledBounds.x - padding,
10188
- y: unscaledBounds.y - padding,
10189
- width: unscaledBounds.width + 2 * padding,
10190
- height: unscaledBounds.height + 2 * padding,
10191
- strokeWidth: 0,
10192
- fill: backgroundColor
10193
- });
10194
- mainLayer.add(background);
10195
- background.moveToBottom();
10196
- const backgroundRect = background.getClientRect({ relativeTo: stage });
10197
- const composites = [];
10165
+ }
10166
+ async exportAreaServerSide(area, options) {
10167
+ const { format, padding, pixelRatio, backgroundColor } = this.parseExportOptions(options);
10168
+ const { nodesSelectionPluginPrev, nodesStageGridPluginPrev } = this.saveAndDisablePlugins();
10169
+ const { stage, originalPosition, originalScale } = this.saveAndResetStage();
10170
+ const mainLayer = this.instance.getMainLayer();
10171
+ if (!mainLayer) throw new Error("Main layer not found");
10172
+ const { background, backgroundRect } = this.buildAreaBackground(area, stage, mainLayer, padding, backgroundColor, true);
10173
+ const { composites } = await this.renderTiles(mainLayer, backgroundRect, format, pixelRatio, options.quality ?? 1);
10198
10174
  const imageWidth = Math.round(backgroundRect.width);
10199
10175
  const imageHeight = Math.round(backgroundRect.height);
10200
- const maxRenderSize = 1920;
10201
- const cols = Math.ceil(imageWidth / maxRenderSize);
10202
- const rows = Math.ceil(imageHeight / maxRenderSize);
10203
- const tileWidth = Math.floor(imageWidth / cols);
10204
- const tileHeight = Math.floor(imageHeight / rows);
10205
- for (let y = 0; y < imageHeight; y += tileHeight) for (let x = 0; x < imageWidth; x += tileWidth) {
10206
- const width = Math.min(tileWidth, imageWidth - x);
10207
- const height = Math.min(tileHeight, imageHeight - y);
10208
- const canvas = await mainLayer.toCanvas({
10209
- x: Math.round(backgroundRect.x) + x,
10210
- y: Math.round(backgroundRect.y) + y,
10211
- width,
10212
- height,
10213
- mimeType: format,
10214
- pixelRatio,
10215
- quality: options.quality ?? 1
10216
- });
10217
- let buffer = null;
10218
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.CANVAS) buffer = canvas.toBuffer();
10219
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.SKIA) buffer = await canvas.toBuffer();
10220
- if (!buffer) throw new Error("Failed to generate image buffer");
10221
- composites.push({
10222
- top: y * pixelRatio,
10223
- left: x * pixelRatio,
10224
- input: buffer
10225
- });
10226
- }
10227
10176
  background.destroy();
10228
- stage.position(originalPosition);
10229
- stage.scale(originalScale);
10230
- stage.batchDraw();
10231
- this.getNodesSelectionPlugin()?.enable();
10232
- this.getStageGridPlugin()?.enable();
10177
+ this.restoreStage(stage, originalPosition, originalScale);
10178
+ this.restorePlugins(nodesSelectionPluginPrev, nodesStageGridPluginPrev);
10233
10179
  return {
10234
10180
  composites,
10235
10181
  width: imageWidth * pixelRatio,
@@ -10257,10 +10203,10 @@ var WeaveExportManager = class {
10257
10203
  return gridPlugin;
10258
10204
  }
10259
10205
  blobToDataURL(blob) {
10260
- return new Promise((resolve, reject$1) => {
10206
+ return new Promise((resolve, reject) => {
10261
10207
  const reader = new FileReader();
10262
10208
  reader.onloadend = () => resolve(reader.result);
10263
- reader.onerror = () => reject$1(new Error("Failed to convert blob to data URL"));
10209
+ reader.onerror = () => reject(new Error("Failed to convert blob to data URL"));
10264
10210
  reader.readAsDataURL(blob);
10265
10211
  });
10266
10212
  }
@@ -11507,6 +11453,7 @@ var Weave = class {
11507
11453
  return this.dragAndDropManager.getDragProperties();
11508
11454
  }
11509
11455
  getEventsController() {
11456
+ if (!this.eventsController) throw new Error("Events controller not initialized");
11510
11457
  return this.eventsController;
11511
11458
  }
11512
11459
  getHooks() {
@@ -11525,14 +11472,14 @@ var Weave = class {
11525
11472
  //#endregion
11526
11473
  //#region src/utils/image.ts
11527
11474
  function loadImageSource(image, options) {
11528
- return new Promise((resolve, reject$1) => {
11475
+ return new Promise((resolve, reject) => {
11529
11476
  const { crossOrigin } = mergeExceptArrays({ crossOrigin: "anonymous" }, options);
11530
11477
  const reader = new FileReader();
11531
11478
  reader.onloadend = () => {
11532
11479
  const imageSource = Konva.Util.createImageElement();
11533
11480
  imageSource.crossOrigin = crossOrigin;
11534
11481
  imageSource.onerror = () => {
11535
- reject$1(new Error("Failed to load image source"));
11482
+ reject(new Error("Failed to load image source"));
11536
11483
  };
11537
11484
  imageSource.onload = async () => {
11538
11485
  resolve(imageSource);
@@ -11540,7 +11487,7 @@ function loadImageSource(image, options) {
11540
11487
  imageSource.src = reader.result;
11541
11488
  };
11542
11489
  reader.onerror = () => {
11543
- reject$1(new Error("Failed to read image file"));
11490
+ reject(new Error("Failed to read image file"));
11544
11491
  };
11545
11492
  reader.readAsDataURL(image);
11546
11493
  });
@@ -11561,12 +11508,12 @@ async function downscaleImageFile(file, ratio) {
11561
11508
  });
11562
11509
  }
11563
11510
  function getImageSizeFromFile(file) {
11564
- return new Promise((resolve, reject$1) => {
11511
+ return new Promise((resolve, reject) => {
11565
11512
  const img = new Image();
11566
11513
  const url = URL.createObjectURL(file);
11567
11514
  img.onload = () => {
11568
11515
  if (img.naturalWidth === 0) {
11569
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11516
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11570
11517
  return;
11571
11518
  }
11572
11519
  resolve({
@@ -11576,7 +11523,7 @@ function getImageSizeFromFile(file) {
11576
11523
  URL.revokeObjectURL(url);
11577
11524
  };
11578
11525
  img.onerror = () => {
11579
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11526
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11580
11527
  };
11581
11528
  img.src = url;
11582
11529
  });
@@ -11591,7 +11538,7 @@ function getDownscaleRatio(width, height, options) {
11591
11538
  return Math.min(widthRatio, heightRatio, 1);
11592
11539
  }
11593
11540
  const downscaleImageFromURL = (url, options) => {
11594
- return new Promise((resolve, reject$1) => {
11541
+ return new Promise((resolve, reject) => {
11595
11542
  const { type, crossOrigin, maxWidth, maxHeight } = mergeExceptArrays({
11596
11543
  type: "image/png",
11597
11544
  crossOrigin: "anonymous",
@@ -11602,7 +11549,7 @@ const downscaleImageFromURL = (url, options) => {
11602
11549
  img.crossOrigin = crossOrigin;
11603
11550
  img.onload = () => {
11604
11551
  if (img.naturalWidth === 0) {
11605
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11552
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11606
11553
  return;
11607
11554
  }
11608
11555
  const ratio = Math.min(maxWidth / img.width, maxHeight / img.height, 1);
@@ -11618,7 +11565,7 @@ const downscaleImageFromURL = (url, options) => {
11618
11565
  resolve(dataURL);
11619
11566
  };
11620
11567
  img.onerror = () => {
11621
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11568
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11622
11569
  };
11623
11570
  img.src = url;
11624
11571
  });
@@ -11735,10 +11682,10 @@ var WeaveStageNode = class extends WeaveNode {
11735
11682
  container.setAttribute("tabindex", "0");
11736
11683
  stage.container().addEventListener("focus", () => {
11737
11684
  this.stageFocused = true;
11738
- }, { signal: this.instance.getEventsController()?.signal });
11685
+ }, { signal: this.instance.getEventsController().signal });
11739
11686
  stage.container().addEventListener("blur", () => {
11740
11687
  this.stageFocused = false;
11741
- }, { signal: this.instance.getEventsController()?.signal });
11688
+ }, { signal: this.instance.getEventsController().signal });
11742
11689
  }
11743
11690
  Konva.Stage.prototype.mode = function(mode) {
11744
11691
  if (typeof mode !== "undefined") this._mode = mode;
@@ -11805,7 +11752,7 @@ var WeaveStageNode = class extends WeaveNode {
11805
11752
  const selectedNode = transformer.nodes()[0];
11806
11753
  selectedNode.fire("onCmdCtrlPressed");
11807
11754
  }
11808
- }, { signal: this.instance.getEventsController()?.signal });
11755
+ }, { signal: this.instance.getEventsController().signal });
11809
11756
  window.addEventListener("keyup", (e) => {
11810
11757
  if (!(e.ctrlKey || e.metaKey)) {
11811
11758
  this.instance.getStage().container().style.cursor = "default";
@@ -11815,7 +11762,7 @@ var WeaveStageNode = class extends WeaveNode {
11815
11762
  const selectedNode = transformer.nodes()[0];
11816
11763
  selectedNode.fire("onCmdCtrlReleased");
11817
11764
  }
11818
- }, { signal: this.instance.getEventsController()?.signal });
11765
+ }, { signal: this.instance.getEventsController().signal });
11819
11766
  this.globalEventsInitialized = true;
11820
11767
  }
11821
11768
  isOnlyCtrlOrMeta(event) {
@@ -12781,7 +12728,7 @@ var WeaveTextNode = class extends WeaveNode {
12781
12728
  onAdd() {
12782
12729
  if (!this.instance.isServerSide() && !this.keyPressHandler) {
12783
12730
  this.keyPressHandler = this.handleKeyPress.bind(this);
12784
- window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController()?.signal });
12731
+ window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController().signal });
12785
12732
  }
12786
12733
  }
12787
12734
  onRender(props) {
@@ -12940,7 +12887,7 @@ var WeaveTextNode = class extends WeaveNode {
12940
12887
  });
12941
12888
  if (!this.instance.isServerSide() && !this.keyPressHandler) {
12942
12889
  this.keyPressHandler = this.handleKeyPress.bind(this);
12943
- window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController()?.signal });
12890
+ window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController().signal });
12944
12891
  }
12945
12892
  return text;
12946
12893
  }
@@ -13188,17 +13135,17 @@ var WeaveTextNode = class extends WeaveNode {
13188
13135
  this.textAreaSuperContainer.scrollTop = 0;
13189
13136
  this.textAreaSuperContainer.scrollLeft = 0;
13190
13137
  }
13191
- }, { signal: this.instance.getEventsController()?.signal });
13138
+ }, { signal: this.instance.getEventsController().signal });
13192
13139
  this.textAreaContainer.addEventListener("scroll", () => {
13193
13140
  if (!this.textAreaContainer) return;
13194
13141
  this.textAreaContainer.scrollTop = 0;
13195
13142
  this.textAreaContainer.scrollLeft = 0;
13196
- }, { signal: this.instance.getEventsController()?.signal });
13143
+ }, { signal: this.instance.getEventsController().signal });
13197
13144
  this.textArea.addEventListener("scroll", () => {
13198
13145
  if (!this.textArea) return;
13199
13146
  this.textArea.scrollTop = 0;
13200
13147
  this.textArea.scrollLeft = 0;
13201
- }, { signal: this.instance.getEventsController()?.signal });
13148
+ }, { signal: this.instance.getEventsController().signal });
13202
13149
  const rotation = textNode.getAbsoluteRotation();
13203
13150
  if (rotation) {
13204
13151
  const transform = "rotate(" + rotation + "deg)";
@@ -13248,8 +13195,8 @@ var WeaveTextNode = class extends WeaveNode {
13248
13195
  this.textAreaDomResize(textNode);
13249
13196
  }
13250
13197
  };
13251
- this.textArea.addEventListener("keydown", handleKeyDown, { signal: this.instance.getEventsController()?.signal });
13252
- this.textArea.addEventListener("keyup", handleKeyUp, { signal: this.instance.getEventsController()?.signal });
13198
+ this.textArea.addEventListener("keydown", handleKeyDown, { signal: this.instance.getEventsController().signal });
13199
+ this.textArea.addEventListener("keyup", handleKeyUp, { signal: this.instance.getEventsController().signal });
13253
13200
  this.textArea.tabIndex = 1;
13254
13201
  this.textArea.focus();
13255
13202
  const handleOutsideClick = (e) => {
@@ -13275,7 +13222,7 @@ var WeaveTextNode = class extends WeaveNode {
13275
13222
  }
13276
13223
  };
13277
13224
  setTimeout(() => {
13278
- window.addEventListener("pointerup", handleOutsideClick, { signal: this.instance.getEventsController()?.signal });
13225
+ window.addEventListener("pointerup", handleOutsideClick, { signal: this.instance.getEventsController().signal });
13279
13226
  }, 0);
13280
13227
  this.instance.getStage().mode(WEAVE_STAGE_TEXT_EDITION_MODE);
13281
13228
  this.editing = true;
@@ -13735,7 +13682,7 @@ var WeaveImageCrop = class WeaveImageCrop {
13735
13682
  utilityLayer?.add(this.transformer);
13736
13683
  this.transformer?.forceUpdate();
13737
13684
  this.cropGroup.show();
13738
- window.addEventListener("keydown", this.handleHide, { signal: this.instance.getEventsController()?.signal });
13685
+ if (!this.instance.isServerSide()) window.addEventListener("keydown", this.handleHide, { signal: this.instance.getEventsController().signal });
13739
13686
  if (options.cmdCtrl.triggered) {
13740
13687
  utilityLayer?.hide();
13741
13688
  const stage = this.instance.getStage();
@@ -16837,10 +16784,10 @@ var WeaveStrokeSingleNode = class extends WeaveNode {
16837
16784
  if (this.eventsInitialized) return;
16838
16785
  window.addEventListener("keydown", (e) => {
16839
16786
  if (e.key === "Shift") this.shiftPressed = true;
16840
- }, { signal: this.instance.getEventsController()?.signal });
16787
+ }, { signal: this.instance.getEventsController().signal });
16841
16788
  window.addEventListener("keyup", (e) => {
16842
16789
  if (e.key === "Shift") this.shiftPressed = false;
16843
- }, { signal: this.instance.getEventsController()?.signal });
16790
+ }, { signal: this.instance.getEventsController().signal });
16844
16791
  this.eventsInitialized = true;
16845
16792
  }
16846
16793
  onRender(props) {
@@ -20927,7 +20874,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
20927
20874
  }
20928
20875
  }, {
20929
20876
  passive: false,
20930
- signal: this.instance.getEventsController()?.signal
20877
+ signal: this.instance.getEventsController().signal
20931
20878
  });
20932
20879
  stage.getContent().addEventListener("touchmove", (e) => {
20933
20880
  e.preventDefault();
@@ -20970,7 +20917,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
20970
20917
  }
20971
20918
  }, {
20972
20919
  passive: false,
20973
- signal: this.instance.getEventsController()?.signal
20920
+ signal: this.instance.getEventsController().signal
20974
20921
  });
20975
20922
  stage.getContent().addEventListener("touchend", () => {
20976
20923
  this.pinching = false;
@@ -20978,7 +20925,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
20978
20925
  lastCenter = null;
20979
20926
  }, {
20980
20927
  passive: false,
20981
- signal: this.instance.getEventsController()?.signal
20928
+ signal: this.instance.getEventsController().signal
20982
20929
  });
20983
20930
  let doZoom = false;
20984
20931
  const handleWheelImmediate = (e) => {
@@ -20999,7 +20946,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
20999
20946
  doZoom = true;
21000
20947
  };
21001
20948
  window.addEventListener("wheel", handleWheelImmediate, {
21002
- signal: this.instance.getEventsController()?.signal,
20949
+ signal: this.instance.getEventsController().signal,
21003
20950
  passive: false
21004
20951
  });
21005
20952
  const handleWheel = (e) => {
@@ -21015,7 +20962,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21015
20962
  };
21016
20963
  const throttledHandleWheel = (0, import_throttle.default)(handleWheel, DEFAULT_THROTTLE_MS);
21017
20964
  window.addEventListener("wheel", throttledHandleWheel, {
21018
- signal: this.instance.getEventsController()?.signal,
20965
+ signal: this.instance.getEventsController().signal,
21019
20966
  passive: true
21020
20967
  });
21021
20968
  }
@@ -21243,7 +21190,7 @@ var WeaveMoveToolAction = class extends WeaveAction {
21243
21190
  this.cancelAction();
21244
21191
  return;
21245
21192
  }
21246
- }, { signal: this.instance.getEventsController()?.signal });
21193
+ }, { signal: this.instance.getEventsController().signal });
21247
21194
  stage.on("pointerdown", () => {
21248
21195
  if ([MOVE_TOOL_ACTION_NAME].includes(this.instance.getActiveAction() ?? "")) stage.container().style.cursor = "grabbing";
21249
21196
  });
@@ -21404,7 +21351,7 @@ var WeaveEraserToolAction = class extends WeaveAction {
21404
21351
  this.cancelAction();
21405
21352
  return;
21406
21353
  }
21407
- }, { signal: this.instance.getEventsController()?.signal });
21354
+ }, { signal: this.instance.getEventsController().signal });
21408
21355
  this.initialized = true;
21409
21356
  }
21410
21357
  setState(state) {
@@ -21509,7 +21456,7 @@ var WeaveRectangleToolAction = class extends WeaveAction {
21509
21456
  this.cancelAction();
21510
21457
  return;
21511
21458
  }
21512
- }, { signal: this.instance.getEventsController()?.signal });
21459
+ }, { signal: this.instance.getEventsController().signal });
21513
21460
  stage.on("pointermove", () => {
21514
21461
  if (this.state === RECTANGLE_TOOL_STATE.IDLE) return;
21515
21462
  this.setCursor();
@@ -21730,7 +21677,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
21730
21677
  this.cancelAction();
21731
21678
  return;
21732
21679
  }
21733
- }, { signal: this.instance.getEventsController()?.signal });
21680
+ }, { signal: this.instance.getEventsController().signal });
21734
21681
  stage.on("pointerdown", (e) => {
21735
21682
  this.setTapStart(e);
21736
21683
  this.pointers.set(e.evt.pointerId, {
@@ -21949,7 +21896,7 @@ var WeavePenToolAction = class extends WeaveAction {
21949
21896
  this.cancelAction();
21950
21897
  return;
21951
21898
  }
21952
- }, { signal: this.instance.getEventsController()?.signal });
21899
+ }, { signal: this.instance.getEventsController().signal });
21953
21900
  stage.on("pointerdown", (e) => {
21954
21901
  this.setTapStart(e);
21955
21902
  this.pointers.set(e.evt.pointerId, {
@@ -22233,13 +22180,13 @@ var WeaveLineToolAction = class extends WeaveAction {
22233
22180
  this.snappedAngle = null;
22234
22181
  this.shiftPressed = true;
22235
22182
  }
22236
- }, { signal: this.instance.getEventsController()?.signal });
22183
+ }, { signal: this.instance.getEventsController().signal });
22237
22184
  window.addEventListener("keyup", (e) => {
22238
22185
  if (e.key === "Shift" && this.instance.getActiveAction() === LINE_TOOL_ACTION_NAME) {
22239
22186
  this.snappedAngle = null;
22240
22187
  this.shiftPressed = false;
22241
22188
  }
22242
- }, { signal: this.instance.getEventsController()?.signal });
22189
+ }, { signal: this.instance.getEventsController().signal });
22243
22190
  stage.on("pointerdown", (e) => {
22244
22191
  this.setTapStart(e);
22245
22192
  this.pointers.set(e.evt.pointerId, {
@@ -22508,7 +22455,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
22508
22455
  stage.container().style.touchAction = "none";
22509
22456
  window.addEventListener("keyup", (e) => {
22510
22457
  if (e.code === "Space" && this.instance.getActiveAction() === BRUSH_TOOL_ACTION_NAME) this.isSpacePressed = false;
22511
- }, { signal: this.instance.getEventsController()?.signal });
22458
+ }, { signal: this.instance.getEventsController().signal });
22512
22459
  window.addEventListener("keydown", (e) => {
22513
22460
  if (e.code === "Enter" && this.instance.getActiveAction() === BRUSH_TOOL_ACTION_NAME) {
22514
22461
  e.stopPropagation();
@@ -22524,8 +22471,8 @@ var WeaveBrushToolAction = class extends WeaveAction {
22524
22471
  e.stopPropagation();
22525
22472
  this.cancelAction();
22526
22473
  }
22527
- }, { signal: this.instance.getEventsController()?.signal });
22528
- const handlePointerDown = (e) => {
22474
+ }, { signal: this.instance.getEventsController().signal });
22475
+ const handlePointerDown$1 = (e) => {
22529
22476
  if (this.state === BRUSH_TOOL_STATE.INACTIVE) return;
22530
22477
  if (this.state !== BRUSH_TOOL_STATE.IDLE) return;
22531
22478
  if (this.getZoomPlugin()?.isPinching()) return;
@@ -22537,8 +22484,8 @@ var WeaveBrushToolAction = class extends WeaveAction {
22537
22484
  this.handleStartStroke(pointPressure);
22538
22485
  e.evt.stopPropagation();
22539
22486
  };
22540
- stage.on("pointerdown", handlePointerDown);
22541
- const handlePointerMove = (e) => {
22487
+ stage.on("pointerdown", handlePointerDown$1);
22488
+ const handlePointerMove$1 = (e) => {
22542
22489
  if (this.state === BRUSH_TOOL_STATE.INACTIVE) return;
22543
22490
  this.setCursor();
22544
22491
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
@@ -22561,15 +22508,15 @@ var WeaveBrushToolAction = class extends WeaveAction {
22561
22508
  }
22562
22509
  e.evt.stopPropagation();
22563
22510
  };
22564
- stage.on("pointermove", handlePointerMove);
22565
- const handlePointerUp = (e) => {
22511
+ stage.on("pointermove", handlePointerMove$1);
22512
+ const handlePointerUp$1 = (e) => {
22566
22513
  this.penActive = false;
22567
22514
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
22568
22515
  if (this.getZoomPlugin()?.isPinching()) return;
22569
22516
  this.handleEndStroke();
22570
22517
  e.evt.stopPropagation();
22571
22518
  };
22572
- stage.on("pointerup", handlePointerUp);
22519
+ stage.on("pointerup", handlePointerUp$1);
22573
22520
  this.initialized = true;
22574
22521
  }
22575
22522
  setState(state) {
@@ -22801,7 +22748,7 @@ var WeaveTextToolAction = class extends WeaveAction {
22801
22748
  this.cancelAction();
22802
22749
  return;
22803
22750
  }
22804
- }, { signal: this.instance.getEventsController()?.signal });
22751
+ }, { signal: this.instance.getEventsController().signal });
22805
22752
  stage.on("pointermove", () => {
22806
22753
  if (this.state === TEXT_TOOL_STATE.IDLE) return;
22807
22754
  this.setCursor();
@@ -22977,7 +22924,7 @@ var WeaveImageToolAction = class extends WeaveAction {
22977
22924
  this.cancelAction();
22978
22925
  return;
22979
22926
  }
22980
- }, { signal: this.instance.getEventsController()?.signal });
22927
+ }, { signal: this.instance.getEventsController().signal });
22981
22928
  stage.on("pointerdown", (e) => {
22982
22929
  this.setTapStart(e);
22983
22930
  if (this.ignorePointerEvents) return;
@@ -23300,10 +23247,10 @@ var WeaveImageToolAction = class extends WeaveAction {
23300
23247
  return this.state;
23301
23248
  }
23302
23249
  loadImageDataURL(imageDataURL) {
23303
- return new Promise((resolve, reject$1) => {
23250
+ return new Promise((resolve, reject) => {
23304
23251
  const imageEle = Konva.Util.createImageElement();
23305
23252
  imageEle.onerror = (error) => {
23306
- reject$1(error);
23253
+ reject(error);
23307
23254
  };
23308
23255
  imageEle.onload = async () => {
23309
23256
  resolve(imageEle);
@@ -23312,13 +23259,13 @@ var WeaveImageToolAction = class extends WeaveAction {
23312
23259
  });
23313
23260
  }
23314
23261
  getDataURL(blob) {
23315
- return new Promise((resolve, reject$1) => {
23262
+ return new Promise((resolve, reject) => {
23316
23263
  const reader = new FileReader();
23317
23264
  reader.onloadend = () => {
23318
23265
  resolve(reader.result);
23319
23266
  };
23320
23267
  reader.onerror = () => {
23321
- reject$1(new Error("Failed to generate dataURL from file"));
23268
+ reject(new Error("Failed to generate dataURL from file"));
23322
23269
  };
23323
23270
  reader.readAsDataURL(blob);
23324
23271
  });
@@ -23437,7 +23384,7 @@ var WeaveImagesToolAction = class extends WeaveAction {
23437
23384
  const stage = this.instance.getStage();
23438
23385
  stage.container().addEventListener("keydown", (e) => {
23439
23386
  if (e.key === "Escape" && this.instance.getActiveAction() === WEAVE_IMAGES_TOOL_ACTION_NAME) this.cancelAction();
23440
- }, { signal: this.instance.getEventsController()?.signal });
23387
+ }, { signal: this.instance.getEventsController().signal });
23441
23388
  stage.on("pointerdown", (e) => {
23442
23389
  this.setTapStart(e);
23443
23390
  this.pointers.set(e.evt.pointerId, {
@@ -23855,7 +23802,7 @@ var WeaveStarToolAction = class extends WeaveAction {
23855
23802
  this.cancelAction();
23856
23803
  return;
23857
23804
  }
23858
- }, { signal: this.instance.getEventsController()?.signal });
23805
+ }, { signal: this.instance.getEventsController().signal });
23859
23806
  stage.on("pointerdown", (e) => {
23860
23807
  this.setTapStart(e);
23861
23808
  this.pointers.set(e.evt.pointerId, {
@@ -24078,7 +24025,7 @@ var WeaveArrowToolAction = class extends WeaveAction {
24078
24025
  return;
24079
24026
  }
24080
24027
  if (e.code === "Escape" && this.instance.getActiveAction() === WEAVE_ARROW_TOOL_ACTION_NAME) this.cancelAction();
24081
- }, { signal: this.instance.getEventsController()?.signal });
24028
+ }, { signal: this.instance.getEventsController().signal });
24082
24029
  stage.on("pointerdown", (e) => {
24083
24030
  this.setTapStart(e);
24084
24031
  this.pointers.set(e.evt.pointerId, {
@@ -24369,10 +24316,10 @@ var WeaveStrokeToolAction = class extends WeaveAction {
24369
24316
  return;
24370
24317
  }
24371
24318
  if (e.key === "Shift" && this.getNames().includes(this.instance.getActiveAction() ?? "")) this.shiftPressed = true;
24372
- }, { signal: this.instance.getEventsController()?.signal });
24319
+ }, { signal: this.instance.getEventsController().signal });
24373
24320
  window.addEventListener("keyup", (e) => {
24374
24321
  if (e.key === "Shift" && this.getNames().includes(this.instance.getActiveAction() ?? "")) this.shiftPressed = false;
24375
- }, { signal: this.instance.getEventsController()?.signal });
24322
+ }, { signal: this.instance.getEventsController().signal });
24376
24323
  stage.on("pointerdown", (e) => {
24377
24324
  this.setTapStart(e);
24378
24325
  this.pointers.set(e.evt.pointerId, {
@@ -24602,7 +24549,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
24602
24549
  this.cancelAction();
24603
24550
  return;
24604
24551
  }
24605
- }, { signal: this.instance.getEventsController()?.signal });
24552
+ }, { signal: this.instance.getEventsController().signal });
24606
24553
  stage.on("pointerdown", (e) => {
24607
24554
  this.setTapStart(e);
24608
24555
  this.pointers.set(e.evt.pointerId, {
@@ -24806,7 +24753,7 @@ var WeaveFrameToolAction = class extends WeaveAction {
24806
24753
  this.cancelAction();
24807
24754
  return;
24808
24755
  }
24809
- }, { signal: this.instance.getEventsController()?.signal });
24756
+ }, { signal: this.instance.getEventsController().signal });
24810
24757
  stage.on("pointermove", () => {
24811
24758
  if (this.state === FRAME_TOOL_STATE.IDLE) return;
24812
24759
  this.setCursor();
@@ -25347,7 +25294,7 @@ var WeaveCommentToolAction = class extends WeaveAction {
25347
25294
  return;
25348
25295
  }
25349
25296
  if (e.code === "Escape" && this.state === WEAVE_COMMENT_TOOL_STATE.CREATING_COMMENT) this.setState(WEAVE_COMMENT_TOOL_STATE.ADDING);
25350
- }, { signal: this.instance.getEventsController()?.signal });
25297
+ }, { signal: this.instance.getEventsController().signal });
25351
25298
  stage.on("pointermove", (e) => {
25352
25299
  if (this.state === WEAVE_COMMENT_TOOL_STATE.IDLE) return;
25353
25300
  if (commentNodeHandler?.isCommentViewing()) {
@@ -25549,7 +25496,7 @@ var WeaveVideoToolAction = class extends WeaveAction {
25549
25496
  this.cancelAction();
25550
25497
  return;
25551
25498
  }
25552
- }, { signal: this.instance.getEventsController()?.signal });
25499
+ }, { signal: this.instance.getEventsController().signal });
25553
25500
  stage.on("pointerdown", (e) => {
25554
25501
  this.setTapStart(e);
25555
25502
  this.pointers.set(e.evt.pointerId, {
@@ -25712,7 +25659,7 @@ var WeaveMeasureToolAction = class extends WeaveAction {
25712
25659
  const stage = this.instance.getStage();
25713
25660
  window.addEventListener("keydown", (e) => {
25714
25661
  if (e.code === "Escape" && this.instance.getActiveAction() === MEASURE_TOOL_ACTION_NAME) this.cancelAction();
25715
- }, { signal: this.instance.getEventsController()?.signal });
25662
+ }, { signal: this.instance.getEventsController().signal });
25716
25663
  stage.on("pointermove", () => {
25717
25664
  if (this.state === MEASURE_TOOL_STATE.IDLE) return;
25718
25665
  if (this.state === MEASURE_TOOL_STATE.SET_TO) {
@@ -26023,7 +25970,7 @@ var WeaveConnectorToolAction = class extends WeaveAction {
26023
25970
  return;
26024
25971
  }
26025
25972
  if (e.code === "Escape" && this.instance.getActiveAction() === CONNECTOR_TOOL_ACTION_NAME) this.cancelAction();
26026
- }, { signal: this.instance.getEventsController()?.signal });
25973
+ }, { signal: this.instance.getEventsController().signal });
26027
25974
  let nodeHovered = void 0;
26028
25975
  stage.on("pointermove", () => {
26029
25976
  if (!(this.state === CONNECTOR_TOOL_STATE.SELECTING_INITIAL || this.state === CONNECTOR_TOOL_STATE.SELECTING_FINAL)) return;
@@ -26855,7 +26802,7 @@ var WeaveGuideToolAction = class extends WeaveAction {
26855
26802
  window.addEventListener("keyup", (e) => {
26856
26803
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
26857
26804
  if (isOptionAltPressed) this.guideDistanceToTargetInfo.cleanup();
26858
- }, { signal: this.instance.getEventsController()?.signal });
26805
+ }, { signal: this.instance.getEventsController().signal });
26859
26806
  window.addEventListener("keydown", (e) => {
26860
26807
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
26861
26808
  if (isOptionAltPressed && this.instance.getActiveAction() === GUIDE_TOOL_ACTION_NAME && this.state === GUIDE_TOOL_STATE.ADDING) this.moveGuide(true);
@@ -26875,7 +26822,7 @@ var WeaveGuideToolAction = class extends WeaveAction {
26875
26822
  this.cancelAction();
26876
26823
  }
26877
26824
  }
26878
- }, { signal: this.instance.getEventsController()?.signal });
26825
+ }, { signal: this.instance.getEventsController().signal });
26879
26826
  stage.on("pointermove", (e) => {
26880
26827
  if (this.state === GUIDE_TOOL_STATE.IDLE) return;
26881
26828
  this.setCursor();
@@ -27147,10 +27094,10 @@ var WeaveStageGridPlugin = class extends WeavePlugin {
27147
27094
  const stage = this.instance.getStage();
27148
27095
  window.addEventListener("keydown", (e) => {
27149
27096
  if (e.code === "Space") this.isSpaceKeyPressed = true;
27150
- }, { signal: this.instance.getEventsController()?.signal });
27097
+ }, { signal: this.instance.getEventsController().signal });
27151
27098
  window.addEventListener("keyup", (e) => {
27152
27099
  if (e.code === "Space") this.isSpaceKeyPressed = false;
27153
- }, { signal: this.instance.getEventsController()?.signal });
27100
+ }, { signal: this.instance.getEventsController().signal });
27154
27101
  this.instance.addEventListener("onStageMove", () => {
27155
27102
  this.onRender();
27156
27103
  });
@@ -27467,7 +27414,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27467
27414
  this.isSpaceKeyPressed = true;
27468
27415
  this.setCursor();
27469
27416
  }
27470
- }, { signal: this.instance.getEventsController()?.signal });
27417
+ }, { signal: this.instance.getEventsController().signal });
27471
27418
  window.addEventListener("keyup", (e) => {
27472
27419
  if (e.code === "Space") {
27473
27420
  this.getContextMenuPlugin()?.enable();
@@ -27475,7 +27422,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27475
27422
  this.isSpaceKeyPressed = false;
27476
27423
  this.disableMove();
27477
27424
  }
27478
- }, { signal: this.instance.getEventsController()?.signal });
27425
+ }, { signal: this.instance.getEventsController().signal });
27479
27426
  let lastPos = null;
27480
27427
  stage.on("pointerdown", (e) => {
27481
27428
  this.pointers.set(e.evt.pointerId, {
@@ -27551,7 +27498,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27551
27498
  const handleWheelThrottled = (0, import_throttle.default)(handleWheel, WEAVE_STAGE_PANNING_THROTTLE_MS);
27552
27499
  window.addEventListener("wheel", handleWheelThrottled, {
27553
27500
  passive: true,
27554
- signal: this.instance.getEventsController()?.signal
27501
+ signal: this.instance.getEventsController().signal
27555
27502
  });
27556
27503
  stage.on("dragstart", (e) => {
27557
27504
  const duration = 1e3 / 60;
@@ -27603,7 +27550,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27603
27550
  e.preventDefault();
27604
27551
  }, {
27605
27552
  passive: false,
27606
- signal: this.instance.getEventsController()?.signal
27553
+ signal: this.instance.getEventsController().signal
27607
27554
  });
27608
27555
  }
27609
27556
  isPanning() {
@@ -27889,7 +27836,7 @@ var WeaveStageResizePlugin = class extends WeavePlugin {
27889
27836
  }, DEFAULT_THROTTLE_MS);
27890
27837
  window.addEventListener("resize", () => {
27891
27838
  throttledResize();
27892
- }, { signal: this.instance.getEventsController()?.signal });
27839
+ }, { signal: this.instance.getEventsController().signal });
27893
27840
  const resizeObserver = new ResizeObserver(() => {
27894
27841
  throttledResize();
27895
27842
  });
@@ -28613,6 +28560,215 @@ var WeaveUsersPresencePlugin = class extends WeavePlugin {
28613
28560
  }
28614
28561
  };
28615
28562
 
28563
+ //#endregion
28564
+ //#region src/plugins/context-menu/context-menu.ts
28565
+ var WeaveContextMenuPlugin = class extends WeavePlugin {
28566
+ getLayerName = void 0;
28567
+ initLayer = void 0;
28568
+ constructor(params) {
28569
+ super();
28570
+ const { config } = params ?? {};
28571
+ this.config = {
28572
+ xOffset: WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT,
28573
+ yOffset: WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT,
28574
+ ...config
28575
+ };
28576
+ this.initialize();
28577
+ }
28578
+ initialize() {
28579
+ this.timer = null;
28580
+ this.tapHold = false;
28581
+ this.contextMenuVisible = false;
28582
+ this.tapStart = {
28583
+ x: 0,
28584
+ y: 0,
28585
+ time: 0
28586
+ };
28587
+ this.tapHoldTimeout = WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT;
28588
+ this.pointers = {};
28589
+ }
28590
+ getName() {
28591
+ return WEAVE_CONTEXT_MENU_PLUGIN_KEY;
28592
+ }
28593
+ onInit() {
28594
+ this.initEvents();
28595
+ }
28596
+ isPressed(e) {
28597
+ return e.evt.buttons > 0;
28598
+ }
28599
+ setTapStart(e) {
28600
+ this.tapStart = {
28601
+ x: e.evt.clientX,
28602
+ y: e.evt.clientY,
28603
+ time: performance.now()
28604
+ };
28605
+ }
28606
+ triggerContextMenu(eventTarget, target) {
28607
+ const stage = this.instance.getStage();
28608
+ const selectionPlugin = this.getSelectionPlugin();
28609
+ let nodes = [];
28610
+ if (target && target !== stage) {
28611
+ const nodeHandler = this.instance.getNodeHandler(target.getAttrs().nodeType);
28612
+ nodes = [{
28613
+ instance: target,
28614
+ node: nodeHandler?.serialize(target)
28615
+ }];
28616
+ }
28617
+ const eventTargetParent = eventTarget.getParent();
28618
+ if (eventTargetParent instanceof Konva.Transformer) nodes = eventTargetParent.nodes().map((node) => {
28619
+ const nodeHandler = this.instance.getNodeHandler(node.getAttrs().nodeType);
28620
+ return {
28621
+ instance: node,
28622
+ node: nodeHandler?.serialize(node)
28623
+ };
28624
+ });
28625
+ if (this.contextMenuVisible) this.closeContextMenu();
28626
+ let allNodesMutexUnlocked = true;
28627
+ let allNodesUnlocked = true;
28628
+ const actUser = this.instance.getStore().getUser();
28629
+ for (const node of nodes) {
28630
+ const locked = node.instance.getAttrs().locked;
28631
+ const mutexInfo = this.instance.getNodeMutexLock(node.node?.key ?? "");
28632
+ if (locked) {
28633
+ allNodesUnlocked = false;
28634
+ break;
28635
+ }
28636
+ if (mutexInfo && mutexInfo.user.id !== actUser.id) {
28637
+ allNodesMutexUnlocked = false;
28638
+ break;
28639
+ }
28640
+ }
28641
+ if (!allNodesMutexUnlocked || !allNodesUnlocked) return;
28642
+ if (selectionPlugin && !(eventTarget.getParent() instanceof Konva.Transformer && selectionPlugin.getSelectedNodes().length > 0)) {
28643
+ selectionPlugin.setSelectedNodes([...nodes.map((node) => node.instance)]);
28644
+ selectionPlugin.getHoverTransformer().nodes([]);
28645
+ }
28646
+ const containerRect = stage.container().getBoundingClientRect();
28647
+ const pointerPos = stage.getPointerPosition();
28648
+ const relativeClickPoint = stage.getRelativePointerPosition();
28649
+ if (containerRect && pointerPos && relativeClickPoint && allNodesUnlocked) {
28650
+ const contextMenuPoint = {
28651
+ x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
28652
+ y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
28653
+ };
28654
+ const stageClickPoint = this.getStageClickPoint(pointerPos);
28655
+ this.contextMenuVisible = true;
28656
+ this.instance.emitEvent("onNodeContextMenu", {
28657
+ selection: nodes,
28658
+ contextMenuPoint,
28659
+ clickPoint: pointerPos,
28660
+ stageClickPoint,
28661
+ visible: true
28662
+ });
28663
+ }
28664
+ }
28665
+ closeContextMenu() {
28666
+ this.contextMenuVisible = false;
28667
+ this.instance.emitEvent("onNodeContextMenu", {
28668
+ selection: [],
28669
+ contextMenuPoint: {
28670
+ x: 0,
28671
+ y: 0
28672
+ },
28673
+ clickPoint: {
28674
+ x: 0,
28675
+ y: 0
28676
+ },
28677
+ stageClickPoint: {
28678
+ x: 0,
28679
+ y: 0
28680
+ },
28681
+ visible: false
28682
+ });
28683
+ }
28684
+ getSelectionPlugin() {
28685
+ const selectionPlugin = this.instance.getPlugin(WEAVE_NODES_SELECTION_KEY);
28686
+ return selectionPlugin;
28687
+ }
28688
+ cancelLongPressTimer() {
28689
+ if (this.timer) {
28690
+ clearTimeout(this.timer);
28691
+ this.timer = null;
28692
+ }
28693
+ }
28694
+ initEvents() {
28695
+ const stage = this.instance.getStage();
28696
+ stage.on("pointerdown", (e) => {
28697
+ this.setTapStart(e);
28698
+ this.pointers[e.evt.pointerId] = e.evt;
28699
+ if (e.evt.buttons === 0) return;
28700
+ if (e.evt.pointerType === "mouse") return;
28701
+ if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
28702
+ if (this.timer) return;
28703
+ this.timer = setTimeout(() => {
28704
+ this.tapHold = true;
28705
+ const actualActions = this.instance.getActiveAction();
28706
+ if (actualActions !== SELECTION_TOOL_ACTION_NAME) return;
28707
+ delete this.pointers[e.evt.pointerId];
28708
+ const selectedGroup = getTargetedNode(this.instance);
28709
+ this.triggerContextMenu(e.target, selectedGroup);
28710
+ }, this.tapHoldTimeout);
28711
+ });
28712
+ stage.on("pointerup", (e) => {
28713
+ delete this.pointers[e.evt.pointerId];
28714
+ if (e.evt.pointerType === "mouse") return;
28715
+ if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length + 1 > 1) return;
28716
+ if (this.timer) {
28717
+ clearTimeout(this.timer);
28718
+ this.timer = null;
28719
+ this.tapHold = false;
28720
+ }
28721
+ });
28722
+ stage.on("contextmenu", (e) => {
28723
+ e.evt.preventDefault();
28724
+ if (!this.enabled) return;
28725
+ const selectedGroup = getTargetedNode(this.instance);
28726
+ this.triggerContextMenu(e.target, selectedGroup);
28727
+ });
28728
+ this.instance.addEventListener("onStageSelection", () => {
28729
+ if (this.tapHold) return;
28730
+ const containerRect = stage.container().getBoundingClientRect();
28731
+ const pointerPos = stage.getPointerPosition();
28732
+ if (containerRect && pointerPos) {
28733
+ const contextMenuPoint = {
28734
+ x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
28735
+ y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
28736
+ };
28737
+ const stageClickPoint = this.getStageClickPoint(pointerPos);
28738
+ this.instance.emitEvent("onNodeContextMenu", {
28739
+ selection: [],
28740
+ contextMenuPoint,
28741
+ clickPoint: pointerPos,
28742
+ stageClickPoint,
28743
+ visible: false
28744
+ });
28745
+ }
28746
+ });
28747
+ }
28748
+ getStageClickPoint(pointerPos) {
28749
+ const stage = this.instance.getStage();
28750
+ const scale = stage.scale();
28751
+ const position = stage.position();
28752
+ const stageClickPoint = {
28753
+ x: (pointerPos.x - position.x) / scale.x,
28754
+ y: (pointerPos.y - position.y) / scale.y
28755
+ };
28756
+ return stageClickPoint;
28757
+ }
28758
+ isContextMenuVisible() {
28759
+ return this.contextMenuVisible;
28760
+ }
28761
+ isTapHold() {
28762
+ return this.tapHold;
28763
+ }
28764
+ enable() {
28765
+ this.enabled = true;
28766
+ }
28767
+ disable() {
28768
+ this.enabled = false;
28769
+ }
28770
+ };
28771
+
28616
28772
  //#endregion
28617
28773
  //#region src/plugins/stage-drop-area/constants.ts
28618
28774
  const WEAVE_STAGE_DROP_AREA_KEY = "stageDropArea";
@@ -28640,18 +28796,18 @@ var WeaveStageDropAreaPlugin = class extends WeavePlugin {
28640
28796
  stage.container().addEventListener("dragover", (e) => {
28641
28797
  e.preventDefault();
28642
28798
  e.stopPropagation();
28643
- }, { signal: this.instance.getEventsController()?.signal });
28799
+ }, { signal: this.instance.getEventsController().signal });
28644
28800
  stage.container().addEventListener("drop", (e) => {
28645
28801
  e.preventDefault();
28646
28802
  e.stopPropagation();
28647
28803
  this.instance.emitEvent("onStageDrop", e);
28648
- }, { signal: this.instance.getEventsController()?.signal });
28804
+ }, { signal: this.instance.getEventsController().signal });
28649
28805
  window.addEventListener("dragover", (e) => e.preventDefault(), {
28650
- signal: this.instance.getEventsController()?.signal,
28806
+ signal: this.instance.getEventsController().signal,
28651
28807
  passive: false
28652
28808
  });
28653
28809
  window.addEventListener("drop", (e) => e.preventDefault(), {
28654
- signal: this.instance.getEventsController()?.signal,
28810
+ signal: this.instance.getEventsController().signal,
28655
28811
  passive: false
28656
28812
  });
28657
28813
  }
@@ -28819,7 +28975,7 @@ var WeaveStageKeyboardMovePlugin = class extends WeavePlugin {
28819
28975
  if (e.code === "ArrowLeft") this.handleNodesMovement(WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION.LEFT, { isShiftPressed });
28820
28976
  if (e.code === "ArrowRight") this.handleNodesMovement(WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION.RIGHT, { isShiftPressed });
28821
28977
  if (e.code === "ArrowDown") this.handleNodesMovement(WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION.DOWN, { isShiftPressed });
28822
- }, { signal: this.instance.getEventsController()?.signal });
28978
+ }, { signal: this.instance.getEventsController().signal });
28823
28979
  }
28824
28980
  enable() {
28825
28981
  this.enabled = true;
@@ -28887,18 +29043,18 @@ var WeaveNodesSnappingCustomGuides = class {
28887
29043
  const isOptionAltPressed = e.altKey;
28888
29044
  this.cleanupDistanceGuide();
28889
29045
  if (isOptionAltPressed && this.isDragging) this.handleDistanceGuide(isOptionAltPressed);
28890
- }, { signal: this.instance.getEventsController()?.signal });
29046
+ }, { signal: this.instance.getEventsController().signal });
28891
29047
  window.addEventListener("keyup", (e) => {
28892
29048
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
28893
29049
  if (isOptionAltPressed) this.cleanupDistanceGuide();
28894
- }, { signal: this.instance.getEventsController()?.signal });
29050
+ }, { signal: this.instance.getEventsController().signal });
28895
29051
  window.addEventListener("keydown", (e) => {
28896
29052
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
28897
29053
  if (isOptionAltPressed && this.isDragging) {
28898
29054
  this.cleanupDistanceGuide();
28899
29055
  this.handleDistanceGuide(isOptionAltPressed);
28900
29056
  }
28901
- }, { signal: this.instance.getEventsController()?.signal });
29057
+ }, { signal: this.instance.getEventsController().signal });
28902
29058
  }
28903
29059
  getAllCustomGuides() {
28904
29060
  return this.customGuides;
@@ -28929,6 +29085,7 @@ var WeaveNodesSnappingCustomGuides = class {
28929
29085
  }
28930
29086
  saveCustomGuide(guide) {
28931
29087
  const containerId = guide.containerId;
29088
+ if (!this.customGuides) this.customGuides = {};
28932
29089
  if (!this.customGuides[containerId]) this.customGuides[containerId] = [];
28933
29090
  this.customGuides[containerId].push(guide);
28934
29091
  this.instance.emitEvent("snappingManager:onCustomGuidesChange", { guides: this.customGuides });
@@ -29096,7 +29253,7 @@ var WeaveNodesSnappingCustomGuides = class {
29096
29253
  this.setupEvents = false;
29097
29254
  }
29098
29255
  if (!this.noGuidesVisible() && !this.setupEvents) {
29099
- stage.container().addEventListener("keydown", this.handleArrowKeys, { signal: this.instance.getEventsController()?.signal });
29256
+ stage.container().addEventListener("keydown", this.handleArrowKeys, { signal: this.instance.getEventsController().signal });
29100
29257
  stage.on("pointerclick", this.handlePointerClick);
29101
29258
  this.instance.addEventListener("onNodesChange", this.handleOnNodesSelectedChange);
29102
29259
  this.instance.addEventListener("onStageMove", this.handleStagePanChange);