@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/types.js CHANGED
@@ -1157,8 +1157,8 @@ var require_isArray = __commonJS({ "../../node_modules/lodash/isArray.js"(export
1157
1157
  * _.isArray(_.noop);
1158
1158
  * // => false
1159
1159
  */
1160
- var isArray$14 = Array.isArray;
1161
- module.exports = isArray$14;
1160
+ var isArray$13 = Array.isArray;
1161
+ module.exports = isArray$13;
1162
1162
  } });
1163
1163
 
1164
1164
  //#endregion
@@ -1383,7 +1383,7 @@ var require_isTypedArray = __commonJS({ "../../node_modules/lodash/isTypedArray.
1383
1383
  //#endregion
1384
1384
  //#region ../../node_modules/lodash/isEmpty.js
1385
1385
  var require_isEmpty = __commonJS({ "../../node_modules/lodash/isEmpty.js"(exports, module) {
1386
- var baseKeys$1 = require__baseKeys(), getTag$1 = require__getTag(), isArguments$3 = require_isArguments(), isArray$13 = require_isArray(), isArrayLike$6 = require_isArrayLike(), isBuffer$3 = require_isBuffer(), isPrototype$2 = require__isPrototype(), isTypedArray$3 = require_isTypedArray();
1386
+ 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();
1387
1387
  /** `Object#toString` result references. */
1388
1388
  var mapTag$1 = "[object Map]", setTag$1 = "[object Set]";
1389
1389
  /** Used for built-in method references. */
@@ -1425,7 +1425,7 @@ var require_isEmpty = __commonJS({ "../../node_modules/lodash/isEmpty.js"(export
1425
1425
  */
1426
1426
  function isEmpty(value) {
1427
1427
  if (value == null) return true;
1428
- if (isArrayLike$6(value) && (isArray$13(value) || typeof value == "string" || typeof value.splice == "function" || isBuffer$3(value) || isTypedArray$3(value) || isArguments$3(value))) return !value.length;
1428
+ 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;
1429
1429
  var tag = getTag$1(value);
1430
1430
  if (tag == mapTag$1 || tag == setTag$1) return !value.size;
1431
1431
  if (isPrototype$2(value)) return !baseKeys$1(value).length;
@@ -1752,13 +1752,6 @@ const WEAVE_NODES_SELECTION_DEFAULT_CONFIG = {
1752
1752
  style: { dragOpacity: .75 }
1753
1753
  };
1754
1754
 
1755
- //#endregion
1756
- //#region src/plugins/context-menu/constants.ts
1757
- const WEAVE_CONTEXT_MENU_PLUGIN_KEY = "contextMenu";
1758
- const WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT = 4;
1759
- const WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT = 4;
1760
- const WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT = 500;
1761
-
1762
1755
  //#endregion
1763
1756
  //#region ../../node_modules/lodash/_listCacheClear.js
1764
1757
  var require__listCacheClear = __commonJS({ "../../node_modules/lodash/_listCacheClear.js"(exports, module) {
@@ -2865,7 +2858,7 @@ var require__isIndex = __commonJS({ "../../node_modules/lodash/_isIndex.js"(expo
2865
2858
  //#endregion
2866
2859
  //#region ../../node_modules/lodash/_arrayLikeKeys.js
2867
2860
  var require__arrayLikeKeys = __commonJS({ "../../node_modules/lodash/_arrayLikeKeys.js"(exports, module) {
2868
- var baseTimes = require__baseTimes(), isArguments$2 = require_isArguments(), isArray$12 = require_isArray(), isBuffer$2 = require_isBuffer(), isIndex$2 = require__isIndex(), isTypedArray$2 = require_isTypedArray();
2861
+ var baseTimes = require__baseTimes(), isArguments$2 = require_isArguments(), isArray$11 = require_isArray(), isBuffer$2 = require_isBuffer(), isIndex$2 = require__isIndex(), isTypedArray$2 = require_isTypedArray();
2869
2862
  /** Used for built-in method references. */
2870
2863
  var objectProto$4 = Object.prototype;
2871
2864
  /** Used to check objects for own properties. */
@@ -2879,7 +2872,7 @@ var require__arrayLikeKeys = __commonJS({ "../../node_modules/lodash/_arrayLikeK
2879
2872
  * @returns {Array} Returns the array of property names.
2880
2873
  */
2881
2874
  function arrayLikeKeys$2(value, inherited) {
2882
- var isArr = isArray$12(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;
2875
+ 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;
2883
2876
  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);
2884
2877
  return result;
2885
2878
  }
@@ -3000,7 +2993,7 @@ var require_toPlainObject = __commonJS({ "../../node_modules/lodash/toPlainObjec
3000
2993
  //#endregion
3001
2994
  //#region ../../node_modules/lodash/_baseMergeDeep.js
3002
2995
  var require__baseMergeDeep = __commonJS({ "../../node_modules/lodash/_baseMergeDeep.js"(exports, module) {
3003
- var assignMergeValue$1 = require__assignMergeValue(), cloneBuffer = require__cloneBuffer(), cloneTypedArray = require__cloneTypedArray(), copyArray = require__copyArray(), initCloneObject = require__initCloneObject(), isArguments$1 = require_isArguments(), isArray$11 = require_isArray(), isArrayLikeObject = require_isArrayLikeObject(), isBuffer$1 = require_isBuffer(), isFunction = require_isFunction(), isObject$7 = require_isObject(), isPlainObject = require_isPlainObject(), isTypedArray$1 = require_isTypedArray(), safeGet$1 = require__safeGet(), toPlainObject = require_toPlainObject();
2996
+ 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$7 = require_isObject(), isPlainObject = require_isPlainObject(), isTypedArray$1 = require_isTypedArray(), safeGet$1 = require__safeGet(), toPlainObject = require_toPlainObject();
3004
2997
  /**
3005
2998
  * A specialized version of `baseMerge` for arrays and objects which performs
3006
2999
  * deep merges and tracks traversed objects enabling objects with circular
@@ -3025,9 +3018,9 @@ var require__baseMergeDeep = __commonJS({ "../../node_modules/lodash/_baseMergeD
3025
3018
  var newValue = customizer ? customizer(objValue, srcValue, key + "", object, source, stack) : void 0;
3026
3019
  var isCommon = newValue === void 0;
3027
3020
  if (isCommon) {
3028
- var isArr = isArray$11(srcValue), isBuff = !isArr && isBuffer$1(srcValue), isTyped = !isArr && !isBuff && isTypedArray$1(srcValue);
3021
+ var isArr = isArray$10(srcValue), isBuff = !isArr && isBuffer$1(srcValue), isTyped = !isArr && !isBuff && isTypedArray$1(srcValue);
3029
3022
  newValue = srcValue;
3030
- if (isArr || isBuff || isTyped) if (isArray$11(objValue)) newValue = objValue;
3023
+ if (isArr || isBuff || isTyped) if (isArray$10(objValue)) newValue = objValue;
3031
3024
  else if (isArrayLikeObject(objValue)) newValue = copyArray(objValue);
3032
3025
  else if (isBuff) {
3033
3026
  isCommon = false;
@@ -3703,223 +3696,6 @@ function isNumber(value) {
3703
3696
  return typeof value === "number" && !Number.isNaN(value);
3704
3697
  }
3705
3698
 
3706
- //#endregion
3707
- //#region src/actions/selection-tool/constants.ts
3708
- const SELECTION_TOOL_ACTION_NAME = "selectionTool";
3709
- const SELECTION_TOOL_STATE = {
3710
- ["IDLE"]: "idle",
3711
- ["SELECTING"]: "selection"
3712
- };
3713
-
3714
- //#endregion
3715
- //#region src/plugins/context-menu/context-menu.ts
3716
- var WeaveContextMenuPlugin = class extends WeavePlugin {
3717
- getLayerName = void 0;
3718
- initLayer = void 0;
3719
- constructor(params) {
3720
- super();
3721
- const { config } = params ?? {};
3722
- this.config = {
3723
- xOffset: WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT,
3724
- yOffset: WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT,
3725
- ...config
3726
- };
3727
- this.initialize();
3728
- }
3729
- initialize() {
3730
- this.timer = null;
3731
- this.tapHold = false;
3732
- this.contextMenuVisible = false;
3733
- this.tapStart = {
3734
- x: 0,
3735
- y: 0,
3736
- time: 0
3737
- };
3738
- this.tapHoldTimeout = WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT;
3739
- this.pointers = {};
3740
- }
3741
- getName() {
3742
- return WEAVE_CONTEXT_MENU_PLUGIN_KEY;
3743
- }
3744
- onInit() {
3745
- this.initEvents();
3746
- }
3747
- isPressed(e) {
3748
- return e.evt.buttons > 0;
3749
- }
3750
- setTapStart(e) {
3751
- this.tapStart = {
3752
- x: e.evt.clientX,
3753
- y: e.evt.clientY,
3754
- time: performance.now()
3755
- };
3756
- }
3757
- triggerContextMenu(eventTarget, target) {
3758
- const stage = this.instance.getStage();
3759
- const selectionPlugin = this.getSelectionPlugin();
3760
- let nodes = [];
3761
- if (target && target !== stage) {
3762
- const nodeHandler = this.instance.getNodeHandler(target.getAttrs().nodeType);
3763
- nodes = [{
3764
- instance: target,
3765
- node: nodeHandler?.serialize(target)
3766
- }];
3767
- }
3768
- const eventTargetParent = eventTarget.getParent();
3769
- if (eventTargetParent instanceof Konva.Transformer) nodes = eventTargetParent.nodes().map((node) => {
3770
- const nodeHandler = this.instance.getNodeHandler(node.getAttrs().nodeType);
3771
- return {
3772
- instance: node,
3773
- node: nodeHandler?.serialize(node)
3774
- };
3775
- });
3776
- if (this.contextMenuVisible) this.closeContextMenu();
3777
- let allNodesMutexUnlocked = true;
3778
- let allNodesUnlocked = true;
3779
- const actUser = this.instance.getStore().getUser();
3780
- for (const node of nodes) {
3781
- const locked = node.instance.getAttrs().locked;
3782
- const mutexInfo = this.instance.getNodeMutexLock(node.node?.key ?? "");
3783
- if (locked) {
3784
- allNodesUnlocked = false;
3785
- break;
3786
- }
3787
- if (mutexInfo && mutexInfo.user.id !== actUser.id) {
3788
- allNodesMutexUnlocked = false;
3789
- break;
3790
- }
3791
- }
3792
- if (!allNodesMutexUnlocked || !allNodesUnlocked) return;
3793
- if (selectionPlugin && !(eventTarget.getParent() instanceof Konva.Transformer && selectionPlugin.getSelectedNodes().length > 0)) {
3794
- selectionPlugin.setSelectedNodes([...nodes.map((node) => node.instance)]);
3795
- selectionPlugin.getHoverTransformer().nodes([]);
3796
- }
3797
- const containerRect = stage.container().getBoundingClientRect();
3798
- const pointerPos = stage.getPointerPosition();
3799
- const relativeClickPoint = stage.getRelativePointerPosition();
3800
- if (containerRect && pointerPos && relativeClickPoint && allNodesUnlocked) {
3801
- const contextMenuPoint = {
3802
- x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
3803
- y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
3804
- };
3805
- const stageClickPoint = this.getStageClickPoint(pointerPos);
3806
- this.contextMenuVisible = true;
3807
- this.instance.emitEvent("onNodeContextMenu", {
3808
- selection: nodes,
3809
- contextMenuPoint,
3810
- clickPoint: pointerPos,
3811
- stageClickPoint,
3812
- visible: true
3813
- });
3814
- }
3815
- }
3816
- closeContextMenu() {
3817
- this.contextMenuVisible = false;
3818
- this.instance.emitEvent("onNodeContextMenu", {
3819
- selection: [],
3820
- contextMenuPoint: {
3821
- x: 0,
3822
- y: 0
3823
- },
3824
- clickPoint: {
3825
- x: 0,
3826
- y: 0
3827
- },
3828
- stageClickPoint: {
3829
- x: 0,
3830
- y: 0
3831
- },
3832
- visible: false
3833
- });
3834
- }
3835
- getSelectionPlugin() {
3836
- const selectionPlugin = this.instance.getPlugin(WEAVE_NODES_SELECTION_KEY);
3837
- return selectionPlugin;
3838
- }
3839
- cancelLongPressTimer() {
3840
- if (this.timer) {
3841
- clearTimeout(this.timer);
3842
- this.timer = null;
3843
- }
3844
- }
3845
- initEvents() {
3846
- const stage = this.instance.getStage();
3847
- stage.on("pointerdown", (e) => {
3848
- this.setTapStart(e);
3849
- this.pointers[e.evt.pointerId] = e.evt;
3850
- if (e.evt.buttons === 0) return;
3851
- if (e.evt.pointerType === "mouse") return;
3852
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
3853
- if (this.timer) return;
3854
- this.timer = setTimeout(() => {
3855
- this.tapHold = true;
3856
- const actualActions = this.instance.getActiveAction();
3857
- if (actualActions !== SELECTION_TOOL_ACTION_NAME) return;
3858
- delete this.pointers[e.evt.pointerId];
3859
- const selectedGroup = getTargetedNode(this.instance);
3860
- this.triggerContextMenu(e.target, selectedGroup);
3861
- }, this.tapHoldTimeout);
3862
- });
3863
- stage.on("pointerup", (e) => {
3864
- delete this.pointers[e.evt.pointerId];
3865
- if (e.evt.pointerType === "mouse") return;
3866
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length + 1 > 1) return;
3867
- if (this.timer) {
3868
- clearTimeout(this.timer);
3869
- this.timer = null;
3870
- this.tapHold = false;
3871
- }
3872
- });
3873
- stage.on("contextmenu", (e) => {
3874
- e.evt.preventDefault();
3875
- if (!this.enabled) return;
3876
- const selectedGroup = getTargetedNode(this.instance);
3877
- this.triggerContextMenu(e.target, selectedGroup);
3878
- });
3879
- this.instance.addEventListener("onStageSelection", () => {
3880
- if (this.tapHold) return;
3881
- const containerRect = stage.container().getBoundingClientRect();
3882
- const pointerPos = stage.getPointerPosition();
3883
- if (containerRect && pointerPos) {
3884
- const contextMenuPoint = {
3885
- x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
3886
- y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
3887
- };
3888
- const stageClickPoint = this.getStageClickPoint(pointerPos);
3889
- this.instance.emitEvent("onNodeContextMenu", {
3890
- selection: [],
3891
- contextMenuPoint,
3892
- clickPoint: pointerPos,
3893
- stageClickPoint,
3894
- visible: false
3895
- });
3896
- }
3897
- });
3898
- }
3899
- getStageClickPoint(pointerPos) {
3900
- const stage = this.instance.getStage();
3901
- const scale = stage.scale();
3902
- const position = stage.position();
3903
- const stageClickPoint = {
3904
- x: (pointerPos.x - position.x) / scale.x,
3905
- y: (pointerPos.y - position.y) / scale.y
3906
- };
3907
- return stageClickPoint;
3908
- }
3909
- isContextMenuVisible() {
3910
- return this.contextMenuVisible;
3911
- }
3912
- isTapHold() {
3913
- return this.tapHold;
3914
- }
3915
- enable() {
3916
- this.enabled = true;
3917
- }
3918
- disable() {
3919
- this.enabled = false;
3920
- }
3921
- };
3922
-
3923
3699
  //#endregion
3924
3700
  //#region src/plugins/users-selection/constants.ts
3925
3701
  const WEAVE_USERS_SELECTION_KEY = "usersSelection";
@@ -4077,7 +3853,7 @@ var require_toNumber = __commonJS({ "../../node_modules/lodash/toNumber.js"(expo
4077
3853
  var require_debounce = __commonJS({ "../../node_modules/lodash/debounce.js"(exports, module) {
4078
3854
  var isObject$3 = require_isObject(), now = require_now(), toNumber = require_toNumber();
4079
3855
  /** Error message constants. */
4080
- var FUNC_ERROR_TEXT$3 = "Expected a function";
3856
+ var FUNC_ERROR_TEXT$2 = "Expected a function";
4081
3857
  var nativeMax = Math.max, nativeMin = Math.min;
4082
3858
  /**
4083
3859
  * Creates a debounced function that delays invoking `func` until after `wait`
@@ -4135,7 +3911,7 @@ var require_debounce = __commonJS({ "../../node_modules/lodash/debounce.js"(expo
4135
3911
  */
4136
3912
  function debounce$1(func, wait, options) {
4137
3913
  var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true;
4138
- if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$3);
3914
+ if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$2);
4139
3915
  wait = toNumber(wait) || 0;
4140
3916
  if (isObject$3(options)) {
4141
3917
  leading = !!options.leading;
@@ -4210,7 +3986,7 @@ var require_debounce = __commonJS({ "../../node_modules/lodash/debounce.js"(expo
4210
3986
  var require_throttle = __commonJS({ "../../node_modules/lodash/throttle.js"(exports, module) {
4211
3987
  var debounce = require_debounce(), isObject$2 = require_isObject();
4212
3988
  /** Error message constants. */
4213
- var FUNC_ERROR_TEXT$2 = "Expected a function";
3989
+ var FUNC_ERROR_TEXT$1 = "Expected a function";
4214
3990
  /**
4215
3991
  * Creates a throttled function that only invokes `func` at most once per
4216
3992
  * every `wait` milliseconds. The throttled function comes with a `cancel`
@@ -4257,7 +4033,7 @@ var require_throttle = __commonJS({ "../../node_modules/lodash/throttle.js"(expo
4257
4033
  */
4258
4034
  function throttle(func, wait, options) {
4259
4035
  var leading = true, trailing = true;
4260
- if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$2);
4036
+ if (typeof func != "function") throw new TypeError(FUNC_ERROR_TEXT$1);
4261
4037
  if (isObject$2(options)) {
4262
4038
  leading = "leading" in options ? !!options.leading : leading;
4263
4039
  trailing = "trailing" in options ? !!options.trailing : trailing;
@@ -4278,170 +4054,310 @@ const WEAVE_STAGE_NODE_TYPE = "stage";
4278
4054
  const WEAVE_STAGE_DEFAULT_MODE = "default";
4279
4055
 
4280
4056
  //#endregion
4281
- //#region src/plugins/stage-grid/constants.ts
4282
- const WEAVE_STAGE_GRID_PLUGIN_KEY = "stageGrid";
4283
- const WEAVE_GRID_TYPES = {
4284
- ["LINES"]: "lines",
4285
- ["DOTS"]: "dots"
4057
+ //#region src/actions/selection-tool/constants.ts
4058
+ const SELECTION_TOOL_ACTION_NAME = "selectionTool";
4059
+ const SELECTION_TOOL_STATE = {
4060
+ ["IDLE"]: "idle",
4061
+ ["SELECTING"]: "selection"
4286
4062
  };
4287
- const WEAVE_GRID_DOT_TYPES = {
4288
- ["SQUARE"]: "square",
4289
- ["CIRCLE"]: "circle"
4063
+
4064
+ //#endregion
4065
+ //#region src/constants.ts
4066
+ const DEFAULT_THROTTLE_MS = 50;
4067
+ const DEFAULT_ADD_NODE_OPTIONS = { emitUserChangeEvent: false };
4068
+ const DEFAULT_UPDATE_NODE_OPTIONS = { emitUserChangeEvent: false };
4069
+ const DEFAULT_REMOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4070
+ const DEFAULT_MOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4071
+ const WEAVE_DEFAULT_CONFIG = {
4072
+ behaviors: { axisLockThreshold: 5 },
4073
+ performance: { upscale: { enabled: false } }
4290
4074
  };
4291
- const WEAVE_GRID_DEFAULT_CONFIG = {
4292
- type: WEAVE_GRID_TYPES.LINES,
4293
- gridColor: "#b3b3b3",
4294
- gridMajorColor: "#b3b3b3",
4295
- gridOriginColor: "#ff746c",
4296
- gridSize: 20,
4297
- gridMajorEvery: 10,
4298
- gridMajorRatio: 2,
4299
- gridStroke: 1,
4300
- gridDotType: WEAVE_GRID_DOT_TYPES.CIRCLE,
4301
- gridDotRadius: 1,
4302
- gridDotRectSize: 2
4303
- };
4304
- const WEAVE_GRID_LAYER_ID = "gridLayer";
4305
4075
 
4306
4076
  //#endregion
4307
- //#region src/plugins/stage-panning/constants.ts
4308
- const WEAVE_STAGE_PANNING_KEY = "stagePanning";
4309
- const WEAVE_STAGE_PANNING_THROTTLE_MS = 20;
4310
- const WEAVE_STAGE_PANNING_DEFAULT_CONFIG = { edgePan: {
4311
- offset: 25,
4312
- speed: 20
4313
- } };
4314
-
4315
- //#endregion
4316
- //#region src/plugins/nodes-multi-selection-feedback/constants.ts
4317
- const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY = "nodesMultiSelectionFeedback";
4318
- const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID = "selectionLayer";
4319
- const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG = { style: {
4320
- stroke: "#ff2c2cff",
4321
- strokeWidth: 2,
4322
- fill: "transparent"
4323
- } };
4324
-
4325
- //#endregion
4326
- //#region src/constants.ts
4327
- const DEFAULT_THROTTLE_MS = 50;
4328
- const DEFAULT_ADD_NODE_OPTIONS = { emitUserChangeEvent: false };
4329
- const DEFAULT_UPDATE_NODE_OPTIONS = { emitUserChangeEvent: false };
4330
- const DEFAULT_REMOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4331
- const DEFAULT_MOVE_NODE_OPTIONS = { emitUserChangeEvent: false };
4332
- const WEAVE_DEFAULT_CONFIG = {
4333
- behaviors: { axisLockThreshold: 5 },
4334
- performance: { upscale: { enabled: false } }
4077
+ //#region src/plugins/nodes-selection/gesture-detector.ts
4078
+ const MOVED_DISTANCE = 5;
4079
+ const DOUBLE_TAP_DISTANCE = 10;
4080
+ const DOUBLE_TAP_TIME = 300;
4081
+ /**
4082
+ * Tracks single-tap, double-tap, and drag-move gesture state for the
4083
+ * nodes-selection plugin. Has no dependency on Weave or Konva internals.
4084
+ */
4085
+ var GestureDetector = class {
4086
+ taps = 0;
4087
+ tapStart = null;
4088
+ previousTap = null;
4089
+ tapTimeoutId = null;
4090
+ isDoubleTap = false;
4091
+ /** Call on every pointerdown to record the tap origin. */
4092
+ setTapStart(clientX, clientY) {
4093
+ this.taps += 1;
4094
+ this.tapStart = {
4095
+ x: clientX,
4096
+ y: clientY,
4097
+ time: performance.now()
4098
+ };
4099
+ }
4100
+ /** Returns true if the pointer moved more than the move threshold since tap start. */
4101
+ checkMoved(clientX, clientY) {
4102
+ if (!this.tapStart) return false;
4103
+ const dist = Math.hypot(clientX - this.tapStart.x, clientY - this.tapStart.y);
4104
+ return dist > MOVED_DISTANCE;
4105
+ }
4106
+ /** Returns true if a drag moved further than the move threshold between two stage positions. */
4107
+ checkMovedDrag(init, actual) {
4108
+ if (!this.tapStart) return false;
4109
+ const dist = Math.hypot(actual.x - init.x, actual.y - init.y);
4110
+ return dist > MOVED_DISTANCE;
4111
+ }
4112
+ /**
4113
+ * Call on pointerup after setTapStart to detect a double-tap.
4114
+ * Sets isDoubleTap = true when two taps occur close in time and space.
4115
+ */
4116
+ checkDoubleTap(clientX, clientY) {
4117
+ if (!this.previousTap) return;
4118
+ const now$2 = performance.now();
4119
+ const dist = Math.hypot(clientX - this.previousTap.x, clientY - this.previousTap.y);
4120
+ if (this.tapTimeoutId) clearTimeout(this.tapTimeoutId);
4121
+ this.tapTimeoutId = setTimeout(() => {
4122
+ this.taps = 0;
4123
+ }, DOUBLE_TAP_TIME + 5);
4124
+ if (this.taps > 1 && now$2 - this.previousTap.time < DOUBLE_TAP_TIME && dist < DOUBLE_TAP_DISTANCE) {
4125
+ this.taps = 0;
4126
+ this.tapStart = null;
4127
+ this.isDoubleTap = true;
4128
+ }
4129
+ }
4130
+ /** Call after checkDoubleTap on pointerup to advance the tap history. */
4131
+ commitTap() {
4132
+ this.previousTap = this.tapStart;
4133
+ }
4134
+ resetDoubleTap() {
4135
+ this.isDoubleTap = false;
4136
+ }
4137
+ reset() {
4138
+ this.taps = 0;
4139
+ this.tapStart = null;
4140
+ this.previousTap = null;
4141
+ this.isDoubleTap = false;
4142
+ if (this.tapTimeoutId) {
4143
+ clearTimeout(this.tapTimeoutId);
4144
+ this.tapTimeoutId = null;
4145
+ }
4146
+ }
4335
4147
  };
4336
4148
 
4337
4149
  //#endregion
4338
- //#region src/plugins/users-presence/constants.ts
4339
- const WEAVE_USER_PRESENCE_KEY = "userPresence";
4340
- const WEAVE_USERS_PRESENCE_PLUGIN_KEY = "usersPresence";
4341
- const WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS = { awarenessThrottleMs: DEFAULT_THROTTLE_MS };
4342
-
4343
- //#endregion
4344
- //#region src/plugins/nodes-selection/nodes-selection.ts
4345
- var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4346
- selectionStart = null;
4347
- panSpeed = {
4150
+ //#region src/plugins/nodes-selection/edge-panning.ts
4151
+ /**
4152
+ * Handles the rAF-driven auto-pan loop that scrolls the canvas when the
4153
+ * pointer is held near an edge during area selection.
4154
+ */
4155
+ var EdgePanning = class {
4156
+ panLoopId = null;
4157
+ direction = {
4348
4158
  x: 0,
4349
4159
  y: 0
4350
4160
  };
4351
- panDirection = {
4161
+ speed = {
4352
4162
  x: 0,
4353
4163
  y: 0
4354
4164
  };
4355
- panLoopId = null;
4356
- prevSelectedNodes = [];
4357
- handledClickOrTap = false;
4358
- dragInProcess = false;
4359
- dragSelectedNodes = [];
4360
- transformInProcess = false;
4361
- serializedSelectedNodes = [];
4362
- constructor(params) {
4363
- super();
4364
- this.config = mergeExceptArrays(WEAVE_NODES_SELECTION_DEFAULT_CONFIG, params?.config ?? {});
4365
- this.initialize();
4165
+ constructor(config, callbacks) {
4166
+ this.config = config;
4167
+ this.callbacks = callbacks;
4366
4168
  }
4367
- initialize() {
4368
- this.defaultEnabledAnchors = this.config.selection?.enabledAnchors ?? [
4369
- "top-left",
4370
- "top-center",
4371
- "top-right",
4372
- "middle-right",
4373
- "middle-left",
4374
- "bottom-left",
4375
- "bottom-center",
4376
- "bottom-right"
4377
- ];
4378
- this.taps = 0;
4379
- this.isSpaceKeyPressed = false;
4380
- this.isDoubleTap = false;
4381
- this.tapStart = null;
4382
- this.previousTap = null;
4383
- this.active = false;
4384
- this.didMove = false;
4385
- this.selecting = false;
4386
- this.initialized = false;
4387
- this.enabled = false;
4388
- this.pointers = {};
4389
- this.panLoopId = null;
4390
- this.tapTimeoutId = null;
4391
- this.dragSelectedNodes = [];
4392
- this.dragInProcess = false;
4169
+ /** Start the panning rAF loop. */
4170
+ start() {
4171
+ this.panLoopId = requestAnimationFrame(() => this.loop());
4393
4172
  }
4394
- getName() {
4395
- return WEAVE_NODES_SELECTION_KEY;
4173
+ /** Stop the panning rAF loop. */
4174
+ stop() {
4175
+ if (this.panLoopId !== null) {
4176
+ cancelAnimationFrame(this.panLoopId);
4177
+ this.panLoopId = null;
4178
+ }
4396
4179
  }
4397
- getLayerName() {
4398
- return WEAVE_NODES_SELECTION_LAYER_ID;
4180
+ /** Reset direction and speed vectors to zero. */
4181
+ reset() {
4182
+ this.direction.x = 0;
4183
+ this.direction.y = 0;
4184
+ this.speed = {
4185
+ x: 0,
4186
+ y: 0
4187
+ };
4399
4188
  }
4400
- getConfiguration() {
4401
- return this.config;
4189
+ /**
4190
+ * Recalculate pan direction and speed based on current pointer position.
4191
+ * Should be called on every pointermove during area selection.
4192
+ */
4193
+ updateDirection() {
4194
+ const stage = this.callbacks.getStage();
4195
+ const pos = stage.getPointerPosition();
4196
+ const viewWidth = stage.width();
4197
+ const viewHeight = stage.height();
4198
+ if (!pos) return;
4199
+ const distLeft = pos.x;
4200
+ const distRight = viewWidth - pos.x;
4201
+ const distTop = pos.y;
4202
+ const distBottom = viewHeight - pos.y;
4203
+ this.direction.x = 0;
4204
+ this.direction.y = 0;
4205
+ this.speed = {
4206
+ x: 0,
4207
+ y: 0
4208
+ };
4209
+ if (distLeft < this.config.edgeThreshold) {
4210
+ this.direction.x = 1;
4211
+ this.speed.x = this.getSpeedFromEdge(distLeft);
4212
+ } else if (distRight < this.config.edgeThreshold) {
4213
+ this.direction.x = -1;
4214
+ this.speed.x = this.getSpeedFromEdge(distRight);
4215
+ }
4216
+ if (distTop < this.config.edgeThreshold) {
4217
+ this.direction.y = 1;
4218
+ this.speed.y = this.getSpeedFromEdge(distTop);
4219
+ } else if (distBottom < this.config.edgeThreshold) {
4220
+ this.direction.y = -1;
4221
+ this.speed.y = this.getSpeedFromEdge(distBottom);
4222
+ }
4402
4223
  }
4403
- initLayer() {
4404
- const stage = this.instance.getStage();
4405
- const layer = new Konva.Layer({ id: this.getLayerName() });
4406
- stage.add(layer);
4224
+ getSpeedFromEdge(distanceFromEdge) {
4225
+ const stage = this.callbacks.getStage();
4226
+ const scaledDistance = distanceFromEdge / stage.scaleX();
4227
+ if (scaledDistance < this.config.edgeThreshold) {
4228
+ const factor = 1 - scaledDistance / this.config.edgeThreshold;
4229
+ return this.config.minScrollSpeed + (this.config.maxScrollSpeed - this.config.minScrollSpeed) * factor;
4230
+ }
4231
+ return 0;
4407
4232
  }
4408
- isPasting() {
4409
- const copyPastePlugin = this.instance.getPlugin("copyPasteNodes");
4410
- if (!copyPastePlugin) return false;
4411
- return copyPastePlugin.isPasting();
4233
+ loop() {
4234
+ const stage = this.callbacks.getStage();
4235
+ if (this.callbacks.isSelecting() && (this.direction.x !== 0 || this.direction.y !== 0)) {
4236
+ const scale = stage.scaleX();
4237
+ const stepX = (this.speed.x || 0) / scale;
4238
+ const stepY = (this.speed.y || 0) / scale;
4239
+ stage.x(stage.x() + this.direction.x * stepX);
4240
+ stage.y(stage.y() + this.direction.y * stepY);
4241
+ this.callbacks.onTick(this.direction.x * stepX, this.direction.y * stepY);
4242
+ }
4243
+ if (this.callbacks.isSelecting()) this.panLoopId = requestAnimationFrame(() => this.loop());
4412
4244
  }
4413
- isAreaSelecting() {
4414
- return this.selecting;
4245
+ };
4246
+
4247
+ //#endregion
4248
+ //#region src/plugins/nodes-selection/area-selection.ts
4249
+ /**
4250
+ * Manages the visual selection-rectangle drawn while the user drags an area
4251
+ * selection, plus the coordinate state (x1/y1/x2/y2) that tracks its bounds.
4252
+ */
4253
+ var AreaSelector = class {
4254
+ x1 = 0;
4255
+ y1 = 0;
4256
+ x2 = 0;
4257
+ y2 = 0;
4258
+ /** The stage-space anchor point when area selection started (updated by edge panning). */
4259
+ selectionStart = null;
4260
+ /**
4261
+ * Create and add the selection Konva.Rect to the given layer.
4262
+ * Must be called once during plugin initialisation.
4263
+ */
4264
+ init(layer, config, scaleX) {
4265
+ this.rect = new Konva.Rect({
4266
+ ...config,
4267
+ ...config.strokeWidth && { strokeWidth: config.strokeWidth / scaleX },
4268
+ ...config.dash && { dash: config.dash.map((d) => d / scaleX) },
4269
+ visible: false,
4270
+ listening: false
4271
+ });
4272
+ layer.add(this.rect);
4415
4273
  }
4416
- isSelecting() {
4417
- return this.instance.getActiveAction() === SELECTION_TOOL_ACTION_NAME;
4274
+ getRect() {
4275
+ return this.rect;
4418
4276
  }
4419
- isNodeSelected(ele) {
4420
- let selected = false;
4421
- if (this.getSelectedNodes().length === 1 && this.getSelectedNodes()[0].getAttrs().id === ele.getAttrs().id) selected = true;
4422
- return selected;
4277
+ /** Returns the screen-space bounding box of the selection rectangle. */
4278
+ getBox() {
4279
+ return this.rect.getClientRect();
4423
4280
  }
4424
- onInit() {
4425
- const stage = this.instance.getStage();
4426
- const selectionLayer = this.getLayer();
4427
- stage.container().tabIndex = 1;
4428
- stage.container().focus();
4429
- const selectionRectangle = new Konva.Rect({
4430
- ...this.config.selectionArea,
4431
- ...this.config.selectionArea.strokeWidth && { strokeWidth: this.config.selectionArea.strokeWidth / stage.scaleX() },
4432
- ...this.config.selectionArea.dash && { dash: this.config.selectionArea.dash.map((d) => d / stage.scaleX()) },
4433
- visible: false,
4434
- listening: false
4281
+ /** Set the anchor corner when area selection begins. */
4282
+ setStart(x, y) {
4283
+ this.x1 = x;
4284
+ this.y1 = y;
4285
+ this.x2 = x;
4286
+ this.y2 = y;
4287
+ this.selectionStart = {
4288
+ x,
4289
+ y
4290
+ };
4291
+ }
4292
+ /**
4293
+ * Adjust stroke and dash to compensate for stage scale, reset dimensions.
4294
+ * Call when area selection starts so the rect looks pixel-perfect at any zoom.
4295
+ */
4296
+ resetForScale(scaleX, config) {
4297
+ this.rect.strokeWidth(config.strokeWidth / scaleX);
4298
+ this.rect.dash(config.dash?.map((d) => d / scaleX) ?? []);
4299
+ this.rect.width(0);
4300
+ this.rect.height(0);
4301
+ }
4302
+ /**
4303
+ * Recalculate x2/y2 from the current pointer position and repaint the rect.
4304
+ * @param selectNone — Callback that clears the transformer selection; called
4305
+ * before updating the rect so previously selected nodes are deselected.
4306
+ */
4307
+ update(stage, selectNone) {
4308
+ this.x2 = stage.getRelativePointerPosition()?.x ?? 0;
4309
+ this.y2 = stage.getRelativePointerPosition()?.y ?? 0;
4310
+ selectNone();
4311
+ this.rect.setAttrs({
4312
+ visible: true,
4313
+ x: Math.min(this.x1, this.x2),
4314
+ y: Math.min(this.y1, this.y2),
4315
+ width: Math.abs(this.x2 - this.x1),
4316
+ height: Math.abs(this.y2 - this.y1)
4435
4317
  });
4436
- selectionLayer?.add(selectionRectangle);
4437
- const tr = new Konva.Transformer({
4318
+ }
4319
+ hide() {
4320
+ this.rect.setAttrs({
4321
+ width: 0,
4322
+ height: 0,
4323
+ visible: false
4324
+ });
4325
+ }
4326
+ };
4327
+
4328
+ //#endregion
4329
+ //#region src/plugins/nodes-selection/transformer-controller.ts
4330
+ /**
4331
+ * Creates and owns both Konva.Transformer instances (selection + hover) and
4332
+ * registers all transformer-level event handlers. Business-logic callbacks are
4333
+ * injected to keep this class decoupled from WeaveNodesSelectionPlugin internals.
4334
+ */
4335
+ var TransformerController = class {
4336
+ dragInProcess = false;
4337
+ transformInProcess = false;
4338
+ didMove = false;
4339
+ initialPos = null;
4340
+ originalNodes = {};
4341
+ originalContainers = {};
4342
+ currentDragSelectedNodes = [];
4343
+ /** Mirrors the previous transformer node list for undo/redo handling. */
4344
+ prevSelectedNodes = [];
4345
+ constructor(instance, config, gesture, callbacks) {
4346
+ this.instance = instance;
4347
+ this.config = config;
4348
+ this.gesture = gesture;
4349
+ this.callbacks = callbacks;
4350
+ }
4351
+ /** Create transformers, add to layer, and register all events. Must be called once during onInit. */
4352
+ setup(layer) {
4353
+ this.tr = new Konva.Transformer({
4438
4354
  id: "selectionTransformer",
4439
4355
  ...this.config.selection,
4440
4356
  listening: true,
4441
4357
  shouldOverdrawWholeArea: true
4442
4358
  });
4443
- selectionLayer?.add(tr);
4444
- const trHover = new Konva.Transformer({
4359
+ layer.add(this.tr);
4360
+ this.trHover = new Konva.Transformer({
4445
4361
  id: "hoverTransformer",
4446
4362
  ...this.config.hover,
4447
4363
  ignoreStroke: true,
@@ -4450,94 +4366,87 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4450
4366
  enabledAnchors: [],
4451
4367
  listening: false
4452
4368
  });
4453
- selectionLayer?.add(trHover);
4369
+ layer.add(this.trHover);
4370
+ this.registerStagePointerMove();
4371
+ this.registerTransformerEvents();
4372
+ this.registerInstanceEvents();
4373
+ }
4374
+ getTransformer() {
4375
+ return this.tr;
4376
+ }
4377
+ getHoverTransformer() {
4378
+ return this.trHover;
4379
+ }
4380
+ isDragging() {
4381
+ return this.dragInProcess;
4382
+ }
4383
+ isTransforming() {
4384
+ return this.transformInProcess;
4385
+ }
4386
+ getStage() {
4387
+ return this.instance.getStage();
4388
+ }
4389
+ registerStagePointerMove() {
4390
+ const stage = this.getStage();
4454
4391
  const handlePointerMoveInit = () => {
4455
4392
  if (this.dragInProcess) return;
4456
- if (tr.nodes().length === 1 && tr.nodes()[0].getAttrs().isContainerPrincipal) {
4393
+ if (this.tr.nodes().length === 1 && this.tr.nodes()[0].getAttrs().isContainerPrincipal) {
4457
4394
  const pos = stage.getPointerPosition();
4458
4395
  if (!pos) return;
4459
4396
  const shapeUnder = stage.getIntersection(pos);
4460
4397
  if (!shapeUnder) {
4461
- tr.setAttrs({ listening: true });
4462
- tr.forceUpdate();
4398
+ this.tr.setAttrs({ listening: true });
4399
+ this.tr.forceUpdate();
4463
4400
  }
4464
- if (shapeUnder && tr.getChildren().includes(shapeUnder) && shapeUnder.name() === "back") {
4465
- tr.setAttrs({ listening: false });
4466
- tr.forceUpdate();
4401
+ if (shapeUnder && this.tr.getChildren().includes(shapeUnder) && shapeUnder.name() === "back") {
4402
+ this.tr.setAttrs({ listening: false });
4403
+ this.tr.forceUpdate();
4467
4404
  }
4468
- if (shapeUnder && tr.nodes()[0].getChildren().includes(shapeUnder)) {
4469
- tr.setAttrs({ listening: false });
4470
- tr.forceUpdate();
4405
+ if (shapeUnder && this.tr.nodes()[0].getChildren().includes(shapeUnder)) {
4406
+ this.tr.setAttrs({ listening: false });
4407
+ this.tr.forceUpdate();
4471
4408
  }
4472
- if (shapeUnder && !tr.getChildren().includes(shapeUnder) && tr.nodes()[0].getChildren().includes(shapeUnder)) {
4473
- tr.setAttrs({ listening: true });
4474
- tr.forceUpdate();
4409
+ if (shapeUnder && !this.tr.getChildren().includes(shapeUnder) && this.tr.nodes()[0].getChildren().includes(shapeUnder)) {
4410
+ this.tr.setAttrs({ listening: true });
4411
+ this.tr.forceUpdate();
4475
4412
  }
4476
4413
  }
4477
4414
  };
4478
4415
  stage.on("pointermove", (0, import_throttle.default)(handlePointerMoveInit, DEFAULT_THROTTLE_MS));
4479
- tr.on("transformstart", (e) => {
4416
+ }
4417
+ registerTransformerEvents() {
4418
+ const stage = this.getStage();
4419
+ let nodeHovered = void 0;
4420
+ this.tr.on("transformstart", (e) => {
4480
4421
  this.transformInProcess = true;
4481
- this.triggerSelectedNodesEvent();
4482
- const selectedNodes$1 = tr.nodes();
4483
- for (const node of selectedNodes$1) node.handleMouseout(e);
4484
- if (this.getSelectedNodes().length > 1) this.instance.setMutexLock({
4485
- nodeIds: selectedNodes$1.map((node) => node.id()),
4422
+ this.callbacks.triggerSelectedNodesEvent();
4423
+ const selectedNodes = this.tr.nodes();
4424
+ for (const node of selectedNodes) node.handleMouseout(e);
4425
+ if (selectedNodes.length > 1) this.instance.setMutexLock({
4426
+ nodeIds: selectedNodes.map((node) => node.id()),
4486
4427
  operation: "nodes-transform"
4487
4428
  });
4488
4429
  this.instance.getHooks().callHook("weave:onTransformerTransformStart", {
4489
4430
  e,
4490
- nodes: selectedNodes$1
4431
+ nodes: selectedNodes
4491
4432
  });
4492
4433
  });
4493
- let nodeHovered = void 0;
4494
- tr.on("mousemove", (e) => {
4495
- if (this.dragInProcess) return;
4496
- const pointerPos = stage.getPointerPosition();
4497
- if (!pointerPos) return;
4498
- this.disable();
4499
- const shape = stage.getIntersection(pointerPos);
4500
- this.enable();
4501
- if (shape) {
4502
- const targetNode = this.instance.getInstanceRecursive(shape);
4503
- if (targetNode && targetNode !== nodeHovered) {
4504
- this.instance.getStage().handleMouseover(e);
4505
- nodeHovered?.handleMouseout?.(e);
4506
- targetNode?.handleMouseover?.(e);
4507
- nodeHovered = targetNode;
4508
- }
4509
- targetNode?.handleMouseover?.(e);
4510
- } else nodeHovered?.handleMouseout?.(e);
4511
- });
4512
- tr.on("mouseover", () => {
4513
- const nodesSelected = tr.nodes();
4514
- if (nodesSelected.length > 1) stage.container().style.cursor = "grab";
4515
- });
4516
- tr.on("mouseout", (e) => {
4517
- this.instance.getStage().handleMouseover?.(e);
4518
- nodeHovered = void 0;
4519
- });
4520
- window.addEventListener("mouseout", (e) => {
4521
- if (nodeHovered) {
4522
- nodeHovered.handleMouseout?.(e);
4523
- nodeHovered = void 0;
4524
- }
4525
- this.instance.getStage().handleMouseover?.(e);
4526
- }, { signal: this.instance.getEventsController()?.signal });
4527
4434
  const handleTransform = (e) => {
4528
- const moved = this.checkMoved(e);
4529
- if (moved) this.getContextMenuPlugin()?.cancelLongPressTimer();
4530
- this.triggerSelectedNodesEvent();
4435
+ const moved = this.gesture.checkMoved(e.evt.clientX, e.evt.clientY);
4436
+ if (moved) this.callbacks.getContextMenuPlugin()?.cancelLongPressTimer();
4437
+ this.callbacks.triggerSelectedNodesEvent();
4438
+ const selectedNodes = this.tr.nodes();
4531
4439
  this.instance.getHooks().callHook("weave:onTransformerTransform", {
4532
4440
  e,
4533
4441
  nodes: selectedNodes
4534
4442
  });
4535
- if (this.getUsersPresencePlugin()) {
4536
- for (const node of tr.nodes()) {
4443
+ const usersPresence = this.callbacks.getUsersPresencePlugin();
4444
+ if (usersPresence) {
4445
+ for (const node of this.tr.nodes()) {
4537
4446
  let parentId = node.getParent()?.id() ?? "";
4538
4447
  const parent = node.getParent();
4539
4448
  if (parent?.getAttrs().nodeId) parentId = parent.getAttrs().nodeId;
4540
- this.getUsersPresencePlugin()?.setPresence(node.id(), parentId, {
4449
+ usersPresence.setPresence(node.id(), parentId, {
4541
4450
  x: node.x(),
4542
4451
  y: node.y(),
4543
4452
  width: node.width(),
@@ -4548,65 +4457,92 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4548
4457
  strokeScaleEnabled: false
4549
4458
  }, false);
4550
4459
  }
4551
- this.getUsersPresencePlugin()?.forceSendPresence();
4460
+ usersPresence.forceSendPresence();
4552
4461
  }
4553
4462
  };
4554
- tr.on("transform", (0, import_throttle.default)(handleTransform, DEFAULT_THROTTLE_MS));
4555
- tr.on("transformend", (e) => {
4463
+ this.tr.on("transform", (0, import_throttle.default)(handleTransform, DEFAULT_THROTTLE_MS));
4464
+ this.tr.on("transformend", (e) => {
4556
4465
  this.transformInProcess = false;
4557
- if (this.getSelectedNodes().length > 1) this.instance.releaseMutexLock();
4558
- const selectedNodes$1 = tr.nodes();
4559
- for (const node of selectedNodes$1) {
4466
+ const selectedNodes = this.tr.nodes();
4467
+ if (selectedNodes.length > 1) this.instance.releaseMutexLock();
4468
+ for (const node of selectedNodes) {
4560
4469
  node.handleDeselectNode();
4561
4470
  node.handleSelectNode();
4562
4471
  }
4563
- tr.forceUpdate();
4564
- this.triggerSelectedNodesEvent();
4472
+ this.tr.forceUpdate();
4473
+ this.callbacks.triggerSelectedNodesEvent();
4565
4474
  this.instance.getHooks().callHook("weave:onTransformerTransformEnd", {
4566
4475
  e,
4567
- nodes: selectedNodes$1
4476
+ nodes: selectedNodes
4568
4477
  });
4569
4478
  });
4570
- let initialPos = null;
4571
- let originalNodes = {};
4572
- let originalContainers = {};
4573
- let selectedNodes = [];
4574
- tr.on("dragstart", (e) => {
4479
+ this.tr.on("mousemove", (e) => {
4480
+ if (this.dragInProcess) return;
4481
+ const pointerPos = stage.getPointerPosition();
4482
+ if (!pointerPos) return;
4483
+ this.callbacks.disablePlugin();
4484
+ const shape = stage.getIntersection(pointerPos);
4485
+ this.callbacks.enablePlugin();
4486
+ if (shape) {
4487
+ const targetNode = this.instance.getInstanceRecursive(shape);
4488
+ if (targetNode && targetNode !== nodeHovered) {
4489
+ this.instance.getStage().handleMouseover(e);
4490
+ nodeHovered?.handleMouseout?.(e);
4491
+ targetNode?.handleMouseover?.(e);
4492
+ nodeHovered = targetNode;
4493
+ }
4494
+ targetNode?.handleMouseover?.(e);
4495
+ } else nodeHovered?.handleMouseout?.(e);
4496
+ });
4497
+ this.tr.on("mouseover", () => {
4498
+ const nodesSelected = this.tr.nodes();
4499
+ if (nodesSelected.length > 1) stage.container().style.cursor = "grab";
4500
+ });
4501
+ this.tr.on("mouseout", (e) => {
4502
+ this.instance.getStage().handleMouseover?.(e);
4503
+ nodeHovered = void 0;
4504
+ });
4505
+ window.addEventListener("mouseout", (e) => {
4506
+ if (nodeHovered) {
4507
+ nodeHovered.handleMouseout?.(e);
4508
+ nodeHovered = void 0;
4509
+ }
4510
+ this.instance.getStage().handleMouseover?.(e);
4511
+ }, { signal: this.instance.getEventsController().signal });
4512
+ this.tr.on("dragstart", (e) => {
4575
4513
  this.dragInProcess = true;
4576
4514
  if (!e?.evt) return;
4577
- let isWheelMousePressed = false;
4578
- if (e.evt?.button === 1) isWheelMousePressed = true;
4515
+ const isWheelMousePressed = e.evt?.button === 1;
4579
4516
  const mainLayer = this.instance.getMainLayer();
4580
4517
  if (!mainLayer) return;
4581
- initialPos = {
4518
+ this.initialPos = {
4582
4519
  x: e.target.x(),
4583
4520
  y: e.target.y()
4584
4521
  };
4585
4522
  this.didMove = false;
4586
- const stage$1 = this.instance.getStage();
4587
- this.saveDragSelectedNodes();
4588
- this.setNodesOpacityOnDrag();
4589
- selectedNodes = tr.nodes();
4523
+ this.callbacks.saveDragSelectedNodes();
4524
+ this.callbacks.setNodesOpacityOnDrag();
4525
+ this.currentDragSelectedNodes = this.tr.nodes();
4590
4526
  if (isWheelMousePressed) {
4591
4527
  e.cancelBubble = true;
4592
4528
  e.target.stopDrag();
4593
4529
  return;
4594
4530
  }
4595
- for (const node of selectedNodes) {
4531
+ for (const node of this.currentDragSelectedNodes) {
4596
4532
  const originalNode = node.clone();
4597
4533
  let originalContainer = node.getParent();
4598
- if (originalContainer?.getAttrs().nodeId) originalContainer = stage$1.findOne(`#${originalContainer.getAttrs().nodeId}`);
4599
- originalNodes[node.getAttrs().id ?? ""] = originalNode;
4600
- originalContainers[node.getAttrs().id ?? ""] = originalContainer;
4534
+ if (originalContainer?.getAttrs().nodeId) originalContainer = stage.findOne(`#${originalContainer.getAttrs().nodeId}`);
4535
+ this.originalNodes[node.getAttrs().id ?? ""] = originalNode;
4536
+ this.originalContainers[node.getAttrs().id ?? ""] = originalContainer;
4601
4537
  }
4602
4538
  e.cancelBubble = true;
4603
4539
  this.instance.getHooks().callHook("weave:onTransformerDragStart", {
4604
4540
  e,
4605
- nodes: selectedNodes
4541
+ nodes: this.currentDragSelectedNodes
4606
4542
  });
4607
- tr.forceUpdate();
4608
- if (selectedNodes.length > 1) this.instance.setMutexLock({
4609
- nodeIds: selectedNodes.map((node) => node.id()),
4543
+ this.tr.forceUpdate();
4544
+ if (this.currentDragSelectedNodes.length > 1) this.instance.setMutexLock({
4545
+ nodeIds: this.currentDragSelectedNodes.map((node) => node.id()),
4610
4546
  operation: "nodes-drag"
4611
4547
  });
4612
4548
  });
@@ -4615,16 +4551,15 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4615
4551
  x: e.target.x(),
4616
4552
  y: e.target.y()
4617
4553
  };
4618
- let isWheelMousePressed = false;
4619
- if (e.evt?.button === 1) isWheelMousePressed = true;
4554
+ const isWheelMousePressed = e.evt?.button === 1;
4620
4555
  e.cancelBubble = true;
4621
4556
  this.instance.getHooks().callHook("weave:onTransformerDragMove", {
4622
4557
  e,
4623
- nodes: selectedNodes
4558
+ nodes: this.currentDragSelectedNodes
4624
4559
  });
4625
- if (initialPos) {
4626
- const moved = this.checkMovedDrag(initialPos, actualPos);
4627
- if (moved) this.getContextMenuPlugin()?.cancelLongPressTimer();
4560
+ if (this.initialPos) {
4561
+ const moved = this.gesture.checkMovedDrag(this.initialPos, actualPos);
4562
+ if (moved) this.callbacks.getContextMenuPlugin()?.cancelLongPressTimer();
4628
4563
  }
4629
4564
  if (isWheelMousePressed) {
4630
4565
  e.cancelBubble = true;
@@ -4633,64 +4568,65 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4633
4568
  }
4634
4569
  this.didMove = true;
4635
4570
  let selectionContainsFrames = false;
4636
- for (let i = 0; i < selectedNodes.length; i++) {
4637
- const node = selectedNodes[i];
4571
+ for (let i = 0; i < this.currentDragSelectedNodes.length; i++) {
4572
+ const node = this.currentDragSelectedNodes[i];
4638
4573
  selectionContainsFrames = selectionContainsFrames || hasFrames(node);
4639
4574
  node.updatePosition(node.getAbsolutePosition());
4640
4575
  }
4641
- if (selectedNodes.length === 1) {
4642
- originalNodes = {};
4643
- originalContainers = {};
4576
+ if (this.currentDragSelectedNodes.length === 1) {
4577
+ this.originalNodes = {};
4578
+ this.originalContainers = {};
4644
4579
  }
4645
- if (this.isSelecting() && selectedNodes.length > 1) {
4580
+ if (this.callbacks.isSelecting() && this.currentDragSelectedNodes.length > 1) {
4646
4581
  clearContainerTargets(this.instance);
4647
- const layerToMove = containerOverCursor(this.instance, selectedNodes);
4648
- if (this.getUsersPresencePlugin() && this.dragInProcess) {
4649
- for (const node of selectedNodes) {
4582
+ const layerToMove = containerOverCursor(this.instance, this.currentDragSelectedNodes);
4583
+ const usersPresence = this.callbacks.getUsersPresencePlugin();
4584
+ if (usersPresence && this.dragInProcess) {
4585
+ for (const node of this.currentDragSelectedNodes) {
4650
4586
  let parentId = node.getParent()?.id() ?? "";
4651
4587
  const parent = node.getParent();
4652
4588
  if (parent?.getAttrs().nodeId) parentId = parent.getAttrs().nodeId;
4653
- this.getUsersPresencePlugin()?.setPresence(node.id(), parentId, {
4589
+ usersPresence.setPresence(node.id(), parentId, {
4654
4590
  x: node.x(),
4655
4591
  y: node.y()
4656
4592
  }, false);
4657
4593
  }
4658
- this.getUsersPresencePlugin()?.forceSendPresence();
4594
+ usersPresence.forceSendPresence();
4659
4595
  }
4660
4596
  if (layerToMove && !selectionContainsFrames) layerToMove.fire(WEAVE_NODE_CUSTOM_EVENTS.onTargetEnter, { bubbles: true });
4661
4597
  }
4662
- tr.forceUpdate();
4598
+ this.tr.forceUpdate();
4663
4599
  };
4664
- tr.on("dragmove", handleDragMove);
4665
- tr.on("dragend", (e) => {
4600
+ this.tr.on("dragmove", handleDragMove);
4601
+ this.tr.on("dragend", (e) => {
4666
4602
  this.dragInProcess = false;
4667
4603
  const mainLayer = this.instance.getMainLayer();
4668
4604
  if (!mainLayer) return;
4669
4605
  this.instance.getSelectionLayer()?.hitGraphEnabled(true);
4670
4606
  this.instance.getMainLayer()?.hitGraphEnabled(true);
4671
4607
  if (!this.didMove) return;
4672
- if (selectedNodes.length > 1) this.instance.releaseMutexLock();
4608
+ if (this.currentDragSelectedNodes.length > 1) this.instance.releaseMutexLock();
4673
4609
  e.cancelBubble = true;
4674
4610
  this.instance.getHooks().callHook("weave:onTransformerDragEnd", {
4675
4611
  e,
4676
- nodes: selectedNodes
4612
+ nodes: this.currentDragSelectedNodes
4677
4613
  });
4678
4614
  this.instance.getCloningManager().cleanupClones();
4679
- this.getStagePanningPlugin()?.cleanupEdgeMoveIntervals();
4615
+ this.callbacks.getStagePanningPlugin()?.cleanupEdgeMoveIntervals();
4680
4616
  let selectionContainsFrames = false;
4681
- for (let i = 0; i < selectedNodes.length; i++) {
4682
- const node = selectedNodes[i];
4617
+ for (let i = 0; i < this.currentDragSelectedNodes.length; i++) {
4618
+ const node = this.currentDragSelectedNodes[i];
4683
4619
  selectionContainsFrames = selectionContainsFrames || hasFrames(node);
4684
4620
  node.updatePosition(node.getAbsolutePosition());
4685
4621
  }
4686
- if (this.isSelecting() && selectedNodes.length > 1) {
4622
+ if (this.callbacks.isSelecting() && this.currentDragSelectedNodes.length > 1) {
4687
4623
  const toSelect = [];
4688
4624
  const toUpdate = [];
4689
4625
  this.instance.stateTransactional(() => {
4690
4626
  const actualCursor = stage.container().style.cursor;
4691
4627
  stage.container().style.cursor = "wait";
4692
4628
  clearContainerTargets(this.instance);
4693
- const layerToMove = containerOverCursor(this.instance, selectedNodes);
4629
+ const layerToMove = containerOverCursor(this.instance, this.currentDragSelectedNodes);
4694
4630
  const nodeUpdate = (node) => {
4695
4631
  const isLockedToContainer = node.getAttrs().lockToContainer;
4696
4632
  let moved = false;
@@ -4700,18 +4636,17 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4700
4636
  let containerToMove = this.instance.getMainLayer();
4701
4637
  if (layerToMove) containerToMove = layerToMove;
4702
4638
  if (containerToMove && !selectionContainsFrames) {
4703
- moved = moveNodeToContainerNT(this.instance, node, containerToMove, originalNodes[node.getAttrs().id ?? ""], originalContainers[node.getAttrs().id ?? ""]);
4639
+ moved = moveNodeToContainerNT(this.instance, node, containerToMove, this.originalNodes[node.getAttrs().id ?? ""], this.originalContainers[node.getAttrs().id ?? ""]);
4704
4640
  if (moved) this.instance.emitEvent("onNodeChangedContainer", {
4705
- originalNode: originalNodes[node.getAttrs().id ?? ""] ?? null,
4706
- originalContainer: originalContainers[node.getAttrs().id ?? ""] ?? null,
4641
+ originalNode: this.originalNodes[node.getAttrs().id ?? ""] ?? null,
4642
+ originalContainer: this.originalContainers[node.getAttrs().id ?? ""] ?? null,
4707
4643
  newNode: node,
4708
4644
  newContainer: containerToMove
4709
4645
  });
4710
4646
  toSelect.push(node.getAttrs().id ?? "");
4711
- delete originalNodes[node.getAttrs().id ?? ""];
4712
- delete originalContainers[node.getAttrs().id ?? ""];
4713
- } else if (node.getAttrs().nodeId) toSelect.push(node.getAttrs().nodeId ?? "");
4714
- else toSelect.push(node.getAttrs().id ?? "");
4647
+ delete this.originalNodes[node.getAttrs().id ?? ""];
4648
+ delete this.originalContainers[node.getAttrs().id ?? ""];
4649
+ } else toSelect.push(node.getAttrs().nodeId ? node.getAttrs().nodeId ?? "" : node.getAttrs().id ?? "");
4715
4650
  if (containerToMove) containerToMove.fire(WEAVE_NODE_CUSTOM_EVENTS.onTargetLeave, { bubbles: true });
4716
4651
  if (!nodeHandler) return;
4717
4652
  if (!moved) toUpdate.push(nodeHandler.serialize(node));
@@ -4723,14 +4658,14 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4723
4658
  toUpdate.push(nodeHandler.serialize(node));
4724
4659
  }
4725
4660
  };
4726
- for (let i = 0; i < selectedNodes.length; i++) nodeUpdate(selectedNodes[i]);
4661
+ for (let i = 0; i < this.currentDragSelectedNodes.length; i++) nodeUpdate(this.currentDragSelectedNodes[i]);
4727
4662
  if (toUpdate.length > 0) this.instance.updateNodesNT(toUpdate);
4728
4663
  this.instance.runPhaseHooks("onMoveNodesToContainer", (hook) => {
4729
- hook({ nodes: selectedNodes });
4664
+ hook({ nodes: this.currentDragSelectedNodes });
4730
4665
  });
4731
4666
  stage.container().style.cursor = actualCursor;
4732
4667
  });
4733
- for (const node of selectedNodes) node.setAttrs({ isCloned: void 0 });
4668
+ for (const node of this.currentDragSelectedNodes) node.setAttrs({ isCloned: void 0 });
4734
4669
  const finalSelectedNodes = [];
4735
4670
  for (const nodeId of toSelect) {
4736
4671
  const actNode = this.instance.getStage().findOne(`#${nodeId}`);
@@ -4740,17 +4675,19 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4740
4675
  actNode.handleSelectNode();
4741
4676
  }
4742
4677
  }
4743
- this.setSelectedNodes(finalSelectedNodes);
4744
- tr.forceUpdate();
4678
+ this.callbacks.setSelectedNodes(finalSelectedNodes);
4679
+ this.tr.forceUpdate();
4745
4680
  }
4746
4681
  });
4682
+ }
4683
+ registerInstanceEvents() {
4747
4684
  this.instance.addEventListener("onNodesChange", () => {
4748
- const currentSelectedNodes = tr.nodes();
4685
+ const currentSelectedNodes = this.tr.nodes();
4749
4686
  const unselectedNodes = this.prevSelectedNodes.filter((node) => !currentSelectedNodes.map((node1) => node1.getAttrs().id).includes(node.getAttrs().id));
4750
4687
  if (currentSelectedNodes.length > 1) for (const node of currentSelectedNodes) node.handleSelectNode();
4751
4688
  if (currentSelectedNodes.length === 1) currentSelectedNodes[0]?.handleDeselectNode?.();
4752
4689
  for (const node of unselectedNodes) node.handleDeselectNode();
4753
- this.prevSelectedNodes = tr.nodes();
4690
+ this.prevSelectedNodes = this.tr.nodes();
4754
4691
  });
4755
4692
  this.instance.addEventListener("onUndoChange", () => {
4756
4693
  this.handleUndoRedoSelectionChange();
@@ -4758,9 +4695,541 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4758
4695
  this.instance.addEventListener("onRedoChange", () => {
4759
4696
  this.handleUndoRedoSelectionChange();
4760
4697
  });
4761
- this.tr = tr;
4762
- this.trHover = trHover;
4763
- this.selectionRectangle = selectionRectangle;
4698
+ }
4699
+ handleUndoRedoSelectionChange() {
4700
+ const selectionLayer = this.instance.getSelectionLayer();
4701
+ const selectionFeedbackPlugin = this.callbacks.getNodesSelectionFeedbackPlugin();
4702
+ if (selectionLayer && selectionFeedbackPlugin) {
4703
+ selectionLayer.find(`.selection-halo`).forEach((node) => node.destroy());
4704
+ selectionFeedbackPlugin.cleanupSelectedHalos();
4705
+ const currentSelectedNodes = this.tr.nodes();
4706
+ if (currentSelectedNodes.length > 1) for (const node of currentSelectedNodes) node.handleSelectNode();
4707
+ if (currentSelectedNodes.length === 1) currentSelectedNodes[0].handleDeselectNode();
4708
+ this.prevSelectedNodes = currentSelectedNodes;
4709
+ }
4710
+ }
4711
+ };
4712
+
4713
+ //#endregion
4714
+ //#region src/plugins/context-menu/constants.ts
4715
+ const WEAVE_CONTEXT_MENU_PLUGIN_KEY = "contextMenu";
4716
+ const WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT = 4;
4717
+ const WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT = 4;
4718
+ const WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT = 500;
4719
+
4720
+ //#endregion
4721
+ //#region src/plugins/stage-grid/constants.ts
4722
+ const WEAVE_STAGE_GRID_PLUGIN_KEY = "stageGrid";
4723
+ const WEAVE_GRID_TYPES = {
4724
+ ["LINES"]: "lines",
4725
+ ["DOTS"]: "dots"
4726
+ };
4727
+ const WEAVE_GRID_DOT_TYPES = {
4728
+ ["SQUARE"]: "square",
4729
+ ["CIRCLE"]: "circle"
4730
+ };
4731
+ const WEAVE_GRID_DEFAULT_CONFIG = {
4732
+ type: WEAVE_GRID_TYPES.LINES,
4733
+ gridColor: "#b3b3b3",
4734
+ gridMajorColor: "#b3b3b3",
4735
+ gridOriginColor: "#ff746c",
4736
+ gridSize: 20,
4737
+ gridMajorEvery: 10,
4738
+ gridMajorRatio: 2,
4739
+ gridStroke: 1,
4740
+ gridDotType: WEAVE_GRID_DOT_TYPES.CIRCLE,
4741
+ gridDotRadius: 1,
4742
+ gridDotRectSize: 2
4743
+ };
4744
+ const WEAVE_GRID_LAYER_ID = "gridLayer";
4745
+
4746
+ //#endregion
4747
+ //#region src/plugins/stage-panning/constants.ts
4748
+ const WEAVE_STAGE_PANNING_KEY = "stagePanning";
4749
+ const WEAVE_STAGE_PANNING_THROTTLE_MS = 20;
4750
+ const WEAVE_STAGE_PANNING_DEFAULT_CONFIG = { edgePan: {
4751
+ offset: 25,
4752
+ speed: 20
4753
+ } };
4754
+
4755
+ //#endregion
4756
+ //#region src/plugins/nodes-multi-selection-feedback/constants.ts
4757
+ const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY = "nodesMultiSelectionFeedback";
4758
+ const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID = "selectionLayer";
4759
+ const WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG = { style: {
4760
+ stroke: "#ff2c2cff",
4761
+ strokeWidth: 2,
4762
+ fill: "transparent"
4763
+ } };
4764
+
4765
+ //#endregion
4766
+ //#region src/plugins/users-presence/constants.ts
4767
+ const WEAVE_USER_PRESENCE_KEY = "userPresence";
4768
+ const WEAVE_USERS_PRESENCE_PLUGIN_KEY = "usersPresence";
4769
+ const WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS = { awarenessThrottleMs: DEFAULT_THROTTLE_MS };
4770
+
4771
+ //#endregion
4772
+ //#region src/plugins/nodes-selection/plugin-accessors.ts
4773
+ function getContextMenuPlugin(instance) {
4774
+ return instance.getPlugin(WEAVE_CONTEXT_MENU_PLUGIN_KEY);
4775
+ }
4776
+ function getStageGridPlugin(instance) {
4777
+ return instance.getPlugin(WEAVE_STAGE_GRID_PLUGIN_KEY);
4778
+ }
4779
+ function getStagePanningPlugin(instance) {
4780
+ return instance.getPlugin(WEAVE_STAGE_PANNING_KEY);
4781
+ }
4782
+ function getNodesSelectionFeedbackPlugin(instance) {
4783
+ return instance.getPlugin(WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY);
4784
+ }
4785
+ function getUsersPresencePlugin(instance) {
4786
+ return instance.getPlugin(WEAVE_USERS_PRESENCE_PLUGIN_KEY);
4787
+ }
4788
+
4789
+ //#endregion
4790
+ //#region src/plugins/nodes-selection/events/click-tap.ts
4791
+ /**
4792
+ * Handles a single click or tap on the canvas: resolves the targeted node,
4793
+ * applies single/multi-selection logic, and triggers the selection-change
4794
+ * event. Called from both pointerdown (immediate click) and pointerup
4795
+ * (after area-selection ends with a tap).
4796
+ */
4797
+ function handleClickOrTap(ctx, e) {
4798
+ const weave = ctx.getWeaveInstance();
4799
+ const stage = weave.getStage();
4800
+ const tr = ctx.getTransformerController().getTransformer();
4801
+ ctx.setClickOrTapHandled(true);
4802
+ e.cancelBubble = true;
4803
+ if (!ctx.isEnabled()) return;
4804
+ if (weave.getActiveAction() !== SELECTION_TOOL_ACTION_NAME) return;
4805
+ const contextMenuPlugin = ctx.getContextMenuPlugin();
4806
+ if (contextMenuPlugin?.isContextMenuVisible()) ctx.getEdgePanning().stop();
4807
+ ctx.hideHoverState();
4808
+ const selectedGroup = getTargetedNode(weave);
4809
+ if (!ctx.isInitialized()) return;
4810
+ if (e.evt.pointerType === "mouse" && e.evt?.button && e.evt?.button !== 0) return;
4811
+ let areNodesSelected = false;
4812
+ let nodeTargeted = selectedGroup && !(selectedGroup.getAttrs().active ?? false) ? selectedGroup : e.target;
4813
+ if (e.target === weave.getStage()) {
4814
+ ctx.getGesture().resetDoubleTap();
4815
+ ctx.getNodesSelectionFeedbackPlugin()?.cleanupSelectedHalos();
4816
+ return;
4817
+ }
4818
+ nodeTargeted = weave.getRealSelectedNode(nodeTargeted);
4819
+ if (!nodeTargeted.getAttrs().nodeType) {
4820
+ ctx.getGesture().resetDoubleTap();
4821
+ return;
4822
+ }
4823
+ const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
4824
+ const nodeSelectedIndex = tr.nodes().findIndex((node) => {
4825
+ return node.getAttrs().id === nodeTargeted.getAttrs().id;
4826
+ });
4827
+ const isSelected = nodeSelectedIndex !== -1;
4828
+ const user = weave.getStore().getUser();
4829
+ const isLocked = nodeTargeted.getAttrs().locked ?? false;
4830
+ const isMutexLocked = nodeTargeted.getAttrs().mutexLocked && nodeTargeted.getAttrs().mutexUserId !== user.id;
4831
+ if (isLocked || isMutexLocked) {
4832
+ const parent = weave.getInstanceRecursive(nodeTargeted.getParent());
4833
+ const mainLayer = weave.getMainLayer();
4834
+ const isStage = parent instanceof Konva.Stage;
4835
+ const isMainLayer = parent === mainLayer;
4836
+ const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
4837
+ if (isStage || isMainLayer || isContainerEmptyArea) ctx.setSelectedNodes([]);
4838
+ return;
4839
+ }
4840
+ if (nodeTargeted.getAttrs().nodeId) {
4841
+ const realNode = stage.findOne(`#${nodeTargeted.getAttrs().nodeId}`);
4842
+ if (realNode) nodeTargeted = realNode;
4843
+ }
4844
+ if (typeof nodeTargeted.getAttrs().isContainerPrincipal !== "undefined" && !nodeTargeted.getAttrs().isContainerPrincipal) return;
4845
+ if (ctx.getGesture().isDoubleTap && !metaPressed) {
4846
+ ctx.getGesture().resetDoubleTap();
4847
+ nodeTargeted.dblClick();
4848
+ return;
4849
+ }
4850
+ const isCtrlOrCmdPressed = e.evt.ctrlKey || e.evt.metaKey;
4851
+ if (isCtrlOrCmdPressed) return;
4852
+ if (!metaPressed) {
4853
+ tr.nodes([nodeTargeted]);
4854
+ tr.show();
4855
+ areNodesSelected = true;
4856
+ }
4857
+ if (metaPressed && isSelected) {
4858
+ const nodes = tr.nodes().slice();
4859
+ nodes.splice(nodes.indexOf(nodeTargeted), 1);
4860
+ tr.nodes(nodes);
4861
+ areNodesSelected = true;
4862
+ }
4863
+ if (metaPressed && !isSelected) {
4864
+ tr.nodes(tr.nodes().concat([nodeTargeted]));
4865
+ areNodesSelected = true;
4866
+ }
4867
+ ctx.handleMultipleSelectionBehavior();
4868
+ ctx.handleBehaviors();
4869
+ if (areNodesSelected) {
4870
+ stage.container().tabIndex = 1;
4871
+ stage.container().focus();
4872
+ stage.container().style.cursor = (typeof nodeTargeted?.defineMousePointer === "function" ? nodeTargeted.defineMousePointer() : null) ?? "grab";
4873
+ }
4874
+ ctx.triggerSelectedNodesEvent();
4875
+ }
4876
+
4877
+ //#endregion
4878
+ //#region src/plugins/nodes-selection/events/keyboard.ts
4879
+ /**
4880
+ * Registers keydown/keyup listeners on the stage container.
4881
+ * Space key toggles the panning-override flag; Backspace/Delete removes
4882
+ * the currently selected nodes.
4883
+ */
4884
+ function registerKeyboardHandlers(ctx) {
4885
+ const stage = ctx.getWeaveInstance().getStage();
4886
+ const signal = ctx.getWeaveInstance().getEventsController().signal;
4887
+ stage.container().addEventListener("keydown", (e) => {
4888
+ if (e.code === "Space") ctx.setSpaceKeyPressed(true);
4889
+ if (e.code === "Backspace" || e.code === "Delete") {
4890
+ Promise.resolve().then(() => {
4891
+ ctx.removeSelectedNodes();
4892
+ });
4893
+ return;
4894
+ }
4895
+ }, { signal });
4896
+ stage.container().addEventListener("keyup", (e) => {
4897
+ if (e.code === "Space") ctx.setSpaceKeyPressed(false);
4898
+ }, { signal });
4899
+ }
4900
+
4901
+ //#endregion
4902
+ //#region src/plugins/nodes-selection/events/pointer-down.ts
4903
+ /**
4904
+ * Handles the stage `pointerdown` event: records pointer state, decides
4905
+ * whether to start an area-selection or delegate to a click/tap handler.
4906
+ */
4907
+ function handlePointerDown(ctx, e) {
4908
+ ctx.getGesture().setTapStart(e.evt.clientX, e.evt.clientY);
4909
+ if (e.target.getClassName().includes("custom-snap-guide")) return;
4910
+ ctx.setClickOrTapHandled(false);
4911
+ ctx.registerPointer(e.evt.pointerId, e.evt);
4912
+ if (e.evt.pointerType === "touch" && ctx.getPointerCount() > 1) return;
4913
+ if (e.evt.pointerType === "mouse" && e.evt?.button !== 0) return;
4914
+ if (e.evt.pointerType === "pen" && e.evt?.pressure <= .05) return;
4915
+ if (!ctx.isInitialized()) return;
4916
+ if (!ctx.isActive()) return;
4917
+ const stage = ctx.getWeaveInstance().getStage();
4918
+ if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
4919
+ const selectedGroup = getTargetedNode(ctx.getWeaveInstance());
4920
+ if (selectedGroup?.getParent() instanceof Konva.Transformer) {
4921
+ ctx.setAreaSelecting(false);
4922
+ ctx.getEdgePanning().stop();
4923
+ ctx.getAreaSelector().hide();
4924
+ return;
4925
+ }
4926
+ const isStage = e.target instanceof Konva.Stage;
4927
+ const isTransformer = e.target?.getParent() instanceof Konva.Transformer;
4928
+ const canBeTargeted = e.target.getAttrs().canBeTargeted !== false;
4929
+ const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
4930
+ if (isTransformer) return;
4931
+ if (!isStage && !isContainerEmptyArea && canBeTargeted) {
4932
+ ctx.setAreaSelecting(false);
4933
+ ctx.getEdgePanning().stop();
4934
+ ctx.getAreaSelector().hide();
4935
+ handleClickOrTap(ctx, e);
4936
+ return;
4937
+ }
4938
+ ctx.getEdgePanning().reset();
4939
+ const relPos = stage.getRelativePointerPosition() ?? {
4940
+ x: 0,
4941
+ y: 0
4942
+ };
4943
+ ctx.getAreaSelector().setStart(relPos.x, relPos.y);
4944
+ ctx.getAreaSelector().resetForScale(stage.scaleX(), ctx.getConfiguration().selectionArea);
4945
+ ctx.setAreaSelecting(true);
4946
+ const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
4947
+ if (isCtrlOrMetaPressed) {
4948
+ const tr = ctx.getTransformerController().getTransformer();
4949
+ const nodesSelected = tr.nodes();
4950
+ for (const node of nodesSelected) node.fire("onSelectionCleared", { bubbles: true });
4951
+ }
4952
+ ctx.selectNone();
4953
+ ctx.getWeaveInstance().emitEvent("onSelectionState", true);
4954
+ ctx.getEdgePanning().start();
4955
+ }
4956
+
4957
+ //#endregion
4958
+ //#region src/plugins/nodes-selection/events/pointer-move.ts
4959
+ /**
4960
+ * Handles the stage `pointermove` event: cancels long-press timers when
4961
+ * the pointer moves, hides the selection rect when no movement, and
4962
+ * updates the area-selection rectangle and edge-panning direction while
4963
+ * a selection drag is in progress.
4964
+ */
4965
+ function handlePointerMove(ctx, e) {
4966
+ if (!e?.evt) return;
4967
+ const moved = ctx.getGesture().checkMoved(e.evt.clientX, e.evt.clientY);
4968
+ if (e.evt?.buttons === 0) return;
4969
+ if (e.evt.pointerType === "touch" && ctx.getPointerCount() > 1) return;
4970
+ if (!ctx.isInitialized()) return;
4971
+ if (!ctx.isActive()) return;
4972
+ const contextMenuPlugin = ctx.getContextMenuPlugin();
4973
+ if (moved) contextMenuPlugin?.cancelLongPressTimer();
4974
+ else ctx.getAreaSelector().hide();
4975
+ if (contextMenuPlugin?.isContextMenuVisible()) ctx.getEdgePanning().stop();
4976
+ if (ctx.getSpaceKeyPressedState()) return;
4977
+ if (!ctx.isAreaSelecting()) return;
4978
+ ctx.getAreaSelector().update(ctx.getWeaveInstance().getStage(), () => ctx.selectNone());
4979
+ ctx.getEdgePanning().updateDirection();
4980
+ }
4981
+
4982
+ //#endregion
4983
+ //#region src/plugins/nodes-selection/events/pointer-up.ts
4984
+ /**
4985
+ * Handles the stage `pointerup` event: ends any in-progress area-selection
4986
+ * (including the node-filtering/commit step), or delegates to the click/tap
4987
+ * handler for point interactions.
4988
+ */
4989
+ function handlePointerUp(ctx, e) {
4990
+ const weave = ctx.getWeaveInstance();
4991
+ const stage = weave.getStage();
4992
+ const store = weave.getStore();
4993
+ const actUser = store.getUser();
4994
+ const tr = ctx.getTransformerController().getTransformer();
4995
+ tr.setAttrs({ listening: true });
4996
+ ctx.setAreaSelecting(false);
4997
+ ctx.getEdgePanning().stop();
4998
+ const moved = ctx.getGesture().checkMoved(e.evt.clientX, e.evt.clientY);
4999
+ ctx.getGesture().checkDoubleTap(e.evt.clientX, e.evt.clientY);
5000
+ ctx.unregisterPointer(e.evt.pointerId);
5001
+ ctx.getGesture().commitTap();
5002
+ if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
5003
+ const contextMenuPlugin = ctx.getContextMenuPlugin();
5004
+ if (!ctx.isInitialized()) {
5005
+ ctx.getAreaSelector().hide();
5006
+ return;
5007
+ }
5008
+ if (!ctx.isActive()) {
5009
+ ctx.getAreaSelector().hide();
5010
+ return;
5011
+ }
5012
+ weave.emitEvent("onSelectionState", false);
5013
+ if (ctx.getGesture().isDoubleTap) {
5014
+ ctx.getAreaSelector().hide();
5015
+ handleClickOrTap(ctx, e);
5016
+ return;
5017
+ }
5018
+ const isStage = e.target instanceof Konva.Stage;
5019
+ const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5020
+ if ((isStage || isContainerEmptyArea) && !moved) {
5021
+ ctx.setAreaSelecting(false);
5022
+ ctx.getEdgePanning().stop();
5023
+ ctx.getAreaSelector().hide();
5024
+ ctx.setSelectedNodes([]);
5025
+ return;
5026
+ }
5027
+ if (e.evt.pointerType === "touch" && ctx.getPointerCount() + 1 > 1) {
5028
+ ctx.getAreaSelector().hide();
5029
+ return;
5030
+ }
5031
+ if (contextMenuPlugin?.isContextMenuVisible()) ctx.getEdgePanning().stop();
5032
+ const selectedGroup = getTargetedNode(weave);
5033
+ if (!moved && selectedGroup?.getParent() instanceof Konva.Transformer && !ctx.wasClickOrTapHandled()) {
5034
+ ctx.setAreaSelecting(false);
5035
+ ctx.getEdgePanning().stop();
5036
+ ctx.getAreaSelector().hide();
5037
+ handleClickOrTap(ctx, e);
5038
+ return;
5039
+ }
5040
+ if (!ctx.getAreaSelector().getRect().visible()) {
5041
+ ctx.getAreaSelector().hide();
5042
+ return;
5043
+ }
5044
+ const shapes = stage.find((node) => {
5045
+ return ["Shape", "Group"].includes(node.getType()) && typeof node.getAttrs().id !== "undefined";
5046
+ });
5047
+ const box = ctx.getAreaSelector().getBox();
5048
+ ctx.getAreaSelector().getRect().visible(false);
5049
+ const selected = shapes.filter((shape) => {
5050
+ const shapeMutex = weave.getNodeMutexLock(shape.id());
5051
+ if (shapeMutex && shapeMutex.user.id !== actUser.id) return false;
5052
+ let parent = weave.getInstanceRecursive(shape.getParent());
5053
+ if (parent.getAttrs().nodeId) parent = stage.findOne(`#${parent.getAttrs().nodeId}`);
5054
+ if (shape.getAttrs().nodeType && shape.getAttrs().nodeType === "frame") {
5055
+ const frameBox = shape.getClientRect();
5056
+ 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;
5057
+ }
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
+ if (shape.getAttrs().nodeType && shape.getAttrs().nodeType !== "group" && ["layer", "frame"].includes(parent?.getAttrs().nodeType)) return shape.getAttrs().nodeType && Konva.Util.haveIntersection(box, shape.getClientRect());
5060
+ return false;
5061
+ });
5062
+ const selectedNodes = new Set();
5063
+ const containerNodesIds = [];
5064
+ const otherNodes = [];
5065
+ for (const node of selected) {
5066
+ let realNode = node;
5067
+ if (node.getAttrs().nodeId) realNode = stage.findOne(`#${node.getAttrs().nodeId}`);
5068
+ if (!realNode) continue;
5069
+ const isContainer = typeof realNode.getAttrs().isContainerPrincipal !== "undefined" && realNode.getAttrs().isContainerPrincipal;
5070
+ if (isContainer) {
5071
+ containerNodesIds.push(realNode.getAttrs().id ?? "");
5072
+ if (!realNode.getAttrs().locked) selectedNodes.add(realNode);
5073
+ } else otherNodes.push(realNode);
5074
+ }
5075
+ for (const node of otherNodes) {
5076
+ let parent = weave.getInstanceRecursive(node.getParent());
5077
+ if (parent?.getAttrs().nodeId) parent = stage.findOne(`#${parent.getAttrs().nodeId}`);
5078
+ if (parent && !containerNodesIds.includes(parent?.getAttrs().id ?? "") && !node.getAttrs().locked) selectedNodes.add(node);
5079
+ }
5080
+ ctx.setAreaSelecting(false);
5081
+ ctx.getEdgePanning().stop();
5082
+ tr.nodes([...selectedNodes]);
5083
+ ctx.handleMultipleSelectionBehavior();
5084
+ ctx.handleBehaviors();
5085
+ if (tr.nodes().length > 0) {
5086
+ stage.container().tabIndex = 1;
5087
+ stage.container().focus();
5088
+ }
5089
+ ctx.triggerSelectedNodesEvent();
5090
+ }
5091
+
5092
+ //#endregion
5093
+ //#region src/plugins/nodes-selection/nodes-selection.ts
5094
+ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5095
+ gesture = new GestureDetector();
5096
+ _handledClickOrTap = false;
5097
+ dragSelectedNodes = [];
5098
+ constructor(params) {
5099
+ super();
5100
+ this.config = mergeExceptArrays(WEAVE_NODES_SELECTION_DEFAULT_CONFIG, params?.config ?? {});
5101
+ this.initialize();
5102
+ }
5103
+ initialize() {
5104
+ this._defaultEnabledAnchors = this.config.selection?.enabledAnchors ?? [
5105
+ "top-left",
5106
+ "top-center",
5107
+ "top-right",
5108
+ "middle-right",
5109
+ "middle-left",
5110
+ "bottom-left",
5111
+ "bottom-center",
5112
+ "bottom-right"
5113
+ ];
5114
+ this.gesture.reset();
5115
+ this._isSpaceKeyPressed = false;
5116
+ this.active = false;
5117
+ this.selecting = false;
5118
+ this.initialized = false;
5119
+ this.enabled = false;
5120
+ this.pointers = {};
5121
+ this.dragSelectedNodes = [];
5122
+ }
5123
+ getName() {
5124
+ return WEAVE_NODES_SELECTION_KEY;
5125
+ }
5126
+ getLayerName() {
5127
+ return WEAVE_NODES_SELECTION_LAYER_ID;
5128
+ }
5129
+ getConfiguration() {
5130
+ return this.config;
5131
+ }
5132
+ getWeaveInstance() {
5133
+ return this.instance;
5134
+ }
5135
+ getGesture() {
5136
+ return this.gesture;
5137
+ }
5138
+ getAreaSelector() {
5139
+ return this.areaSelector;
5140
+ }
5141
+ getEdgePanning() {
5142
+ return this.edgePanning;
5143
+ }
5144
+ getTransformerController() {
5145
+ return this.transformerCtrl;
5146
+ }
5147
+ getDefaultEnabledAnchors() {
5148
+ return this._defaultEnabledAnchors;
5149
+ }
5150
+ isInitialized() {
5151
+ return this.initialized;
5152
+ }
5153
+ isActive() {
5154
+ return this.active;
5155
+ }
5156
+ getSpaceKeyPressedState() {
5157
+ return this._isSpaceKeyPressed;
5158
+ }
5159
+ setSpaceKeyPressed(val) {
5160
+ this._isSpaceKeyPressed = val;
5161
+ }
5162
+ getPointerCount() {
5163
+ return Object.keys(this.pointers).length;
5164
+ }
5165
+ registerPointer(id, evt) {
5166
+ this.pointers[id] = evt;
5167
+ }
5168
+ unregisterPointer(id) {
5169
+ delete this.pointers[id];
5170
+ }
5171
+ wasClickOrTapHandled() {
5172
+ return this._handledClickOrTap;
5173
+ }
5174
+ setClickOrTapHandled(val) {
5175
+ this._handledClickOrTap = val;
5176
+ }
5177
+ setAreaSelecting(val) {
5178
+ this.selecting = val;
5179
+ }
5180
+ initLayer() {
5181
+ const stage = this.instance.getStage();
5182
+ const layer = new Konva.Layer({ id: this.getLayerName() });
5183
+ stage.add(layer);
5184
+ }
5185
+ isPasting() {
5186
+ const copyPastePlugin = this.instance.getPlugin("copyPasteNodes");
5187
+ if (!copyPastePlugin) return false;
5188
+ return copyPastePlugin.isPasting();
5189
+ }
5190
+ isAreaSelecting() {
5191
+ return this.selecting;
5192
+ }
5193
+ isSelecting() {
5194
+ return this.instance.getActiveAction() === SELECTION_TOOL_ACTION_NAME;
5195
+ }
5196
+ isNodeSelected(ele) {
5197
+ return this.getSelectedNodes().length === 1 && this.getSelectedNodes()[0].getAttrs().id === ele.getAttrs().id;
5198
+ }
5199
+ onInit() {
5200
+ const stage = this.instance.getStage();
5201
+ const selectionLayer = this.getLayer();
5202
+ stage.container().tabIndex = 1;
5203
+ stage.container().focus();
5204
+ this.areaSelector = new AreaSelector();
5205
+ this.areaSelector.init(selectionLayer, this.config.selectionArea, stage.scaleX());
5206
+ this.edgePanning = new EdgePanning(this.config.panningWhenSelection, {
5207
+ getStage: () => this.instance.getStage(),
5208
+ isSelecting: () => this.isAreaSelecting(),
5209
+ onTick: (dx, dy) => {
5210
+ if (this.areaSelector.selectionStart) {
5211
+ this.areaSelector.selectionStart.x += dx;
5212
+ this.areaSelector.selectionStart.y += dy;
5213
+ }
5214
+ this.getStageGridPlugin()?.onRender();
5215
+ this.areaSelector.update(this.instance.getStage(), () => this.selectNone());
5216
+ }
5217
+ });
5218
+ const callbacks = {
5219
+ isSelecting: () => this.isSelecting(),
5220
+ setSelectedNodes: (nodes) => this.setSelectedNodes(nodes),
5221
+ triggerSelectedNodesEvent: () => this.triggerSelectedNodesEvent(),
5222
+ saveDragSelectedNodes: () => this.saveDragSelectedNodes(),
5223
+ setNodesOpacityOnDrag: () => this.setNodesOpacityOnDrag(),
5224
+ disablePlugin: () => this.disable(),
5225
+ enablePlugin: () => this.enable(),
5226
+ getContextMenuPlugin: () => this.getContextMenuPlugin(),
5227
+ getUsersPresencePlugin: () => this.getUsersPresencePlugin(),
5228
+ getStagePanningPlugin: () => this.getStagePanningPlugin(),
5229
+ getNodesSelectionFeedbackPlugin: () => this.getNodesSelectionFeedbackPlugin()
5230
+ };
5231
+ this.transformerCtrl = new TransformerController(this.instance, this.config, this.gesture, callbacks);
5232
+ this.transformerCtrl.setup(selectionLayer);
4764
5233
  this.initEvents();
4765
5234
  this.initialized = true;
4766
5235
  this.instance.addEventListener("onActiveActionChange", (activeAction) => {
@@ -4771,39 +5240,21 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4771
5240
  this.active = true;
4772
5241
  });
4773
5242
  this.instance.addEventListener("onNodeRemoved", (node) => {
4774
- const selectedNodes$1 = this.getSelectedNodes();
4775
- const newSelectedNodes = selectedNodes$1.filter((actNode) => {
4776
- return actNode.getAttrs().id !== node.id;
4777
- });
5243
+ const selectedNodes = this.getSelectedNodes();
5244
+ const newSelectedNodes = selectedNodes.filter((actNode) => actNode.getAttrs().id !== node.id);
4778
5245
  this.setSelectedNodes(newSelectedNodes);
4779
5246
  stage.container().tabIndex = 1;
4780
5247
  stage.container().focus();
4781
- stage.container().style.cursor = "default";
4782
- });
4783
- }
4784
- handleUndoRedoSelectionChange() {
4785
- const selectionLayer = this.instance.getSelectionLayer();
4786
- const selectionFeedbackPlugin = this.getNodesSelectionFeedbackPlugin();
4787
- if (selectionLayer && selectionFeedbackPlugin) {
4788
- selectionLayer.find(`.selection-halo`).forEach((node) => node.destroy());
4789
- selectionFeedbackPlugin.cleanupSelectedHalos();
4790
- const currentSelectedNodes = this.tr.nodes();
4791
- if (currentSelectedNodes.length > 1) for (const node of currentSelectedNodes) node.handleSelectNode();
4792
- if (currentSelectedNodes.length === 1) currentSelectedNodes[0].handleDeselectNode();
4793
- this.prevSelectedNodes = currentSelectedNodes;
4794
- }
5248
+ stage.container().style.cursor = "default";
5249
+ });
4795
5250
  }
4796
5251
  getLayer() {
4797
5252
  const stage = this.instance.getStage();
4798
5253
  return stage.findOne(`#${this.getLayerName()}`);
4799
5254
  }
4800
5255
  triggerSelectedNodesEvent() {
4801
- this.serializeSelectedNodes();
4802
- this.triggerSelectionAwarenessEvent();
4803
- this.triggerOnNodesChangeEvent();
4804
- }
4805
- serializeSelectedNodes() {
4806
- const selectedNodes = this.tr.getNodes().map((node) => {
5256
+ const tr = this.transformerCtrl.getTransformer();
5257
+ const selectedNodes = tr.getNodes().map((node) => {
4807
5258
  const nodeType = node.getAttr("nodeType");
4808
5259
  const nodeHandler = this.instance.getNodeHandler(nodeType);
4809
5260
  return {
@@ -4811,17 +5262,12 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4811
5262
  node: nodeHandler?.serialize(node)
4812
5263
  };
4813
5264
  });
4814
- this.serializedSelectedNodes = selectedNodes;
4815
- }
4816
- triggerSelectionAwarenessEvent() {
4817
5265
  const usersSelectionPlugin = this.instance.getPlugin(WEAVE_USERS_SELECTION_KEY);
4818
5266
  if (usersSelectionPlugin) requestAnimationFrame(() => {
4819
- usersSelectionPlugin.sendSelectionAwarenessInfo(this.tr);
5267
+ usersSelectionPlugin.sendSelectionAwarenessInfo(tr);
4820
5268
  });
4821
- }
4822
- triggerOnNodesChangeEvent() {
4823
5269
  requestAnimationFrame(() => {
4824
- this.instance.emitEvent("onNodesChange", this.serializedSelectedNodes);
5270
+ this.instance.emitEvent("onNodesChange", selectedNodes);
4825
5271
  });
4826
5272
  }
4827
5273
  removeElement(element) {
@@ -4841,334 +5287,13 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
4841
5287
  this.selectNone();
4842
5288
  this.triggerSelectedNodesEvent();
4843
5289
  }
4844
- updateSelectionRect() {
4845
- const stage = this.instance.getStage();
4846
- this.x2 = stage.getRelativePointerPosition()?.x ?? 0;
4847
- this.y2 = stage.getRelativePointerPosition()?.y ?? 0;
4848
- this.selectNone();
4849
- this.selectionRectangle.setAttrs({
4850
- visible: true,
4851
- x: Math.min(this.x1, this.x2),
4852
- y: Math.min(this.y1, this.y2),
4853
- width: Math.abs(this.x2 - this.x1),
4854
- height: Math.abs(this.y2 - this.y1)
4855
- });
4856
- }
4857
- getSpeedFromEdge(distanceFromEdge) {
4858
- const stage = this.instance.getStage();
4859
- const scaledDistance = distanceFromEdge / stage.scaleX();
4860
- if (scaledDistance < this.config.panningWhenSelection.edgeThreshold) {
4861
- const factor = 1 - scaledDistance / this.config.panningWhenSelection.edgeThreshold;
4862
- return this.config.panningWhenSelection.minScrollSpeed + (this.config.panningWhenSelection.maxScrollSpeed - this.config.panningWhenSelection.minScrollSpeed) * factor;
4863
- }
4864
- return 0;
4865
- }
4866
- updatePanDirection() {
4867
- const stage = this.instance.getStage();
4868
- const pos = stage.getPointerPosition();
4869
- const viewWidth = stage.width();
4870
- const viewHeight = stage.height();
4871
- if (!pos) return;
4872
- const distLeft = pos.x;
4873
- const distRight = viewWidth - pos.x;
4874
- const distTop = pos.y;
4875
- const distBottom = viewHeight - pos.y;
4876
- this.panDirection.x = 0;
4877
- this.panDirection.y = 0;
4878
- this.panSpeed = {
4879
- x: 0,
4880
- y: 0
4881
- };
4882
- if (distLeft < this.config.panningWhenSelection.edgeThreshold) {
4883
- this.panDirection.x = 1;
4884
- this.panSpeed.x = this.getSpeedFromEdge(distLeft);
4885
- } else if (distRight < this.config.panningWhenSelection.edgeThreshold) {
4886
- this.panDirection.x = -1;
4887
- this.panSpeed.x = this.getSpeedFromEdge(distRight);
4888
- }
4889
- if (distTop < this.config.panningWhenSelection.edgeThreshold) {
4890
- this.panDirection.y = 1;
4891
- this.panSpeed.y = this.getSpeedFromEdge(distTop);
4892
- } else if (distBottom < this.config.panningWhenSelection.edgeThreshold) {
4893
- this.panDirection.y = -1;
4894
- this.panSpeed.y = this.getSpeedFromEdge(distBottom);
4895
- }
4896
- }
4897
- stopPanLoop() {
4898
- if (this.panLoopId) {
4899
- cancelAnimationFrame(this.panLoopId);
4900
- this.panLoopId = null;
4901
- }
4902
- }
4903
- panLoop() {
4904
- const stage = this.instance.getStage();
4905
- if (this.isAreaSelecting() && (this.panDirection.x !== 0 || this.panDirection.y !== 0)) {
4906
- const scale = stage.scaleX();
4907
- const stepX = (this.panSpeed.x || 0) / scale;
4908
- const stepY = (this.panSpeed.y || 0) / scale;
4909
- stage.x(stage.x() + this.panDirection.x * stepX);
4910
- stage.y(stage.y() + this.panDirection.y * stepY);
4911
- if (this.selectionStart) {
4912
- this.selectionStart.x += this.panDirection.x * stepX;
4913
- this.selectionStart.y += this.panDirection.y * stepY;
4914
- }
4915
- this.getStageGridPlugin()?.onRender();
4916
- this.updateSelectionRect();
4917
- }
4918
- if (this.isAreaSelecting()) this.panLoopId = requestAnimationFrame(() => this.panLoop());
4919
- }
4920
- setTapStart(e) {
4921
- this.taps = this.taps + 1;
4922
- this.tapStart = {
4923
- x: e.evt.clientX,
4924
- y: e.evt.clientY,
4925
- time: performance.now()
4926
- };
4927
- }
4928
- checkMovedDrag(init, actual) {
4929
- if (!this.tapStart) return false;
4930
- const dx = actual.x - init.x;
4931
- const dy = actual.y - init.y;
4932
- const dist = Math.hypot(dx, dy);
4933
- const MOVED_DISTANCE = 5;
4934
- if (dist <= MOVED_DISTANCE) return false;
4935
- return true;
4936
- }
4937
- checkMoved(e) {
4938
- if (!this.tapStart) return false;
4939
- const dx = e.evt.clientX - this.tapStart.x;
4940
- const dy = e.evt.clientY - this.tapStart.y;
4941
- const dist = Math.hypot(dx, dy);
4942
- const MOVED_DISTANCE = 5;
4943
- if (dist <= MOVED_DISTANCE) return false;
4944
- return true;
4945
- }
4946
- checkDoubleTap(e) {
4947
- if (!this.previousTap) return;
4948
- const now$2 = performance.now();
4949
- const dx = e.evt.clientX - this.previousTap.x;
4950
- const dy = e.evt.clientY - this.previousTap.y;
4951
- const dist = Math.hypot(dx, dy);
4952
- const DOUBLE_TAP_DISTANCE = 10;
4953
- const DOUBLE_TAP_TIME = 300;
4954
- if (this.tapTimeoutId) clearTimeout(this.tapTimeoutId);
4955
- this.tapTimeoutId = setTimeout(() => {
4956
- this.taps = 0;
4957
- }, DOUBLE_TAP_TIME + 5);
4958
- if (this.taps > 1 && now$2 - this.previousTap.time < DOUBLE_TAP_TIME && dist < DOUBLE_TAP_DISTANCE) {
4959
- this.taps = 0;
4960
- this.tapStart = null;
4961
- this.isDoubleTap = true;
4962
- }
4963
- }
4964
- hideSelectorArea() {
4965
- this.selectionRectangle.setAttrs({
4966
- width: 0,
4967
- height: 0,
4968
- visible: false
4969
- });
4970
- }
4971
5290
  initEvents() {
4972
5291
  this.selecting = false;
4973
5292
  const stage = this.instance.getStage();
4974
- stage.container().addEventListener("keydown", (e) => {
4975
- if (e.code === "Space") this.isSpaceKeyPressed = true;
4976
- if (e.code === "Backspace" || e.code === "Delete") {
4977
- Promise.resolve().then(() => {
4978
- this.removeSelectedNodes();
4979
- });
4980
- return;
4981
- }
4982
- }, { signal: this.instance.getEventsController()?.signal });
4983
- stage.container().addEventListener("keyup", (e) => {
4984
- if (e.code === "Space") this.isSpaceKeyPressed = false;
4985
- }, { signal: this.instance.getEventsController()?.signal });
4986
- stage.on("pointerdown", (e) => {
4987
- this.setTapStart(e);
4988
- if (e.target.getClassName().includes("custom-snap-guide")) return;
4989
- this.handledClickOrTap = false;
4990
- this.pointers[e.evt.pointerId] = e.evt;
4991
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
4992
- if (e.evt.pointerType === "mouse" && e.evt?.button !== 0) return;
4993
- if (e.evt.pointerType === "pen" && e.evt?.pressure <= .05) return;
4994
- if (!this.initialized) return;
4995
- if (!this.active) return;
4996
- if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
4997
- const selectedGroup = getTargetedNode(this.instance);
4998
- if (selectedGroup?.getParent() instanceof Konva.Transformer) {
4999
- this.selecting = false;
5000
- this.stopPanLoop();
5001
- this.hideSelectorArea();
5002
- return;
5003
- }
5004
- const isStage = e.target instanceof Konva.Stage;
5005
- const isTransformer = e.target?.getParent() instanceof Konva.Transformer;
5006
- const canBeTargeted = e.target.getAttrs().canBeTargeted !== false;
5007
- const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5008
- if (isTransformer) return;
5009
- if (!isStage && !isContainerEmptyArea && canBeTargeted) {
5010
- this.selecting = false;
5011
- this.stopPanLoop();
5012
- this.hideSelectorArea();
5013
- this.handleClickOrTap(e);
5014
- return;
5015
- }
5016
- if (isStage || isContainerEmptyArea) {
5017
- this.setSelectedNodes([]);
5018
- this.serializeSelectedNodes();
5019
- this.triggerOnNodesChangeEvent();
5020
- }
5021
- this.panDirection.x = 0;
5022
- this.panDirection.y = 0;
5023
- this.panSpeed = {
5024
- x: 0,
5025
- y: 0
5026
- };
5027
- const intStage = this.instance.getStage();
5028
- this.x1 = intStage.getRelativePointerPosition()?.x ?? 0;
5029
- this.y1 = intStage.getRelativePointerPosition()?.y ?? 0;
5030
- this.x2 = intStage.getRelativePointerPosition()?.x ?? 0;
5031
- this.y2 = intStage.getRelativePointerPosition()?.y ?? 0;
5032
- this.selectionStart = {
5033
- x: this.x1,
5034
- y: this.y1
5035
- };
5036
- this.selectionRectangle.strokeWidth(this.config.selectionArea.strokeWidth / stage.scaleX());
5037
- this.selectionRectangle.dash(this.config.selectionArea.dash?.map((d) => d / stage.scaleX()) ?? []);
5038
- this.selectionRectangle.width(0);
5039
- this.selectionRectangle.height(0);
5040
- this.selecting = true;
5041
- const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
5042
- if (isCtrlOrMetaPressed) {
5043
- const nodesSelected = this.tr.nodes();
5044
- for (const node of nodesSelected) node.fire("onSelectionCleared", { bubbles: true });
5045
- }
5046
- this.selectNone();
5047
- this.instance.emitEvent("onSelectionState", true);
5048
- this.panLoopId = requestAnimationFrame(() => this.panLoop());
5049
- });
5050
- const handleMouseMove = (e) => {
5051
- if (!e?.evt) return;
5052
- const moved = this.checkMoved(e);
5053
- if (e.evt?.buttons === 0) return;
5054
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
5055
- if (!this.initialized) return;
5056
- if (!this.active) return;
5057
- const contextMenuPlugin = this.getContextMenuPlugin();
5058
- if (moved) contextMenuPlugin?.cancelLongPressTimer();
5059
- else this.hideSelectorArea();
5060
- if (contextMenuPlugin?.isContextMenuVisible()) this.stopPanLoop();
5061
- if (this.isSpaceKeyPressed) return;
5062
- if (!this.selecting) return;
5063
- this.updateSelectionRect();
5064
- this.updatePanDirection();
5065
- };
5066
- stage.on("pointermove", (0, import_throttle.default)(handleMouseMove, DEFAULT_THROTTLE_MS));
5067
- this.panLoop();
5068
- stage.on("pointerup", (e) => {
5069
- const store = this.instance.getStore();
5070
- const actUser = store.getUser();
5071
- this.tr.setAttrs({ listening: true });
5072
- this.selecting = false;
5073
- this.stopPanLoop();
5074
- const moved = this.checkMoved(e);
5075
- this.checkDoubleTap(e);
5076
- delete this.pointers[e.evt.pointerId];
5077
- this.previousTap = this.tapStart;
5078
- if (stage.mode() !== WEAVE_STAGE_DEFAULT_MODE) return;
5079
- const contextMenuPlugin = this.getContextMenuPlugin();
5080
- if (!this.initialized) {
5081
- this.hideSelectorArea();
5082
- return;
5083
- }
5084
- if (!this.active) {
5085
- this.hideSelectorArea();
5086
- return;
5087
- }
5088
- this.instance.emitEvent("onSelectionState", false);
5089
- if (this.isDoubleTap) {
5090
- this.hideSelectorArea();
5091
- this.handleClickOrTap(e);
5092
- return;
5093
- }
5094
- const isStage = e.target instanceof Konva.Stage;
5095
- const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5096
- if ((isStage || isContainerEmptyArea) && !moved) {
5097
- this.selecting = false;
5098
- this.stopPanLoop();
5099
- this.hideSelectorArea();
5100
- this.getSelectionPlugin()?.setSelectedNodes([]);
5101
- return;
5102
- }
5103
- if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length + 1 > 1) {
5104
- this.hideSelectorArea();
5105
- return;
5106
- }
5107
- if (contextMenuPlugin?.isContextMenuVisible()) this.stopPanLoop();
5108
- const selectedGroup = getTargetedNode(this.instance);
5109
- if (!moved && selectedGroup?.getParent() instanceof Konva.Transformer && !this.handledClickOrTap) {
5110
- this.selecting = false;
5111
- this.stopPanLoop();
5112
- this.hideSelectorArea();
5113
- this.handleClickOrTap(e);
5114
- return;
5115
- }
5116
- if (!this.selectionRectangle.visible()) {
5117
- this.hideSelectorArea();
5118
- return;
5119
- }
5120
- const shapes = stage.find((node) => {
5121
- return ["Shape", "Group"].includes(node.getType()) && typeof node.getAttrs().id !== "undefined";
5122
- });
5123
- const box = this.selectionRectangle.getClientRect();
5124
- this.selectionRectangle.visible(false);
5125
- const selected = shapes.filter((shape) => {
5126
- const shapeMutex = this.instance.getNodeMutexLock(shape.id());
5127
- if (shapeMutex && shapeMutex.user.id !== actUser.id) return false;
5128
- let parent = this.instance.getInstanceRecursive(shape.getParent());
5129
- if (parent.getAttrs().nodeId) parent = this.instance.getStage().findOne(`#${parent.getAttrs().nodeId}`);
5130
- if (shape.getAttrs().nodeType && shape.getAttrs().nodeType === "frame") {
5131
- const frameBox = shape.getClientRect();
5132
- 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;
5133
- return isContained;
5134
- }
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
- if (shape.getAttrs().nodeType && shape.getAttrs().nodeType !== "group" && ["layer", "frame"].includes(parent?.getAttrs().nodeType)) return shape.getAttrs().nodeType && Konva.Util.haveIntersection(box, shape.getClientRect());
5137
- return false;
5138
- });
5139
- const selectedNodes = new Set();
5140
- const uniqueContainerNodesIds = new Set();
5141
- const containerNodesIds = [];
5142
- const containerNodes = [];
5143
- const otherNodes = [];
5144
- for (const node of selected) {
5145
- let realNode = node;
5146
- if (node.getAttrs().nodeId) realNode = stage.findOne(`#${node.getAttrs().nodeId}`);
5147
- if (!realNode) continue;
5148
- const isContainer = typeof realNode.getAttrs().isContainerPrincipal !== "undefined" && realNode.getAttrs().isContainerPrincipal;
5149
- if (isContainer) {
5150
- containerNodes.push(realNode);
5151
- containerNodesIds.push(realNode.getAttrs().id ?? "");
5152
- uniqueContainerNodesIds.add(realNode.getAttrs().id ?? "");
5153
- if (!realNode.getAttrs().locked) selectedNodes.add(realNode);
5154
- } else otherNodes.push(realNode);
5155
- }
5156
- for (const node of otherNodes) {
5157
- let parent = this.instance.getInstanceRecursive(node.getParent());
5158
- if (parent?.getAttrs().nodeId) parent = this.instance.getStage().findOne(`#${parent.getAttrs().nodeId}`);
5159
- if (parent && !containerNodesIds.includes(parent?.getAttrs().id ?? "") && !node.getAttrs().locked) selectedNodes.add(node);
5160
- }
5161
- this.selecting = false;
5162
- this.stopPanLoop();
5163
- this.tr.nodes([...selectedNodes]);
5164
- this.handleMultipleSelectionBehavior();
5165
- this.handleBehaviors();
5166
- if (this.tr.nodes().length > 0) {
5167
- stage.container().tabIndex = 1;
5168
- stage.container().focus();
5169
- }
5170
- this.triggerSelectedNodesEvent();
5171
- });
5293
+ registerKeyboardHandlers(this);
5294
+ stage.on("pointerdown", (e) => handlePointerDown(this, e));
5295
+ stage.on("pointermove", (0, import_throttle.default)((e) => handlePointerMove(this, e), DEFAULT_THROTTLE_MS));
5296
+ stage.on("pointerup", (e) => handlePointerUp(this, e));
5172
5297
  this.instance.addEventListener("onStateChange", () => {
5173
5298
  requestAnimationFrame(() => {
5174
5299
  this.syncSelection();
@@ -5181,129 +5306,53 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5181
5306
  });
5182
5307
  }
5183
5308
  handleMultipleSelectionBehavior() {
5184
- if (this.tr.nodes().length > 1 && this.config.behaviors?.onMultipleSelection) {
5185
- const selectionBehavior = this.config.behaviors?.onMultipleSelection?.(this.tr.nodes());
5186
- this.tr.setAttrs(selectionBehavior);
5187
- this.tr.forceUpdate();
5309
+ const tr = this.transformerCtrl.getTransformer();
5310
+ if (tr.nodes().length > 1 && this.config.behaviors?.onMultipleSelection) {
5311
+ const selectionBehavior = this.config.behaviors.onMultipleSelection(tr.nodes());
5312
+ tr.setAttrs(selectionBehavior);
5313
+ tr.forceUpdate();
5188
5314
  }
5189
5315
  }
5190
5316
  syncSelection() {
5191
5317
  const stageMode = this.instance.getStage().mode();
5192
5318
  if (![WEAVE_STAGE_DEFAULT_MODE].includes(stageMode)) return;
5319
+ const tr = this.transformerCtrl.getTransformer();
5193
5320
  const newSelectedNodes = [];
5194
- const actualSelectedNodes = this.tr.nodes();
5321
+ const actualSelectedNodes = tr.nodes();
5195
5322
  for (const node of actualSelectedNodes) {
5196
5323
  const existNode = this.instance.getStage().findOne(`#${node.getAttrs().id}`);
5197
5324
  if (existNode) newSelectedNodes.push(existNode);
5198
5325
  }
5199
- this.tr.nodes([...newSelectedNodes]);
5200
- if (newSelectedNodes.length > 0) this.tr.forceUpdate();
5326
+ tr.nodes([...newSelectedNodes]);
5327
+ if (newSelectedNodes.length > 0) tr.forceUpdate();
5201
5328
  this.triggerSelectedNodesEvent();
5202
5329
  }
5203
5330
  getSelectionPlugin() {
5204
- const selectionPlugin = this.instance.getPlugin("nodesSelection");
5205
- return selectionPlugin;
5331
+ return this.instance.getPlugin("nodesSelection");
5206
5332
  }
5207
5333
  hideHoverState() {
5208
5334
  const selectionPlugin = this.getSelectionPlugin();
5209
5335
  if (!selectionPlugin) return;
5210
5336
  selectionPlugin.getHoverTransformer().nodes([]);
5211
5337
  }
5212
- handleClickOrTap(e) {
5213
- const stage = this.instance.getStage();
5214
- this.handledClickOrTap = true;
5215
- e.cancelBubble = true;
5216
- if (!this.enabled) return;
5217
- if (this.instance.getActiveAction() !== SELECTION_TOOL_ACTION_NAME) return;
5218
- const contextMenuPlugin = this.getContextMenuPlugin();
5219
- if (contextMenuPlugin?.isContextMenuVisible()) this.stopPanLoop();
5220
- this.hideHoverState();
5221
- const selectedGroup = getTargetedNode(this.instance);
5222
- if (!this.initialized) return;
5223
- if (e.evt.pointerType === "mouse" && e.evt?.button && e.evt?.button !== 0) return;
5224
- let areNodesSelected = false;
5225
- let nodeTargeted = selectedGroup && !(selectedGroup.getAttrs().active ?? false) ? selectedGroup : e.target;
5226
- if (e.target === this.instance.getStage()) {
5227
- this.isDoubleTap = false;
5228
- this.getNodesSelectionFeedbackPlugin()?.cleanupSelectedHalos();
5229
- return;
5230
- }
5231
- nodeTargeted = this.instance.getRealSelectedNode(nodeTargeted);
5232
- if (!nodeTargeted.getAttrs().nodeType) {
5233
- this.isDoubleTap = false;
5234
- return;
5235
- }
5236
- const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
5237
- const nodeSelectedIndex = this.tr.nodes().findIndex((node) => {
5238
- return node.getAttrs().id === nodeTargeted.getAttrs().id;
5239
- });
5240
- const isSelected = nodeSelectedIndex !== -1;
5241
- const user = this.instance.getStore().getUser();
5242
- const isLocked = nodeTargeted.getAttrs().locked ?? false;
5243
- const isMutexLocked = nodeTargeted.getAttrs().mutexLocked && nodeTargeted.getAttrs().mutexUserId !== user.id;
5244
- if (isLocked || isMutexLocked) {
5245
- const parent = this.instance.getInstanceRecursive(nodeTargeted.getParent());
5246
- const mainLayer = this.instance.getMainLayer();
5247
- const isStage = parent instanceof Konva.Stage;
5248
- const isMainLayer = parent === mainLayer;
5249
- const isContainerEmptyArea = e.target.getAttrs().isContainerPrincipal !== void 0 && !e.target.getAttrs().isContainerPrincipal;
5250
- if (isStage || isMainLayer || isContainerEmptyArea) this.getSelectionPlugin()?.setSelectedNodes([]);
5251
- return;
5252
- }
5253
- if (nodeTargeted.getAttrs().nodeId) {
5254
- const realNode = stage.findOne(`#${nodeTargeted.getAttrs().nodeId}`);
5255
- if (realNode) nodeTargeted = realNode;
5256
- }
5257
- if (typeof nodeTargeted.getAttrs().isContainerPrincipal !== "undefined" && !nodeTargeted.getAttrs().isContainerPrincipal) return;
5258
- if (this.isDoubleTap && !metaPressed) {
5259
- this.isDoubleTap = false;
5260
- nodeTargeted.dblClick();
5261
- return;
5262
- }
5263
- const isCtrlOrCmdPressed = e.evt.ctrlKey || e.evt.metaKey;
5264
- if (isCtrlOrCmdPressed) return;
5265
- if (!metaPressed) {
5266
- this.tr.nodes([nodeTargeted]);
5267
- this.tr.show();
5268
- areNodesSelected = true;
5269
- }
5270
- if (metaPressed && isSelected) {
5271
- const nodes = this.tr.nodes().slice();
5272
- nodes.splice(nodes.indexOf(nodeTargeted), 1);
5273
- this.tr.nodes(nodes);
5274
- areNodesSelected = true;
5275
- }
5276
- if (metaPressed && !isSelected) {
5277
- const nodes = this.tr.nodes().concat([nodeTargeted]);
5278
- this.tr.nodes(nodes);
5279
- areNodesSelected = true;
5280
- }
5281
- this.handleMultipleSelectionBehavior();
5282
- this.handleBehaviors();
5283
- if (areNodesSelected) {
5284
- stage.container().tabIndex = 1;
5285
- stage.container().focus();
5286
- stage.container().style.cursor = (typeof nodeTargeted?.defineMousePointer === "function" ? nodeTargeted.defineMousePointer() : null) ?? "grab";
5287
- }
5288
- this.triggerSelectedNodesEvent();
5289
- }
5290
5338
  getTransformer() {
5291
- return this.tr;
5339
+ return this.transformerCtrl.getTransformer();
5292
5340
  }
5293
5341
  getHoverTransformer() {
5294
- return this.trHover;
5342
+ return this.transformerCtrl.getHoverTransformer();
5295
5343
  }
5296
5344
  handleBehaviors() {
5345
+ const tr = this.transformerCtrl.getTransformer();
5297
5346
  const nodes = this.getSelectedNodes();
5298
5347
  const nodesSelected = nodes.length;
5299
- if (nodesSelected > 1 && !this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && !this.config.behaviors.singleSelection.enabled) this.tr.enabledAnchors([]);
5300
- if (nodesSelected > 1 && this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && this.config.behaviors.singleSelection.enabled) this.tr.enabledAnchors(this.defaultEnabledAnchors);
5348
+ if (nodesSelected > 1 && !this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && !this.config.behaviors.singleSelection.enabled) tr.enabledAnchors([]);
5349
+ if (nodesSelected > 1 && this.config.behaviors.multipleSelection.enabled || nodesSelected === 1 && this.config.behaviors.singleSelection.enabled) tr.enabledAnchors(this._defaultEnabledAnchors);
5301
5350
  let transformerAttrs = { ...this.config.selection };
5302
- if (this.tr && this.tr.nodes().length > 0) {
5303
- const currentAttrs = this.tr.getAttrs();
5351
+ if (tr && tr.nodes().length > 0) {
5352
+ const currentAttrs = tr.getAttrs();
5304
5353
  Object.keys(currentAttrs).forEach((key) => {
5305
- if (["rotationSnaps", "enabledAnchors"].includes(key)) this.tr.setAttr(key, []);
5306
- else this.tr.setAttr(key, void 0);
5354
+ if (["rotationSnaps", "enabledAnchors"].includes(key)) tr.setAttr(key, []);
5355
+ else tr.setAttr(key, void 0);
5307
5356
  });
5308
5357
  }
5309
5358
  if (nodesSelected === 1) {
@@ -5313,31 +5362,32 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5313
5362
  if (nodesSelected > 1) {
5314
5363
  const anchorsArrays = [];
5315
5364
  for (const node of nodes) anchorsArrays.push(node?.allowedAnchors?.() ?? []);
5316
- const enabledAnchors = intersectArrays(anchorsArrays);
5317
- transformerAttrs.enabledAnchors = enabledAnchors;
5365
+ transformerAttrs.enabledAnchors = intersectArrays(anchorsArrays);
5318
5366
  }
5319
- if (this.tr && this.tr.nodes().length > 0) {
5367
+ if (tr && tr.nodes().length > 0) {
5320
5368
  if (transformerAttrs.enabledAnchors?.length === 0) transformerAttrs.resizeEnabled = false;
5321
- this.tr.setAttrs(transformerAttrs);
5322
- this.tr.forceUpdate();
5323
- this.tr.getLayer()?.batchDraw();
5369
+ tr.setAttrs(transformerAttrs);
5370
+ tr.forceUpdate();
5371
+ tr.getLayer()?.batchDraw();
5324
5372
  }
5325
5373
  }
5326
5374
  setSelectedNodes(nodes) {
5327
- this.tr.setNodes(nodes);
5375
+ const tr = this.transformerCtrl.getTransformer();
5376
+ tr.setNodes(nodes);
5328
5377
  this.handleBehaviors();
5329
5378
  if (nodes.length === 0) this.getNodesSelectionFeedbackPlugin()?.cleanupSelectedHalos();
5330
5379
  const usersSelectionPlugin = this.instance.getPlugin(WEAVE_USERS_SELECTION_KEY);
5331
5380
  if (usersSelectionPlugin) requestAnimationFrame(() => {
5332
- usersSelectionPlugin.sendSelectionAwarenessInfo(this.tr);
5381
+ usersSelectionPlugin.sendSelectionAwarenessInfo(tr);
5333
5382
  });
5334
5383
  }
5335
5384
  getSelectedNodes() {
5336
- if (!this.tr) return [];
5337
- return this.tr.nodes();
5385
+ if (!this.transformerCtrl) return [];
5386
+ return this.transformerCtrl.getTransformer().nodes();
5338
5387
  }
5339
5388
  getSelectedNodesExtended() {
5340
- const selectedNodes = this.tr.getNodes().map((node) => {
5389
+ const tr = this.transformerCtrl.getTransformer();
5390
+ return tr.getNodes().map((node) => {
5341
5391
  const nodeType = node.getAttr("nodeType");
5342
5392
  const nodeHandler = this.instance.getNodeHandler(nodeType);
5343
5393
  return {
@@ -5345,17 +5395,13 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5345
5395
  node: nodeHandler?.serialize(node)
5346
5396
  };
5347
5397
  });
5348
- return selectedNodes;
5349
5398
  }
5350
5399
  selectAll() {
5351
5400
  const mainLayer = this.instance.getMainLayer();
5352
- if (mainLayer) {
5353
- const nodes = mainLayer.getChildren();
5354
- this.tr.nodes(nodes);
5355
- }
5401
+ if (mainLayer) this.transformerCtrl.getTransformer().nodes(mainLayer.getChildren());
5356
5402
  }
5357
5403
  selectNone() {
5358
- this.tr.nodes([]);
5404
+ this.transformerCtrl.getTransformer().nodes([]);
5359
5405
  }
5360
5406
  enable() {
5361
5407
  this.getLayer()?.show();
@@ -5366,36 +5412,31 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
5366
5412
  this.enabled = false;
5367
5413
  }
5368
5414
  getNodesSelectionFeedbackPlugin() {
5369
- const selectionFeedbackPlugin = this.instance.getPlugin(WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY);
5370
- return selectionFeedbackPlugin;
5415
+ return getNodesSelectionFeedbackPlugin(this.instance);
5371
5416
  }
5372
5417
  getContextMenuPlugin() {
5373
- const contextMenuPlugin = this.instance.getPlugin(WEAVE_CONTEXT_MENU_PLUGIN_KEY);
5374
- return contextMenuPlugin;
5418
+ return getContextMenuPlugin(this.instance);
5375
5419
  }
5376
5420
  getStageGridPlugin() {
5377
- const gridPlugin = this.instance.getPlugin(WEAVE_STAGE_GRID_PLUGIN_KEY);
5378
- return gridPlugin;
5421
+ return getStageGridPlugin(this.instance);
5379
5422
  }
5380
5423
  getStagePanningPlugin() {
5381
- const stagePanning = this.instance.getPlugin(WEAVE_STAGE_PANNING_KEY);
5382
- return stagePanning;
5424
+ return getStagePanningPlugin(this.instance);
5383
5425
  }
5384
5426
  getUsersPresencePlugin() {
5385
- const usersPresencePlugin = this.instance.getPlugin(WEAVE_USERS_PRESENCE_PLUGIN_KEY);
5386
- return usersPresencePlugin;
5427
+ return getUsersPresencePlugin(this.instance);
5387
5428
  }
5388
5429
  isTransforming() {
5389
- return this.transformInProcess;
5430
+ return this.transformerCtrl.isTransforming();
5390
5431
  }
5391
5432
  isDragging() {
5392
- return this.dragInProcess;
5433
+ return this.transformerCtrl.isDragging();
5393
5434
  }
5394
5435
  getSelectorConfig() {
5395
5436
  return this.config.selection;
5396
5437
  }
5397
5438
  saveDragSelectedNodes() {
5398
- this.dragSelectedNodes = this.tr.nodes();
5439
+ this.dragSelectedNodes = this.transformerCtrl.getTransformer().nodes();
5399
5440
  }
5400
5441
  getDragSelectedNodes() {
5401
5442
  return this.dragSelectedNodes;
@@ -5473,30 +5514,30 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
5473
5514
  this.initEvents();
5474
5515
  }
5475
5516
  writeClipboardImage(base64Data) {
5476
- return new Promise((resolve, reject$1) => {
5517
+ return new Promise((resolve, reject) => {
5477
5518
  setTimeout(async () => {
5478
- if (navigator.clipboard === void 0) return reject$1(new Error("Clipboard API not supported"));
5519
+ if (navigator.clipboard === void 0) return reject(new Error("Clipboard API not supported"));
5479
5520
  const res = await fetch(base64Data);
5480
5521
  const imageBlob = await res.blob();
5481
5522
  const item = new ClipboardItem({ [imageBlob.type]: imageBlob });
5482
5523
  navigator.clipboard.write([item]).then(() => {
5483
5524
  resolve();
5484
5525
  }).catch((error) => {
5485
- reject$1(error);
5526
+ reject(error);
5486
5527
  });
5487
5528
  });
5488
5529
  });
5489
5530
  }
5490
5531
  writeClipboardData(data) {
5491
- return new Promise((resolve, reject$1) => {
5532
+ return new Promise((resolve, reject) => {
5492
5533
  setTimeout(async () => {
5493
- if (navigator.clipboard === void 0) return reject$1(new Error("Clipboard API not supported"));
5534
+ if (navigator.clipboard === void 0) return reject(new Error("Clipboard API not supported"));
5494
5535
  const textBlob = new Blob([data], { type: "text/plain" });
5495
5536
  const item = new ClipboardItem({ [textBlob.type]: textBlob });
5496
5537
  navigator.clipboard.write([item]).then(() => {
5497
5538
  resolve();
5498
5539
  }).catch((error) => {
5499
- reject$1(error);
5540
+ reject(error);
5500
5541
  });
5501
5542
  });
5502
5543
  });
@@ -5566,7 +5607,7 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
5566
5607
  this.focusPasteCatcher();
5567
5608
  if (!this.enabled) return;
5568
5609
  }
5569
- }, { signal: this.instance.getEventsController()?.signal });
5610
+ }, { signal: this.instance.getEventsController().signal });
5570
5611
  if (catcher) catcher.addEventListener("paste", async (e) => {
5571
5612
  e.preventDefault();
5572
5613
  let items = void 0;
@@ -5585,7 +5626,7 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
5585
5626
  return;
5586
5627
  }
5587
5628
  this.sendExternalPasteEvent(void 0, items);
5588
- }, { signal: this.instance.getEventsController()?.signal });
5629
+ }, { signal: this.instance.getEventsController().signal });
5589
5630
  }
5590
5631
  sendExternalPasteEvent(dataList, items) {
5591
5632
  const stage = this.instance.getStage();
@@ -6828,7 +6869,7 @@ var require__arrayMap = __commonJS({ "../../node_modules/lodash/_arrayMap.js"(ex
6828
6869
  //#endregion
6829
6870
  //#region ../../node_modules/lodash/_isKey.js
6830
6871
  var require__isKey = __commonJS({ "../../node_modules/lodash/_isKey.js"(exports, module) {
6831
- var isArray$10 = require_isArray(), isSymbol$3 = require_isSymbol();
6872
+ var isArray$9 = require_isArray(), isSymbol$3 = require_isSymbol();
6832
6873
  /** Used to match property names within property paths. */
6833
6874
  var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/;
6834
6875
  /**
@@ -6840,7 +6881,7 @@ var require__isKey = __commonJS({ "../../node_modules/lodash/_isKey.js"(exports,
6840
6881
  * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
6841
6882
  */
6842
6883
  function isKey$3(value, object) {
6843
- if (isArray$10(value)) return false;
6884
+ if (isArray$9(value)) return false;
6844
6885
  var type = typeof value;
6845
6886
  if (type == "number" || type == "symbol" || type == "boolean" || value == null || isSymbol$3(value)) return true;
6846
6887
  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object(object);
@@ -6853,7 +6894,7 @@ var require__isKey = __commonJS({ "../../node_modules/lodash/_isKey.js"(exports,
6853
6894
  var require_memoize = __commonJS({ "../../node_modules/lodash/memoize.js"(exports, module) {
6854
6895
  var MapCache$1 = require__MapCache();
6855
6896
  /** Error message constants. */
6856
- var FUNC_ERROR_TEXT$1 = "Expected a function";
6897
+ var FUNC_ERROR_TEXT = "Expected a function";
6857
6898
  /**
6858
6899
  * Creates a function that memoizes the result of `func`. If `resolver` is
6859
6900
  * provided, it determines the cache key for storing the result based on the
@@ -6899,7 +6940,7 @@ var require_memoize = __commonJS({ "../../node_modules/lodash/memoize.js"(export
6899
6940
  * _.memoize.Cache = WeakMap;
6900
6941
  */
6901
6942
  function memoize$2(func, resolver) {
6902
- if (typeof func != "function" || resolver != null && typeof resolver != "function") throw new TypeError(FUNC_ERROR_TEXT$1);
6943
+ if (typeof func != "function" || resolver != null && typeof resolver != "function") throw new TypeError(FUNC_ERROR_TEXT);
6903
6944
  var memoized = function() {
6904
6945
  var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
6905
6946
  if (cache.has(key)) return cache.get(key);
@@ -6968,7 +7009,7 @@ var require__stringToPath = __commonJS({ "../../node_modules/lodash/_stringToPat
6968
7009
  //#endregion
6969
7010
  //#region ../../node_modules/lodash/_baseToString.js
6970
7011
  var require__baseToString = __commonJS({ "../../node_modules/lodash/_baseToString.js"(exports, module) {
6971
- var Symbol$2 = require__Symbol(), arrayMap$1 = require__arrayMap(), isArray$9 = require_isArray(), isSymbol$2 = require_isSymbol();
7012
+ var Symbol$2 = require__Symbol(), arrayMap$1 = require__arrayMap(), isArray$8 = require_isArray(), isSymbol$2 = require_isSymbol();
6972
7013
  /** Used as references for various `Number` constants. */
6973
7014
  var INFINITY$1 = Infinity;
6974
7015
  /** Used to convert symbols to primitives and strings. */
@@ -6983,7 +7024,7 @@ var require__baseToString = __commonJS({ "../../node_modules/lodash/_baseToStrin
6983
7024
  */
6984
7025
  function baseToString$1(value) {
6985
7026
  if (typeof value == "string") return value;
6986
- if (isArray$9(value)) return arrayMap$1(value, baseToString$1) + "";
7027
+ if (isArray$8(value)) return arrayMap$1(value, baseToString$1) + "";
6987
7028
  if (isSymbol$2(value)) return symbolToString ? symbolToString.call(value) : "";
6988
7029
  var result = value + "";
6989
7030
  return result == "0" && 1 / value == -INFINITY$1 ? "-0" : result;
@@ -7025,7 +7066,7 @@ var require_toString = __commonJS({ "../../node_modules/lodash/toString.js"(expo
7025
7066
  //#endregion
7026
7067
  //#region ../../node_modules/lodash/_castPath.js
7027
7068
  var require__castPath = __commonJS({ "../../node_modules/lodash/_castPath.js"(exports, module) {
7028
- var isArray$8 = require_isArray(), isKey$2 = require__isKey(), stringToPath = require__stringToPath(), toString = require_toString();
7069
+ var isArray$7 = require_isArray(), isKey$2 = require__isKey(), stringToPath = require__stringToPath(), toString = require_toString();
7029
7070
  /**
7030
7071
  * Casts `value` to a path array if it's not one.
7031
7072
  *
@@ -7035,7 +7076,7 @@ var require__castPath = __commonJS({ "../../node_modules/lodash/_castPath.js"(ex
7035
7076
  * @returns {Array} Returns the cast property path array.
7036
7077
  */
7037
7078
  function castPath$2(value, object) {
7038
- if (isArray$8(value)) return value;
7079
+ if (isArray$7(value)) return value;
7039
7080
  return isKey$2(value, object) ? [value] : stringToPath(toString(value));
7040
7081
  }
7041
7082
  module.exports = castPath$2;
@@ -7362,7 +7403,7 @@ var require__arrayPush = __commonJS({ "../../node_modules/lodash/_arrayPush.js"(
7362
7403
  //#endregion
7363
7404
  //#region ../../node_modules/lodash/_baseGetAllKeys.js
7364
7405
  var require__baseGetAllKeys = __commonJS({ "../../node_modules/lodash/_baseGetAllKeys.js"(exports, module) {
7365
- var arrayPush = require__arrayPush(), isArray$7 = require_isArray();
7406
+ var arrayPush = require__arrayPush(), isArray$6 = require_isArray();
7366
7407
  /**
7367
7408
  * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
7368
7409
  * `keysFunc` and `symbolsFunc` to get the enumerable property names and
@@ -7376,7 +7417,7 @@ var require__baseGetAllKeys = __commonJS({ "../../node_modules/lodash/_baseGetAl
7376
7417
  */
7377
7418
  function baseGetAllKeys$1(object, keysFunc, symbolsFunc) {
7378
7419
  var result = keysFunc(object);
7379
- return isArray$7(object) ? result : arrayPush(result, symbolsFunc(object));
7420
+ return isArray$6(object) ? result : arrayPush(result, symbolsFunc(object));
7380
7421
  }
7381
7422
  module.exports = baseGetAllKeys$1;
7382
7423
  } });
@@ -7393,7 +7434,7 @@ var require__arrayFilter = __commonJS({ "../../node_modules/lodash/_arrayFilter.
7393
7434
  * @param {Function} predicate The function invoked per iteration.
7394
7435
  * @returns {Array} Returns the new filtered array.
7395
7436
  */
7396
- function arrayFilter$2(array, predicate) {
7437
+ function arrayFilter$1(array, predicate) {
7397
7438
  var index = -1, length = array == null ? 0 : array.length, resIndex = 0, result = [];
7398
7439
  while (++index < length) {
7399
7440
  var value = array[index];
@@ -7401,7 +7442,7 @@ var require__arrayFilter = __commonJS({ "../../node_modules/lodash/_arrayFilter.
7401
7442
  }
7402
7443
  return result;
7403
7444
  }
7404
- module.exports = arrayFilter$2;
7445
+ module.exports = arrayFilter$1;
7405
7446
  } });
7406
7447
 
7407
7448
  //#endregion
@@ -7434,7 +7475,7 @@ var require_stubArray = __commonJS({ "../../node_modules/lodash/stubArray.js"(ex
7434
7475
  //#endregion
7435
7476
  //#region ../../node_modules/lodash/_getSymbols.js
7436
7477
  var require__getSymbols = __commonJS({ "../../node_modules/lodash/_getSymbols.js"(exports, module) {
7437
- var arrayFilter$1 = require__arrayFilter(), stubArray = require_stubArray();
7478
+ var arrayFilter = require__arrayFilter(), stubArray = require_stubArray();
7438
7479
  /** Used for built-in method references. */
7439
7480
  var objectProto$2 = Object.prototype;
7440
7481
  /** Built-in value references. */
@@ -7450,7 +7491,7 @@ var require__getSymbols = __commonJS({ "../../node_modules/lodash/_getSymbols.js
7450
7491
  var getSymbols$1 = !nativeGetSymbols ? stubArray : function(object) {
7451
7492
  if (object == null) return [];
7452
7493
  object = Object(object);
7453
- return arrayFilter$1(nativeGetSymbols(object), function(symbol) {
7494
+ return arrayFilter(nativeGetSymbols(object), function(symbol) {
7454
7495
  return propertyIsEnumerable.call(object, symbol);
7455
7496
  });
7456
7497
  };
@@ -7574,7 +7615,7 @@ var require__equalObjects = __commonJS({ "../../node_modules/lodash/_equalObject
7574
7615
  //#endregion
7575
7616
  //#region ../../node_modules/lodash/_baseIsEqualDeep.js
7576
7617
  var require__baseIsEqualDeep = __commonJS({ "../../node_modules/lodash/_baseIsEqualDeep.js"(exports, module) {
7577
- var Stack$1 = require__Stack(), equalArrays = require__equalArrays(), equalByTag = require__equalByTag(), equalObjects = require__equalObjects(), getTag = require__getTag(), isArray$6 = require_isArray(), isBuffer = require_isBuffer(), isTypedArray = require_isTypedArray();
7618
+ 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();
7578
7619
  /** Used to compose bitmasks for value comparisons. */
7579
7620
  var COMPARE_PARTIAL_FLAG$2 = 1;
7580
7621
  /** `Object#toString` result references. */
@@ -7598,7 +7639,7 @@ var require__baseIsEqualDeep = __commonJS({ "../../node_modules/lodash/_baseIsEq
7598
7639
  * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
7599
7640
  */
7600
7641
  function baseIsEqualDeep$1(object, other, bitmask, customizer, equalFunc, stack) {
7601
- var objIsArr = isArray$6(object), othIsArr = isArray$6(other), objTag = objIsArr ? arrayTag : getTag(object), othTag = othIsArr ? arrayTag : getTag(other);
7642
+ var objIsArr = isArray$5(object), othIsArr = isArray$5(other), objTag = objIsArr ? arrayTag : getTag(object), othTag = othIsArr ? arrayTag : getTag(other);
7602
7643
  objTag = objTag == argsTag ? objectTag : objTag;
7603
7644
  othTag = othTag == argsTag ? objectTag : othTag;
7604
7645
  var objIsObj = objTag == objectTag, othIsObj = othTag == objectTag, isSameTag = objTag == othTag;
@@ -7834,7 +7875,7 @@ var require__baseHasIn = __commonJS({ "../../node_modules/lodash/_baseHasIn.js"(
7834
7875
  //#endregion
7835
7876
  //#region ../../node_modules/lodash/_hasPath.js
7836
7877
  var require__hasPath = __commonJS({ "../../node_modules/lodash/_hasPath.js"(exports, module) {
7837
- var castPath = require__castPath(), isArguments = require_isArguments(), isArray$5 = require_isArray(), isIndex = require__isIndex(), isLength = require_isLength(), toKey$2 = require__toKey();
7878
+ var castPath = require__castPath(), isArguments = require_isArguments(), isArray$4 = require_isArray(), isIndex = require__isIndex(), isLength = require_isLength(), toKey$2 = require__toKey();
7838
7879
  /**
7839
7880
  * Checks if `path` exists on `object`.
7840
7881
  *
@@ -7854,7 +7895,7 @@ var require__hasPath = __commonJS({ "../../node_modules/lodash/_hasPath.js"(expo
7854
7895
  }
7855
7896
  if (result || ++index != length) return result;
7856
7897
  length = object == null ? 0 : object.length;
7857
- return !!length && isLength(length) && isIndex(key, length) && (isArray$5(object) || isArguments(object));
7898
+ return !!length && isLength(length) && isIndex(key, length) && (isArray$4(object) || isArguments(object));
7858
7899
  }
7859
7900
  module.exports = hasPath$1;
7860
7901
  } });
@@ -7991,7 +8032,7 @@ var require_property = __commonJS({ "../../node_modules/lodash/property.js"(expo
7991
8032
  //#endregion
7992
8033
  //#region ../../node_modules/lodash/_baseIteratee.js
7993
8034
  var require__baseIteratee = __commonJS({ "../../node_modules/lodash/_baseIteratee.js"(exports, module) {
7994
- var baseMatches = require__baseMatches(), baseMatchesProperty = require__baseMatchesProperty(), identity$1 = require_identity(), isArray$4 = require_isArray(), property = require_property();
8035
+ var baseMatches = require__baseMatches(), baseMatchesProperty = require__baseMatchesProperty(), identity$1 = require_identity(), isArray$3 = require_isArray(), property = require_property();
7995
8036
  /**
7996
8037
  * The base implementation of `_.iteratee`.
7997
8038
  *
@@ -7999,13 +8040,13 @@ var require__baseIteratee = __commonJS({ "../../node_modules/lodash/_baseIterate
7999
8040
  * @param {*} [value=_.identity] The value to convert to an iteratee.
8000
8041
  * @returns {Function} Returns the iteratee.
8001
8042
  */
8002
- function baseIteratee$2(value) {
8043
+ function baseIteratee$1(value) {
8003
8044
  if (typeof value == "function") return value;
8004
8045
  if (value == null) return identity$1;
8005
- if (typeof value == "object") return isArray$4(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value);
8046
+ if (typeof value == "object") return isArray$3(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value);
8006
8047
  return property(value);
8007
8048
  }
8008
- module.exports = baseIteratee$2;
8049
+ module.exports = baseIteratee$1;
8009
8050
  } });
8010
8051
 
8011
8052
  //#endregion
@@ -8062,14 +8103,14 @@ var require__baseEach = __commonJS({ "../../node_modules/lodash/_baseEach.js"(ex
8062
8103
  * @param {Function} iteratee The function invoked per iteration.
8063
8104
  * @returns {Array|Object} Returns `collection`.
8064
8105
  */
8065
- var baseEach$2 = createBaseEach(baseForOwn);
8066
- module.exports = baseEach$2;
8106
+ var baseEach$1 = createBaseEach(baseForOwn);
8107
+ module.exports = baseEach$1;
8067
8108
  } });
8068
8109
 
8069
8110
  //#endregion
8070
8111
  //#region ../../node_modules/lodash/_baseMap.js
8071
8112
  var require__baseMap = __commonJS({ "../../node_modules/lodash/_baseMap.js"(exports, module) {
8072
- var baseEach$1 = require__baseEach(), isArrayLike = require_isArrayLike();
8113
+ var baseEach = require__baseEach(), isArrayLike = require_isArrayLike();
8073
8114
  /**
8074
8115
  * The base implementation of `_.map` without support for iteratee shorthands.
8075
8116
  *
@@ -8080,7 +8121,7 @@ var require__baseMap = __commonJS({ "../../node_modules/lodash/_baseMap.js"(expo
8080
8121
  */
8081
8122
  function baseMap$1(collection, iteratee) {
8082
8123
  var index = -1, result = isArrayLike(collection) ? Array(collection.length) : [];
8083
- baseEach$1(collection, function(value, key, collection$1) {
8124
+ baseEach(collection, function(value, key, collection$1) {
8084
8125
  result[++index] = iteratee(value, key, collection$1);
8085
8126
  });
8086
8127
  return result;
@@ -8170,7 +8211,7 @@ var require__compareMultiple = __commonJS({ "../../node_modules/lodash/_compareM
8170
8211
  //#endregion
8171
8212
  //#region ../../node_modules/lodash/_baseOrderBy.js
8172
8213
  var require__baseOrderBy = __commonJS({ "../../node_modules/lodash/_baseOrderBy.js"(exports, module) {
8173
- 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$3 = require_isArray();
8214
+ 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$2 = require_isArray();
8174
8215
  /**
8175
8216
  * The base implementation of `_.orderBy` without param guards.
8176
8217
  *
@@ -8182,14 +8223,14 @@ var require__baseOrderBy = __commonJS({ "../../node_modules/lodash/_baseOrderBy.
8182
8223
  */
8183
8224
  function baseOrderBy$1(collection, iteratees, orders) {
8184
8225
  if (iteratees.length) iteratees = arrayMap(iteratees, function(iteratee) {
8185
- if (isArray$3(iteratee)) return function(value) {
8226
+ if (isArray$2(iteratee)) return function(value) {
8186
8227
  return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
8187
8228
  };
8188
8229
  return iteratee;
8189
8230
  });
8190
8231
  else iteratees = [identity];
8191
8232
  var index = -1;
8192
- iteratees = arrayMap(iteratees, baseUnary(baseIteratee$1));
8233
+ iteratees = arrayMap(iteratees, baseUnary(baseIteratee));
8193
8234
  var result = baseMap(collection, function(value, key, collection$1) {
8194
8235
  var criteria = arrayMap(iteratees, function(iteratee) {
8195
8236
  return iteratee(value);
@@ -8210,7 +8251,7 @@ var require__baseOrderBy = __commonJS({ "../../node_modules/lodash/_baseOrderBy.
8210
8251
  //#endregion
8211
8252
  //#region ../../node_modules/lodash/orderBy.js
8212
8253
  var require_orderBy = __commonJS({ "../../node_modules/lodash/orderBy.js"(exports, module) {
8213
- var baseOrderBy = require__baseOrderBy(), isArray$2 = require_isArray();
8254
+ var baseOrderBy = require__baseOrderBy(), isArray$1 = require_isArray();
8214
8255
  /**
8215
8256
  * This method is like `_.sortBy` except that it allows specifying the sort
8216
8257
  * orders of the iteratees to sort by. If `orders` is unspecified, all values
@@ -8242,9 +8283,9 @@ var require_orderBy = __commonJS({ "../../node_modules/lodash/orderBy.js"(export
8242
8283
  */
8243
8284
  function orderBy(collection, iteratees, orders, guard) {
8244
8285
  if (collection == null) return [];
8245
- if (!isArray$2(iteratees)) iteratees = iteratees == null ? [] : [iteratees];
8286
+ if (!isArray$1(iteratees)) iteratees = iteratees == null ? [] : [iteratees];
8246
8287
  orders = guard ? void 0 : orders;
8247
- if (!isArray$2(orders)) orders = orders == null ? [] : [orders];
8288
+ if (!isArray$1(orders)) orders = orders == null ? [] : [orders];
8248
8289
  return baseOrderBy(collection, iteratees, orders);
8249
8290
  }
8250
8291
  module.exports = orderBy;
@@ -8323,8 +8364,7 @@ var WeaveGroupsManager = class {
8323
8364
  tr.hide();
8324
8365
  selectionPlugin.setSelectedNodes([]);
8325
8366
  }
8326
- let parentNodeId = parentId ?? WEAVE_NODE_LAYER_ID;
8327
- if (typeof parentNodeId === "undefined") parentNodeId = WEAVE_NODE_LAYER_ID;
8367
+ const parentNodeId = parentId ?? WEAVE_NODE_LAYER_ID;
8328
8368
  const parentLayer = stage.findOne(`#${parentNodeId}`);
8329
8369
  const groupId = v4_default();
8330
8370
  const groupInstance = new Konva.Group({
@@ -9453,7 +9493,7 @@ var WeaveRegisterManager = class {
9453
9493
 
9454
9494
  //#endregion
9455
9495
  //#region package.json
9456
- var version = "5.0.0-SNAPSHOT.342.1";
9496
+ var version = "5.0.0-SNAPSHOT.366.1";
9457
9497
 
9458
9498
  //#endregion
9459
9499
  //#region src/managers/setup.ts
@@ -9650,143 +9690,34 @@ var WeaveActionsManager = class {
9650
9690
  actionsHandlers[actionName].cleanup?.();
9651
9691
  this.instance.emitEvent("onActiveActionChange", this.activeAction);
9652
9692
  }
9653
- cancelActionCallback(actionName) {
9654
- return () => {
9655
- this.cancelAction(actionName);
9656
- };
9657
- }
9658
- };
9659
-
9660
- //#endregion
9661
- //#region src/managers/store.ts
9662
- var WeaveStoreManager = class {
9663
- constructor(instance) {
9664
- this.instance = instance;
9665
- this.logger = this.instance.getChildLogger("store-manager");
9666
- this.logger.debug("Store manager created");
9667
- }
9668
- getStore() {
9669
- return this.store;
9670
- }
9671
- registerStore(store) {
9672
- if (typeof this.store !== "undefined") {
9673
- const msg = `Store already registered`;
9674
- this.logger.error(msg);
9675
- throw new Error(msg);
9676
- }
9677
- const storeInstance = store.register(this.instance);
9678
- this.store = storeInstance;
9679
- }
9680
- };
9681
-
9682
- //#endregion
9683
- //#region ../../node_modules/lodash/_baseFilter.js
9684
- var require__baseFilter = __commonJS({ "../../node_modules/lodash/_baseFilter.js"(exports, module) {
9685
- var baseEach = require__baseEach();
9686
- /**
9687
- * The base implementation of `_.filter` without support for iteratee shorthands.
9688
- *
9689
- * @private
9690
- * @param {Array|Object} collection The collection to iterate over.
9691
- * @param {Function} predicate The function invoked per iteration.
9692
- * @returns {Array} Returns the new filtered array.
9693
- */
9694
- function baseFilter$1(collection, predicate) {
9695
- var result = [];
9696
- baseEach(collection, function(value, index, collection$1) {
9697
- if (predicate(value, index, collection$1)) result.push(value);
9698
- });
9699
- return result;
9700
- }
9701
- module.exports = baseFilter$1;
9702
- } });
9703
-
9704
- //#endregion
9705
- //#region ../../node_modules/lodash/negate.js
9706
- var require_negate = __commonJS({ "../../node_modules/lodash/negate.js"(exports, module) {
9707
- /** Error message constants. */
9708
- var FUNC_ERROR_TEXT = "Expected a function";
9709
- /**
9710
- * Creates a function that negates the result of the predicate `func`. The
9711
- * `func` predicate is invoked with the `this` binding and arguments of the
9712
- * created function.
9713
- *
9714
- * @static
9715
- * @memberOf _
9716
- * @since 3.0.0
9717
- * @category Function
9718
- * @param {Function} predicate The predicate to negate.
9719
- * @returns {Function} Returns the new negated function.
9720
- * @example
9721
- *
9722
- * function isEven(n) {
9723
- * return n % 2 == 0;
9724
- * }
9725
- *
9726
- * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
9727
- * // => [1, 3, 5]
9728
- */
9729
- function negate$1(predicate) {
9730
- if (typeof predicate != "function") throw new TypeError(FUNC_ERROR_TEXT);
9731
- return function() {
9732
- var args = arguments;
9733
- switch (args.length) {
9734
- case 0: return !predicate.call(this);
9735
- case 1: return !predicate.call(this, args[0]);
9736
- case 2: return !predicate.call(this, args[0], args[1]);
9737
- case 3: return !predicate.call(this, args[0], args[1], args[2]);
9738
- }
9739
- return !predicate.apply(this, args);
9740
- };
9741
- }
9742
- module.exports = negate$1;
9743
- } });
9744
-
9745
- //#endregion
9746
- //#region ../../node_modules/lodash/reject.js
9747
- var require_reject = __commonJS({ "../../node_modules/lodash/reject.js"(exports, module) {
9748
- var arrayFilter = require__arrayFilter(), baseFilter = require__baseFilter(), baseIteratee = require__baseIteratee(), isArray$1 = require_isArray(), negate = require_negate();
9749
- /**
9750
- * The opposite of `_.filter`; this method returns the elements of `collection`
9751
- * that `predicate` does **not** return truthy for.
9752
- *
9753
- * @static
9754
- * @memberOf _
9755
- * @since 0.1.0
9756
- * @category Collection
9757
- * @param {Array|Object} collection The collection to iterate over.
9758
- * @param {Function} [predicate=_.identity] The function invoked per iteration.
9759
- * @returns {Array} Returns the new filtered array.
9760
- * @see _.filter
9761
- * @example
9762
- *
9763
- * var users = [
9764
- * { 'user': 'barney', 'age': 36, 'active': false },
9765
- * { 'user': 'fred', 'age': 40, 'active': true }
9766
- * ];
9767
- *
9768
- * _.reject(users, function(o) { return !o.active; });
9769
- * // => objects for ['fred']
9770
- *
9771
- * // The `_.matches` iteratee shorthand.
9772
- * _.reject(users, { 'age': 40, 'active': true });
9773
- * // => objects for ['barney']
9774
- *
9775
- * // The `_.matchesProperty` iteratee shorthand.
9776
- * _.reject(users, ['active', false]);
9777
- * // => objects for ['fred']
9778
- *
9779
- * // The `_.property` iteratee shorthand.
9780
- * _.reject(users, 'active');
9781
- * // => objects for ['barney']
9782
- */
9783
- function reject(collection, predicate) {
9784
- var func = isArray$1(collection) ? arrayFilter : baseFilter;
9785
- return func(collection, negate(baseIteratee(predicate, 3)));
9786
- }
9787
- module.exports = reject;
9788
- } });
9789
- var import_reject = __toESM(require_reject(), 1);
9693
+ cancelActionCallback(actionName) {
9694
+ return () => {
9695
+ this.cancelAction(actionName);
9696
+ };
9697
+ }
9698
+ };
9699
+
9700
+ //#endregion
9701
+ //#region src/managers/store.ts
9702
+ var WeaveStoreManager = class {
9703
+ constructor(instance) {
9704
+ this.instance = instance;
9705
+ this.logger = this.instance.getChildLogger("store-manager");
9706
+ this.logger.debug("Store manager created");
9707
+ }
9708
+ getStore() {
9709
+ return this.store;
9710
+ }
9711
+ registerStore(store) {
9712
+ if (typeof this.store !== "undefined") {
9713
+ const msg = `Store already registered`;
9714
+ this.logger.error(msg);
9715
+ throw new Error(msg);
9716
+ }
9717
+ const storeInstance = store.register(this.instance);
9718
+ this.store = storeInstance;
9719
+ }
9720
+ };
9790
9721
 
9791
9722
  //#endregion
9792
9723
  //#region src/managers/export/export.ts
@@ -9796,6 +9727,155 @@ var WeaveExportManager = class {
9796
9727
  this.logger = this.instance.getChildLogger("export-manager");
9797
9728
  this.logger.debug("Export manager created");
9798
9729
  }
9730
+ parseExportOptions(options) {
9731
+ return {
9732
+ format: options.format ?? WEAVE_EXPORT_FORMATS.PNG,
9733
+ padding: options.padding ?? 0,
9734
+ pixelRatio: options.pixelRatio ?? 1,
9735
+ backgroundColor: options.backgroundColor ?? WEAVE_EXPORT_BACKGROUND_COLOR
9736
+ };
9737
+ }
9738
+ saveAndDisablePlugins() {
9739
+ const nodesSelectionPluginPrev = this.getNodesSelectionPlugin()?.isEnabled();
9740
+ const nodesStageGridPluginPrev = this.getStageGridPlugin()?.isEnabled();
9741
+ this.getNodesSelectionPlugin()?.disable();
9742
+ this.getStageGridPlugin()?.disable();
9743
+ return {
9744
+ nodesSelectionPluginPrev,
9745
+ nodesStageGridPluginPrev
9746
+ };
9747
+ }
9748
+ restorePlugins(nodesSelectionPluginPrev, nodesStageGridPluginPrev) {
9749
+ if (nodesSelectionPluginPrev) this.getNodesSelectionPlugin()?.enable();
9750
+ if (nodesStageGridPluginPrev) this.getStageGridPlugin()?.enable();
9751
+ }
9752
+ saveAndResetStage(resetPosition = false) {
9753
+ const stage = this.instance.getStage();
9754
+ const originalPosition = {
9755
+ x: stage.x(),
9756
+ y: stage.y()
9757
+ };
9758
+ const originalScale = {
9759
+ x: stage.scaleX(),
9760
+ y: stage.scaleY()
9761
+ };
9762
+ stage.scale({
9763
+ x: 1,
9764
+ y: 1
9765
+ });
9766
+ if (resetPosition) stage.position({
9767
+ x: 0,
9768
+ y: 0
9769
+ });
9770
+ return {
9771
+ stage,
9772
+ originalPosition,
9773
+ originalScale
9774
+ };
9775
+ }
9776
+ restoreStage(stage, originalPosition, originalScale) {
9777
+ stage.position(originalPosition);
9778
+ stage.scale(originalScale);
9779
+ stage.batchDraw();
9780
+ }
9781
+ buildNodesExportGroup(nodes, boundingNodes, stage, mainLayer, padding, backgroundColor) {
9782
+ const bounds = getExportBoundingBox(boundingNodes(nodes));
9783
+ const scaleX = stage.scaleX();
9784
+ const scaleY = stage.scaleY();
9785
+ const unscaledBounds = {
9786
+ x: bounds.x / scaleX,
9787
+ y: bounds.y / scaleY,
9788
+ width: bounds.width / scaleX,
9789
+ height: bounds.height / scaleY
9790
+ };
9791
+ const exportGroup = new Konva.Group();
9792
+ const background = new Konva.Rect({
9793
+ x: unscaledBounds.x - padding,
9794
+ y: unscaledBounds.y - padding,
9795
+ width: unscaledBounds.width + 2 * padding,
9796
+ height: unscaledBounds.height + 2 * padding,
9797
+ strokeWidth: 0,
9798
+ fill: backgroundColor
9799
+ });
9800
+ exportGroup.add(background);
9801
+ for (const node of nodes) {
9802
+ const clonedNode = node.clone({ id: v4_default() });
9803
+ const absPos = node.getAbsolutePosition();
9804
+ clonedNode.absolutePosition({
9805
+ x: absPos.x / scaleX,
9806
+ y: absPos.y / scaleY
9807
+ });
9808
+ exportGroup.add(clonedNode);
9809
+ }
9810
+ mainLayer.add(exportGroup);
9811
+ const backgroundRect = background.getClientRect();
9812
+ stage.batchDraw();
9813
+ return {
9814
+ exportGroup,
9815
+ background,
9816
+ backgroundRect
9817
+ };
9818
+ }
9819
+ buildAreaBackground(area, stage, mainLayer, padding, backgroundColor, relativeToStage = false) {
9820
+ const bounds = area;
9821
+ const scaleX = stage.scaleX();
9822
+ const scaleY = stage.scaleY();
9823
+ const unscaledBounds = {
9824
+ x: bounds.x / scaleX,
9825
+ y: bounds.y / scaleY,
9826
+ width: bounds.width / scaleX,
9827
+ height: bounds.height / scaleY
9828
+ };
9829
+ const background = new Konva.Rect({
9830
+ x: unscaledBounds.x - padding,
9831
+ y: unscaledBounds.y - padding,
9832
+ width: unscaledBounds.width + 2 * padding,
9833
+ height: unscaledBounds.height + 2 * padding,
9834
+ strokeWidth: 0,
9835
+ fill: backgroundColor
9836
+ });
9837
+ mainLayer.add(background);
9838
+ background.moveToBottom();
9839
+ stage.batchDraw();
9840
+ const backgroundRect = relativeToStage ? background.getClientRect({ relativeTo: stage }) : background.getClientRect();
9841
+ return {
9842
+ background,
9843
+ backgroundRect
9844
+ };
9845
+ }
9846
+ async renderTiles(source, backgroundRect, format, pixelRatio, quality) {
9847
+ const composites = [];
9848
+ const imageWidth = Math.round(backgroundRect.width);
9849
+ const imageHeight = Math.round(backgroundRect.height);
9850
+ const maxRenderSize = 1920;
9851
+ const cols = Math.ceil(imageWidth / maxRenderSize);
9852
+ const rows = Math.ceil(imageHeight / maxRenderSize);
9853
+ const tileWidth = Math.floor(imageWidth / cols);
9854
+ const tileHeight = Math.floor(imageHeight / rows);
9855
+ for (let y = 0; y < imageHeight; y += tileHeight) for (let x = 0; x < imageWidth; x += tileWidth) {
9856
+ const width = Math.min(tileWidth, imageWidth - x);
9857
+ const height = Math.min(tileHeight, imageHeight - y);
9858
+ const canvas = await source.toCanvas({
9859
+ x: Math.round(backgroundRect.x) + x,
9860
+ y: Math.round(backgroundRect.y) + y,
9861
+ width,
9862
+ height,
9863
+ mimeType: format,
9864
+ pixelRatio,
9865
+ quality
9866
+ });
9867
+ let buffer = null;
9868
+ if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.CANVAS) buffer = canvas.toBuffer();
9869
+ if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.SKIA) buffer = await canvas.toBuffer();
9870
+ if (!buffer) throw new Error("Failed to generate image buffer");
9871
+ composites.push({
9872
+ top: y * pixelRatio,
9873
+ left: x * pixelRatio,
9874
+ input: buffer
9875
+ });
9876
+ }
9877
+ return { composites };
9878
+ }
9799
9879
  fitKonvaPixelRatio(sw, sh, targetPR = 1, maxArea = 16777216) {
9800
9880
  if (sw <= 0 || sh <= 0) return {
9801
9881
  pixelRatio: 0,
@@ -9905,7 +9985,7 @@ var WeaveExportManager = class {
9905
9985
  });
9906
9986
  }
9907
9987
  exportNodesAsBlob(nodes, boundingNodes, options) {
9908
- return new Promise((resolve) => {
9988
+ return new Promise((resolve, reject) => {
9909
9989
  const { format = WEAVE_EXPORT_FORMATS.PNG } = options;
9910
9990
  const { stage, mainLayer, originalScale: { scaleX, scaleY } } = this.cloneStageForExport();
9911
9991
  if (mainLayer) {
@@ -9931,7 +10011,7 @@ var WeaveExportManager = class {
9931
10011
  exportGroup.destroy();
9932
10012
  stage.destroy();
9933
10013
  if (!blob) {
9934
- (0, import_reject.default)(new Error("Failed to generate image blob"));
10014
+ reject(new Error("Failed to generate image blob"));
9935
10015
  return;
9936
10016
  }
9937
10017
  resolve(blob);
@@ -10004,7 +10084,7 @@ var WeaveExportManager = class {
10004
10084
  });
10005
10085
  }
10006
10086
  exportAreaAsBlob(area, options) {
10007
- return new Promise((resolve) => {
10087
+ return new Promise((resolve, reject) => {
10008
10088
  const { format = WEAVE_EXPORT_FORMATS.PNG } = options;
10009
10089
  const { stage, mainLayer, originalScale: { scaleX, scaleY } } = this.cloneStageForExport();
10010
10090
  if (mainLayer) {
@@ -10029,7 +10109,7 @@ var WeaveExportManager = class {
10029
10109
  callback: (blob) => {
10030
10110
  stage.destroy();
10031
10111
  if (!blob) {
10032
- (0, import_reject.default)(new Error("Failed to generate image blob"));
10112
+ reject(new Error("Failed to generate image blob"));
10033
10113
  return;
10034
10114
  }
10035
10115
  resolve(blob);
@@ -10070,24 +10150,11 @@ var WeaveExportManager = class {
10070
10150
  });
10071
10151
  }
10072
10152
  async exportNodesServerSide(nodes, boundingNodes, options) {
10073
- const { format = WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = WEAVE_EXPORT_BACKGROUND_COLOR } = options;
10074
- this.getNodesSelectionPlugin()?.disable();
10075
- this.getStageGridPlugin()?.disable();
10076
- const stage = this.instance.getStage();
10153
+ const { format, padding, pixelRatio, backgroundColor } = this.parseExportOptions(options);
10154
+ const { nodesSelectionPluginPrev, nodesStageGridPluginPrev } = this.saveAndDisablePlugins();
10155
+ const { stage, originalPosition, originalScale } = this.saveAndResetStage();
10077
10156
  const mainLayer = this.instance.getMainLayer();
10078
10157
  if (!mainLayer) throw new Error("Main layer not found");
10079
- const originalPosition = {
10080
- x: stage.x(),
10081
- y: stage.y()
10082
- };
10083
- const originalScale = {
10084
- x: stage.scaleX(),
10085
- y: stage.scaleY()
10086
- };
10087
- stage.scale({
10088
- x: 1,
10089
- y: 1
10090
- });
10091
10158
  let realNodes = [...nodes];
10092
10159
  if (nodes.length === 0) realNodes = mainLayer.getChildren().map((node) => node.getAttrs().id ?? "") ?? [];
10093
10160
  const konvaNodes = [];
@@ -10095,153 +10162,32 @@ var WeaveExportManager = class {
10095
10162
  const node = stage.findOne(`#${nodeId}`);
10096
10163
  if (node) konvaNodes.push(node);
10097
10164
  }
10098
- const bounds = getExportBoundingBox(boundingNodes(konvaNodes));
10099
- const scaleX = stage.scaleX();
10100
- const scaleY = stage.scaleY();
10101
- const unscaledBounds = {
10102
- x: bounds.x / scaleX,
10103
- y: bounds.y / scaleY,
10104
- width: bounds.width / scaleX,
10105
- height: bounds.height / scaleY
10106
- };
10107
- const exportGroup = new Konva.Group();
10108
- const background = new Konva.Rect({
10109
- x: unscaledBounds.x - padding,
10110
- y: unscaledBounds.y - padding,
10111
- width: unscaledBounds.width + 2 * padding,
10112
- height: unscaledBounds.height + 2 * padding,
10113
- strokeWidth: 0,
10114
- fill: backgroundColor
10115
- });
10116
- exportGroup.add(background);
10117
- for (const node of konvaNodes) {
10118
- const clonedNode = node.clone({ id: v4_default() });
10119
- const absPos = node.getAbsolutePosition();
10120
- clonedNode.absolutePosition({
10121
- x: absPos.x / scaleX,
10122
- y: absPos.y / scaleY
10123
- });
10124
- exportGroup.add(clonedNode);
10125
- }
10126
- mainLayer.add(exportGroup);
10127
- const backgroundRect = background.getClientRect();
10128
- const composites = [];
10165
+ const { exportGroup, backgroundRect } = this.buildNodesExportGroup(konvaNodes, boundingNodes, stage, mainLayer, padding, backgroundColor);
10166
+ const { composites } = await this.renderTiles(exportGroup, backgroundRect, format, pixelRatio, options.quality ?? 1);
10129
10167
  const imageWidth = Math.round(backgroundRect.width);
10130
10168
  const imageHeight = Math.round(backgroundRect.height);
10131
- const maxRenderSize = 1920;
10132
- const cols = Math.ceil(imageWidth / maxRenderSize);
10133
- const rows = Math.ceil(imageHeight / maxRenderSize);
10134
- const tileWidth = Math.floor(imageWidth / cols);
10135
- const tileHeight = Math.floor(imageHeight / rows);
10136
- for (let y = 0; y < imageHeight; y += tileHeight) for (let x = 0; x < imageWidth; x += tileWidth) {
10137
- const width = Math.min(tileWidth, imageWidth - x);
10138
- const height = Math.min(tileHeight, imageHeight - y);
10139
- const canvas = await exportGroup.toCanvas({
10140
- x: Math.round(backgroundRect.x) + x,
10141
- y: Math.round(backgroundRect.y) + y,
10142
- width,
10143
- height,
10144
- mimeType: format,
10145
- pixelRatio,
10146
- quality: options.quality ?? 1
10147
- });
10148
- let buffer = null;
10149
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.CANVAS) buffer = canvas.toBuffer();
10150
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.SKIA) buffer = await canvas.toBuffer();
10151
- if (!buffer) throw new Error("Failed to generate image buffer");
10152
- composites.push({
10153
- top: y * pixelRatio,
10154
- left: x * pixelRatio,
10155
- input: buffer
10156
- });
10157
- }
10158
10169
  exportGroup.destroy();
10159
- stage.position(originalPosition);
10160
- stage.scale(originalScale);
10161
- stage.batchDraw();
10162
- this.getNodesSelectionPlugin()?.enable();
10163
- this.getStageGridPlugin()?.enable();
10164
- return {
10165
- composites,
10166
- width: imageWidth * pixelRatio,
10167
- height: imageHeight * pixelRatio
10168
- };
10169
- }
10170
- async exportAreaServerSide(area, options) {
10171
- const { format = WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = WEAVE_EXPORT_BACKGROUND_COLOR } = options;
10172
- this.getNodesSelectionPlugin()?.disable();
10173
- this.getStageGridPlugin()?.disable();
10174
- const stage = this.instance.getStage();
10175
- const mainLayer = this.instance.getMainLayer();
10176
- if (!mainLayer) throw new Error("Main layer not found");
10177
- const originalPosition = {
10178
- x: stage.x(),
10179
- y: stage.y()
10180
- };
10181
- const originalScale = {
10182
- x: stage.scaleX(),
10183
- y: stage.scaleY()
10184
- };
10185
- stage.scale({
10186
- x: 1,
10187
- y: 1
10188
- });
10189
- const bounds = area;
10190
- const scaleX = stage.scaleX();
10191
- const scaleY = stage.scaleY();
10192
- const unscaledBounds = {
10193
- x: bounds.x / scaleX,
10194
- y: bounds.y / scaleY,
10195
- width: bounds.width / scaleX,
10196
- height: bounds.height / scaleY
10170
+ this.restoreStage(stage, originalPosition, originalScale);
10171
+ this.restorePlugins(nodesSelectionPluginPrev, nodesStageGridPluginPrev);
10172
+ return {
10173
+ composites,
10174
+ width: imageWidth * pixelRatio,
10175
+ height: imageHeight * pixelRatio
10197
10176
  };
10198
- const background = new Konva.Rect({
10199
- x: unscaledBounds.x - padding,
10200
- y: unscaledBounds.y - padding,
10201
- width: unscaledBounds.width + 2 * padding,
10202
- height: unscaledBounds.height + 2 * padding,
10203
- strokeWidth: 0,
10204
- fill: backgroundColor
10205
- });
10206
- mainLayer.add(background);
10207
- background.moveToBottom();
10208
- const backgroundRect = background.getClientRect({ relativeTo: stage });
10209
- const composites = [];
10177
+ }
10178
+ async exportAreaServerSide(area, options) {
10179
+ const { format, padding, pixelRatio, backgroundColor } = this.parseExportOptions(options);
10180
+ const { nodesSelectionPluginPrev, nodesStageGridPluginPrev } = this.saveAndDisablePlugins();
10181
+ const { stage, originalPosition, originalScale } = this.saveAndResetStage();
10182
+ const mainLayer = this.instance.getMainLayer();
10183
+ if (!mainLayer) throw new Error("Main layer not found");
10184
+ const { background, backgroundRect } = this.buildAreaBackground(area, stage, mainLayer, padding, backgroundColor, true);
10185
+ const { composites } = await this.renderTiles(mainLayer, backgroundRect, format, pixelRatio, options.quality ?? 1);
10210
10186
  const imageWidth = Math.round(backgroundRect.width);
10211
10187
  const imageHeight = Math.round(backgroundRect.height);
10212
- const maxRenderSize = 1920;
10213
- const cols = Math.ceil(imageWidth / maxRenderSize);
10214
- const rows = Math.ceil(imageHeight / maxRenderSize);
10215
- const tileWidth = Math.floor(imageWidth / cols);
10216
- const tileHeight = Math.floor(imageHeight / rows);
10217
- for (let y = 0; y < imageHeight; y += tileHeight) for (let x = 0; x < imageWidth; x += tileWidth) {
10218
- const width = Math.min(tileWidth, imageWidth - x);
10219
- const height = Math.min(tileHeight, imageHeight - y);
10220
- const canvas = await mainLayer.toCanvas({
10221
- x: Math.round(backgroundRect.x) + x,
10222
- y: Math.round(backgroundRect.y) + y,
10223
- width,
10224
- height,
10225
- mimeType: format,
10226
- pixelRatio,
10227
- quality: options.quality ?? 1
10228
- });
10229
- let buffer = null;
10230
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.CANVAS) buffer = canvas.toBuffer();
10231
- if (globalThis._weave_serverSideBackend === WEAVE_KONVA_BACKEND.SKIA) buffer = await canvas.toBuffer();
10232
- if (!buffer) throw new Error("Failed to generate image buffer");
10233
- composites.push({
10234
- top: y * pixelRatio,
10235
- left: x * pixelRatio,
10236
- input: buffer
10237
- });
10238
- }
10239
10188
  background.destroy();
10240
- stage.position(originalPosition);
10241
- stage.scale(originalScale);
10242
- stage.batchDraw();
10243
- this.getNodesSelectionPlugin()?.enable();
10244
- this.getStageGridPlugin()?.enable();
10189
+ this.restoreStage(stage, originalPosition, originalScale);
10190
+ this.restorePlugins(nodesSelectionPluginPrev, nodesStageGridPluginPrev);
10245
10191
  return {
10246
10192
  composites,
10247
10193
  width: imageWidth * pixelRatio,
@@ -10269,10 +10215,10 @@ var WeaveExportManager = class {
10269
10215
  return gridPlugin;
10270
10216
  }
10271
10217
  blobToDataURL(blob) {
10272
- return new Promise((resolve, reject$1) => {
10218
+ return new Promise((resolve, reject) => {
10273
10219
  const reader = new FileReader();
10274
10220
  reader.onloadend = () => resolve(reader.result);
10275
- reader.onerror = () => reject$1(new Error("Failed to convert blob to data URL"));
10221
+ reader.onerror = () => reject(new Error("Failed to convert blob to data URL"));
10276
10222
  reader.readAsDataURL(blob);
10277
10223
  });
10278
10224
  }
@@ -11519,6 +11465,7 @@ var Weave = class {
11519
11465
  return this.dragAndDropManager.getDragProperties();
11520
11466
  }
11521
11467
  getEventsController() {
11468
+ if (!this.eventsController) throw new Error("Events controller not initialized");
11522
11469
  return this.eventsController;
11523
11470
  }
11524
11471
  getHooks() {
@@ -11537,14 +11484,14 @@ var Weave = class {
11537
11484
  //#endregion
11538
11485
  //#region src/utils/image.ts
11539
11486
  function loadImageSource(image, options) {
11540
- return new Promise((resolve, reject$1) => {
11487
+ return new Promise((resolve, reject) => {
11541
11488
  const { crossOrigin } = mergeExceptArrays({ crossOrigin: "anonymous" }, options);
11542
11489
  const reader = new FileReader();
11543
11490
  reader.onloadend = () => {
11544
11491
  const imageSource = Konva.Util.createImageElement();
11545
11492
  imageSource.crossOrigin = crossOrigin;
11546
11493
  imageSource.onerror = () => {
11547
- reject$1(new Error("Failed to load image source"));
11494
+ reject(new Error("Failed to load image source"));
11548
11495
  };
11549
11496
  imageSource.onload = async () => {
11550
11497
  resolve(imageSource);
@@ -11552,7 +11499,7 @@ function loadImageSource(image, options) {
11552
11499
  imageSource.src = reader.result;
11553
11500
  };
11554
11501
  reader.onerror = () => {
11555
- reject$1(new Error("Failed to read image file"));
11502
+ reject(new Error("Failed to read image file"));
11556
11503
  };
11557
11504
  reader.readAsDataURL(image);
11558
11505
  });
@@ -11573,12 +11520,12 @@ async function downscaleImageFile(file, ratio) {
11573
11520
  });
11574
11521
  }
11575
11522
  function getImageSizeFromFile(file) {
11576
- return new Promise((resolve, reject$1) => {
11523
+ return new Promise((resolve, reject) => {
11577
11524
  const img = new Image();
11578
11525
  const url = URL.createObjectURL(file);
11579
11526
  img.onload = () => {
11580
11527
  if (img.naturalWidth === 0) {
11581
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11528
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11582
11529
  return;
11583
11530
  }
11584
11531
  resolve({
@@ -11588,7 +11535,7 @@ function getImageSizeFromFile(file) {
11588
11535
  URL.revokeObjectURL(url);
11589
11536
  };
11590
11537
  img.onerror = () => {
11591
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11538
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11592
11539
  };
11593
11540
  img.src = url;
11594
11541
  });
@@ -11603,7 +11550,7 @@ function getDownscaleRatio(width, height, options) {
11603
11550
  return Math.min(widthRatio, heightRatio, 1);
11604
11551
  }
11605
11552
  const downscaleImageFromURL = (url, options) => {
11606
- return new Promise((resolve, reject$1) => {
11553
+ return new Promise((resolve, reject) => {
11607
11554
  const { type, crossOrigin, maxWidth, maxHeight } = mergeExceptArrays({
11608
11555
  type: "image/png",
11609
11556
  crossOrigin: "anonymous",
@@ -11614,7 +11561,7 @@ const downscaleImageFromURL = (url, options) => {
11614
11561
  img.crossOrigin = crossOrigin;
11615
11562
  img.onload = () => {
11616
11563
  if (img.naturalWidth === 0) {
11617
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11564
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11618
11565
  return;
11619
11566
  }
11620
11567
  const ratio = Math.min(maxWidth / img.width, maxHeight / img.height, 1);
@@ -11630,7 +11577,7 @@ const downscaleImageFromURL = (url, options) => {
11630
11577
  resolve(dataURL);
11631
11578
  };
11632
11579
  img.onerror = () => {
11633
- reject$1(new Error("Invalid image", { cause: "InvalidImage" }));
11580
+ reject(new Error("Invalid image", { cause: "InvalidImage" }));
11634
11581
  };
11635
11582
  img.src = url;
11636
11583
  });
@@ -11747,10 +11694,10 @@ var WeaveStageNode = class extends WeaveNode {
11747
11694
  container.setAttribute("tabindex", "0");
11748
11695
  stage.container().addEventListener("focus", () => {
11749
11696
  this.stageFocused = true;
11750
- }, { signal: this.instance.getEventsController()?.signal });
11697
+ }, { signal: this.instance.getEventsController().signal });
11751
11698
  stage.container().addEventListener("blur", () => {
11752
11699
  this.stageFocused = false;
11753
- }, { signal: this.instance.getEventsController()?.signal });
11700
+ }, { signal: this.instance.getEventsController().signal });
11754
11701
  }
11755
11702
  Konva.Stage.prototype.mode = function(mode) {
11756
11703
  if (typeof mode !== "undefined") this._mode = mode;
@@ -11817,7 +11764,7 @@ var WeaveStageNode = class extends WeaveNode {
11817
11764
  const selectedNode = transformer.nodes()[0];
11818
11765
  selectedNode.fire("onCmdCtrlPressed");
11819
11766
  }
11820
- }, { signal: this.instance.getEventsController()?.signal });
11767
+ }, { signal: this.instance.getEventsController().signal });
11821
11768
  window.addEventListener("keyup", (e) => {
11822
11769
  if (!(e.ctrlKey || e.metaKey)) {
11823
11770
  this.instance.getStage().container().style.cursor = "default";
@@ -11827,7 +11774,7 @@ var WeaveStageNode = class extends WeaveNode {
11827
11774
  const selectedNode = transformer.nodes()[0];
11828
11775
  selectedNode.fire("onCmdCtrlReleased");
11829
11776
  }
11830
- }, { signal: this.instance.getEventsController()?.signal });
11777
+ }, { signal: this.instance.getEventsController().signal });
11831
11778
  this.globalEventsInitialized = true;
11832
11779
  }
11833
11780
  isOnlyCtrlOrMeta(event) {
@@ -12839,7 +12786,7 @@ var WeaveTextNode = class extends WeaveNode {
12839
12786
  onAdd() {
12840
12787
  if (!this.instance.isServerSide() && !this.keyPressHandler) {
12841
12788
  this.keyPressHandler = this.handleKeyPress.bind(this);
12842
- window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController()?.signal });
12789
+ window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController().signal });
12843
12790
  }
12844
12791
  }
12845
12792
  onRender(props) {
@@ -12998,7 +12945,7 @@ var WeaveTextNode = class extends WeaveNode {
12998
12945
  });
12999
12946
  if (!this.instance.isServerSide() && !this.keyPressHandler) {
13000
12947
  this.keyPressHandler = this.handleKeyPress.bind(this);
13001
- window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController()?.signal });
12948
+ window.addEventListener("keypress", this.keyPressHandler, { signal: this.instance.getEventsController().signal });
13002
12949
  }
13003
12950
  return text;
13004
12951
  }
@@ -13246,17 +13193,17 @@ var WeaveTextNode = class extends WeaveNode {
13246
13193
  this.textAreaSuperContainer.scrollTop = 0;
13247
13194
  this.textAreaSuperContainer.scrollLeft = 0;
13248
13195
  }
13249
- }, { signal: this.instance.getEventsController()?.signal });
13196
+ }, { signal: this.instance.getEventsController().signal });
13250
13197
  this.textAreaContainer.addEventListener("scroll", () => {
13251
13198
  if (!this.textAreaContainer) return;
13252
13199
  this.textAreaContainer.scrollTop = 0;
13253
13200
  this.textAreaContainer.scrollLeft = 0;
13254
- }, { signal: this.instance.getEventsController()?.signal });
13201
+ }, { signal: this.instance.getEventsController().signal });
13255
13202
  this.textArea.addEventListener("scroll", () => {
13256
13203
  if (!this.textArea) return;
13257
13204
  this.textArea.scrollTop = 0;
13258
13205
  this.textArea.scrollLeft = 0;
13259
- }, { signal: this.instance.getEventsController()?.signal });
13206
+ }, { signal: this.instance.getEventsController().signal });
13260
13207
  const rotation = textNode.getAbsoluteRotation();
13261
13208
  if (rotation) {
13262
13209
  const transform = "rotate(" + rotation + "deg)";
@@ -13306,8 +13253,8 @@ var WeaveTextNode = class extends WeaveNode {
13306
13253
  this.textAreaDomResize(textNode);
13307
13254
  }
13308
13255
  };
13309
- this.textArea.addEventListener("keydown", handleKeyDown, { signal: this.instance.getEventsController()?.signal });
13310
- this.textArea.addEventListener("keyup", handleKeyUp, { signal: this.instance.getEventsController()?.signal });
13256
+ this.textArea.addEventListener("keydown", handleKeyDown, { signal: this.instance.getEventsController().signal });
13257
+ this.textArea.addEventListener("keyup", handleKeyUp, { signal: this.instance.getEventsController().signal });
13311
13258
  this.textArea.tabIndex = 1;
13312
13259
  this.textArea.focus();
13313
13260
  const handleOutsideClick = (e) => {
@@ -13333,7 +13280,7 @@ var WeaveTextNode = class extends WeaveNode {
13333
13280
  }
13334
13281
  };
13335
13282
  setTimeout(() => {
13336
- window.addEventListener("pointerup", handleOutsideClick, { signal: this.instance.getEventsController()?.signal });
13283
+ window.addEventListener("pointerup", handleOutsideClick, { signal: this.instance.getEventsController().signal });
13337
13284
  }, 0);
13338
13285
  this.instance.getStage().mode(WEAVE_STAGE_TEXT_EDITION_MODE);
13339
13286
  this.editing = true;
@@ -13793,7 +13740,7 @@ var WeaveImageCrop = class WeaveImageCrop {
13793
13740
  utilityLayer?.add(this.transformer);
13794
13741
  this.transformer?.forceUpdate();
13795
13742
  this.cropGroup.show();
13796
- window.addEventListener("keydown", this.handleHide, { signal: this.instance.getEventsController()?.signal });
13743
+ if (!this.instance.isServerSide()) window.addEventListener("keydown", this.handleHide, { signal: this.instance.getEventsController().signal });
13797
13744
  if (options.cmdCtrl.triggered) {
13798
13745
  utilityLayer?.hide();
13799
13746
  const stage = this.instance.getStage();
@@ -16895,10 +16842,10 @@ var WeaveStrokeSingleNode = class extends WeaveNode {
16895
16842
  if (this.eventsInitialized) return;
16896
16843
  window.addEventListener("keydown", (e) => {
16897
16844
  if (e.key === "Shift") this.shiftPressed = true;
16898
- }, { signal: this.instance.getEventsController()?.signal });
16845
+ }, { signal: this.instance.getEventsController().signal });
16899
16846
  window.addEventListener("keyup", (e) => {
16900
16847
  if (e.key === "Shift") this.shiftPressed = false;
16901
- }, { signal: this.instance.getEventsController()?.signal });
16848
+ }, { signal: this.instance.getEventsController().signal });
16902
16849
  this.eventsInitialized = true;
16903
16850
  }
16904
16851
  onRender(props) {
@@ -20985,7 +20932,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
20985
20932
  }
20986
20933
  }, {
20987
20934
  passive: false,
20988
- signal: this.instance.getEventsController()?.signal
20935
+ signal: this.instance.getEventsController().signal
20989
20936
  });
20990
20937
  stage.getContent().addEventListener("touchmove", (e) => {
20991
20938
  e.preventDefault();
@@ -21028,7 +20975,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21028
20975
  }
21029
20976
  }, {
21030
20977
  passive: false,
21031
- signal: this.instance.getEventsController()?.signal
20978
+ signal: this.instance.getEventsController().signal
21032
20979
  });
21033
20980
  stage.getContent().addEventListener("touchend", () => {
21034
20981
  this.pinching = false;
@@ -21036,7 +20983,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21036
20983
  lastCenter = null;
21037
20984
  }, {
21038
20985
  passive: false,
21039
- signal: this.instance.getEventsController()?.signal
20986
+ signal: this.instance.getEventsController().signal
21040
20987
  });
21041
20988
  let doZoom = false;
21042
20989
  const handleWheelImmediate = (e) => {
@@ -21057,7 +21004,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21057
21004
  doZoom = true;
21058
21005
  };
21059
21006
  window.addEventListener("wheel", handleWheelImmediate, {
21060
- signal: this.instance.getEventsController()?.signal,
21007
+ signal: this.instance.getEventsController().signal,
21061
21008
  passive: false
21062
21009
  });
21063
21010
  const handleWheel = (e) => {
@@ -21073,7 +21020,7 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21073
21020
  };
21074
21021
  const throttledHandleWheel = (0, import_throttle.default)(handleWheel, DEFAULT_THROTTLE_MS);
21075
21022
  window.addEventListener("wheel", throttledHandleWheel, {
21076
- signal: this.instance.getEventsController()?.signal,
21023
+ signal: this.instance.getEventsController().signal,
21077
21024
  passive: true
21078
21025
  });
21079
21026
  }
@@ -21301,7 +21248,7 @@ var WeaveMoveToolAction = class extends WeaveAction {
21301
21248
  this.cancelAction();
21302
21249
  return;
21303
21250
  }
21304
- }, { signal: this.instance.getEventsController()?.signal });
21251
+ }, { signal: this.instance.getEventsController().signal });
21305
21252
  stage.on("pointerdown", () => {
21306
21253
  if ([MOVE_TOOL_ACTION_NAME].includes(this.instance.getActiveAction() ?? "")) stage.container().style.cursor = "grabbing";
21307
21254
  });
@@ -21462,7 +21409,7 @@ var WeaveEraserToolAction = class extends WeaveAction {
21462
21409
  this.cancelAction();
21463
21410
  return;
21464
21411
  }
21465
- }, { signal: this.instance.getEventsController()?.signal });
21412
+ }, { signal: this.instance.getEventsController().signal });
21466
21413
  this.initialized = true;
21467
21414
  }
21468
21415
  setState(state) {
@@ -21567,7 +21514,7 @@ var WeaveRectangleToolAction = class extends WeaveAction {
21567
21514
  this.cancelAction();
21568
21515
  return;
21569
21516
  }
21570
- }, { signal: this.instance.getEventsController()?.signal });
21517
+ }, { signal: this.instance.getEventsController().signal });
21571
21518
  stage.on("pointermove", () => {
21572
21519
  if (this.state === RECTANGLE_TOOL_STATE.IDLE) return;
21573
21520
  this.setCursor();
@@ -21788,7 +21735,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
21788
21735
  this.cancelAction();
21789
21736
  return;
21790
21737
  }
21791
- }, { signal: this.instance.getEventsController()?.signal });
21738
+ }, { signal: this.instance.getEventsController().signal });
21792
21739
  stage.on("pointerdown", (e) => {
21793
21740
  this.setTapStart(e);
21794
21741
  this.pointers.set(e.evt.pointerId, {
@@ -22007,7 +21954,7 @@ var WeavePenToolAction = class extends WeaveAction {
22007
21954
  this.cancelAction();
22008
21955
  return;
22009
21956
  }
22010
- }, { signal: this.instance.getEventsController()?.signal });
21957
+ }, { signal: this.instance.getEventsController().signal });
22011
21958
  stage.on("pointerdown", (e) => {
22012
21959
  this.setTapStart(e);
22013
21960
  this.pointers.set(e.evt.pointerId, {
@@ -22291,13 +22238,13 @@ var WeaveLineToolAction = class extends WeaveAction {
22291
22238
  this.snappedAngle = null;
22292
22239
  this.shiftPressed = true;
22293
22240
  }
22294
- }, { signal: this.instance.getEventsController()?.signal });
22241
+ }, { signal: this.instance.getEventsController().signal });
22295
22242
  window.addEventListener("keyup", (e) => {
22296
22243
  if (e.key === "Shift" && this.instance.getActiveAction() === LINE_TOOL_ACTION_NAME) {
22297
22244
  this.snappedAngle = null;
22298
22245
  this.shiftPressed = false;
22299
22246
  }
22300
- }, { signal: this.instance.getEventsController()?.signal });
22247
+ }, { signal: this.instance.getEventsController().signal });
22301
22248
  stage.on("pointerdown", (e) => {
22302
22249
  this.setTapStart(e);
22303
22250
  this.pointers.set(e.evt.pointerId, {
@@ -22566,7 +22513,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
22566
22513
  stage.container().style.touchAction = "none";
22567
22514
  window.addEventListener("keyup", (e) => {
22568
22515
  if (e.code === "Space" && this.instance.getActiveAction() === BRUSH_TOOL_ACTION_NAME) this.isSpacePressed = false;
22569
- }, { signal: this.instance.getEventsController()?.signal });
22516
+ }, { signal: this.instance.getEventsController().signal });
22570
22517
  window.addEventListener("keydown", (e) => {
22571
22518
  if (e.code === "Enter" && this.instance.getActiveAction() === BRUSH_TOOL_ACTION_NAME) {
22572
22519
  e.stopPropagation();
@@ -22582,8 +22529,8 @@ var WeaveBrushToolAction = class extends WeaveAction {
22582
22529
  e.stopPropagation();
22583
22530
  this.cancelAction();
22584
22531
  }
22585
- }, { signal: this.instance.getEventsController()?.signal });
22586
- const handlePointerDown = (e) => {
22532
+ }, { signal: this.instance.getEventsController().signal });
22533
+ const handlePointerDown$1 = (e) => {
22587
22534
  if (this.state === BRUSH_TOOL_STATE.INACTIVE) return;
22588
22535
  if (this.state !== BRUSH_TOOL_STATE.IDLE) return;
22589
22536
  if (this.getZoomPlugin()?.isPinching()) return;
@@ -22595,8 +22542,8 @@ var WeaveBrushToolAction = class extends WeaveAction {
22595
22542
  this.handleStartStroke(pointPressure);
22596
22543
  e.evt.stopPropagation();
22597
22544
  };
22598
- stage.on("pointerdown", handlePointerDown);
22599
- const handlePointerMove = (e) => {
22545
+ stage.on("pointerdown", handlePointerDown$1);
22546
+ const handlePointerMove$1 = (e) => {
22600
22547
  if (this.state === BRUSH_TOOL_STATE.INACTIVE) return;
22601
22548
  this.setCursor();
22602
22549
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
@@ -22619,15 +22566,15 @@ var WeaveBrushToolAction = class extends WeaveAction {
22619
22566
  }
22620
22567
  e.evt.stopPropagation();
22621
22568
  };
22622
- stage.on("pointermove", handlePointerMove);
22623
- const handlePointerUp = (e) => {
22569
+ stage.on("pointermove", handlePointerMove$1);
22570
+ const handlePointerUp$1 = (e) => {
22624
22571
  this.penActive = false;
22625
22572
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
22626
22573
  if (this.getZoomPlugin()?.isPinching()) return;
22627
22574
  this.handleEndStroke();
22628
22575
  e.evt.stopPropagation();
22629
22576
  };
22630
- stage.on("pointerup", handlePointerUp);
22577
+ stage.on("pointerup", handlePointerUp$1);
22631
22578
  this.initialized = true;
22632
22579
  }
22633
22580
  setState(state) {
@@ -22859,7 +22806,7 @@ var WeaveTextToolAction = class extends WeaveAction {
22859
22806
  this.cancelAction();
22860
22807
  return;
22861
22808
  }
22862
- }, { signal: this.instance.getEventsController()?.signal });
22809
+ }, { signal: this.instance.getEventsController().signal });
22863
22810
  stage.on("pointermove", () => {
22864
22811
  if (this.state === TEXT_TOOL_STATE.IDLE) return;
22865
22812
  this.setCursor();
@@ -23035,7 +22982,7 @@ var WeaveImageToolAction = class extends WeaveAction {
23035
22982
  this.cancelAction();
23036
22983
  return;
23037
22984
  }
23038
- }, { signal: this.instance.getEventsController()?.signal });
22985
+ }, { signal: this.instance.getEventsController().signal });
23039
22986
  stage.on("pointerdown", (e) => {
23040
22987
  this.setTapStart(e);
23041
22988
  if (this.ignorePointerEvents) return;
@@ -23358,10 +23305,10 @@ var WeaveImageToolAction = class extends WeaveAction {
23358
23305
  return this.state;
23359
23306
  }
23360
23307
  loadImageDataURL(imageDataURL) {
23361
- return new Promise((resolve, reject$1) => {
23308
+ return new Promise((resolve, reject) => {
23362
23309
  const imageEle = Konva.Util.createImageElement();
23363
23310
  imageEle.onerror = (error) => {
23364
- reject$1(error);
23311
+ reject(error);
23365
23312
  };
23366
23313
  imageEle.onload = async () => {
23367
23314
  resolve(imageEle);
@@ -23370,13 +23317,13 @@ var WeaveImageToolAction = class extends WeaveAction {
23370
23317
  });
23371
23318
  }
23372
23319
  getDataURL(blob) {
23373
- return new Promise((resolve, reject$1) => {
23320
+ return new Promise((resolve, reject) => {
23374
23321
  const reader = new FileReader();
23375
23322
  reader.onloadend = () => {
23376
23323
  resolve(reader.result);
23377
23324
  };
23378
23325
  reader.onerror = () => {
23379
- reject$1(new Error("Failed to generate dataURL from file"));
23326
+ reject(new Error("Failed to generate dataURL from file"));
23380
23327
  };
23381
23328
  reader.readAsDataURL(blob);
23382
23329
  });
@@ -23495,7 +23442,7 @@ var WeaveImagesToolAction = class extends WeaveAction {
23495
23442
  const stage = this.instance.getStage();
23496
23443
  stage.container().addEventListener("keydown", (e) => {
23497
23444
  if (e.key === "Escape" && this.instance.getActiveAction() === WEAVE_IMAGES_TOOL_ACTION_NAME) this.cancelAction();
23498
- }, { signal: this.instance.getEventsController()?.signal });
23445
+ }, { signal: this.instance.getEventsController().signal });
23499
23446
  stage.on("pointerdown", (e) => {
23500
23447
  this.setTapStart(e);
23501
23448
  this.pointers.set(e.evt.pointerId, {
@@ -23913,7 +23860,7 @@ var WeaveStarToolAction = class extends WeaveAction {
23913
23860
  this.cancelAction();
23914
23861
  return;
23915
23862
  }
23916
- }, { signal: this.instance.getEventsController()?.signal });
23863
+ }, { signal: this.instance.getEventsController().signal });
23917
23864
  stage.on("pointerdown", (e) => {
23918
23865
  this.setTapStart(e);
23919
23866
  this.pointers.set(e.evt.pointerId, {
@@ -24136,7 +24083,7 @@ var WeaveArrowToolAction = class extends WeaveAction {
24136
24083
  return;
24137
24084
  }
24138
24085
  if (e.code === "Escape" && this.instance.getActiveAction() === WEAVE_ARROW_TOOL_ACTION_NAME) this.cancelAction();
24139
- }, { signal: this.instance.getEventsController()?.signal });
24086
+ }, { signal: this.instance.getEventsController().signal });
24140
24087
  stage.on("pointerdown", (e) => {
24141
24088
  this.setTapStart(e);
24142
24089
  this.pointers.set(e.evt.pointerId, {
@@ -24427,10 +24374,10 @@ var WeaveStrokeToolAction = class extends WeaveAction {
24427
24374
  return;
24428
24375
  }
24429
24376
  if (e.key === "Shift" && this.getNames().includes(this.instance.getActiveAction() ?? "")) this.shiftPressed = true;
24430
- }, { signal: this.instance.getEventsController()?.signal });
24377
+ }, { signal: this.instance.getEventsController().signal });
24431
24378
  window.addEventListener("keyup", (e) => {
24432
24379
  if (e.key === "Shift" && this.getNames().includes(this.instance.getActiveAction() ?? "")) this.shiftPressed = false;
24433
- }, { signal: this.instance.getEventsController()?.signal });
24380
+ }, { signal: this.instance.getEventsController().signal });
24434
24381
  stage.on("pointerdown", (e) => {
24435
24382
  this.setTapStart(e);
24436
24383
  this.pointers.set(e.evt.pointerId, {
@@ -24660,7 +24607,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
24660
24607
  this.cancelAction();
24661
24608
  return;
24662
24609
  }
24663
- }, { signal: this.instance.getEventsController()?.signal });
24610
+ }, { signal: this.instance.getEventsController().signal });
24664
24611
  stage.on("pointerdown", (e) => {
24665
24612
  this.setTapStart(e);
24666
24613
  this.pointers.set(e.evt.pointerId, {
@@ -24864,7 +24811,7 @@ var WeaveFrameToolAction = class extends WeaveAction {
24864
24811
  this.cancelAction();
24865
24812
  return;
24866
24813
  }
24867
- }, { signal: this.instance.getEventsController()?.signal });
24814
+ }, { signal: this.instance.getEventsController().signal });
24868
24815
  stage.on("pointermove", () => {
24869
24816
  if (this.state === FRAME_TOOL_STATE.IDLE) return;
24870
24817
  this.setCursor();
@@ -25405,7 +25352,7 @@ var WeaveCommentToolAction = class extends WeaveAction {
25405
25352
  return;
25406
25353
  }
25407
25354
  if (e.code === "Escape" && this.state === WEAVE_COMMENT_TOOL_STATE.CREATING_COMMENT) this.setState(WEAVE_COMMENT_TOOL_STATE.ADDING);
25408
- }, { signal: this.instance.getEventsController()?.signal });
25355
+ }, { signal: this.instance.getEventsController().signal });
25409
25356
  stage.on("pointermove", (e) => {
25410
25357
  if (this.state === WEAVE_COMMENT_TOOL_STATE.IDLE) return;
25411
25358
  if (commentNodeHandler?.isCommentViewing()) {
@@ -25607,7 +25554,7 @@ var WeaveVideoToolAction = class extends WeaveAction {
25607
25554
  this.cancelAction();
25608
25555
  return;
25609
25556
  }
25610
- }, { signal: this.instance.getEventsController()?.signal });
25557
+ }, { signal: this.instance.getEventsController().signal });
25611
25558
  stage.on("pointerdown", (e) => {
25612
25559
  this.setTapStart(e);
25613
25560
  this.pointers.set(e.evt.pointerId, {
@@ -25770,7 +25717,7 @@ var WeaveMeasureToolAction = class extends WeaveAction {
25770
25717
  const stage = this.instance.getStage();
25771
25718
  window.addEventListener("keydown", (e) => {
25772
25719
  if (e.code === "Escape" && this.instance.getActiveAction() === MEASURE_TOOL_ACTION_NAME) this.cancelAction();
25773
- }, { signal: this.instance.getEventsController()?.signal });
25720
+ }, { signal: this.instance.getEventsController().signal });
25774
25721
  stage.on("pointermove", () => {
25775
25722
  if (this.state === MEASURE_TOOL_STATE.IDLE) return;
25776
25723
  if (this.state === MEASURE_TOOL_STATE.SET_TO) {
@@ -26081,7 +26028,7 @@ var WeaveConnectorToolAction = class extends WeaveAction {
26081
26028
  return;
26082
26029
  }
26083
26030
  if (e.code === "Escape" && this.instance.getActiveAction() === CONNECTOR_TOOL_ACTION_NAME) this.cancelAction();
26084
- }, { signal: this.instance.getEventsController()?.signal });
26031
+ }, { signal: this.instance.getEventsController().signal });
26085
26032
  let nodeHovered = void 0;
26086
26033
  stage.on("pointermove", () => {
26087
26034
  if (!(this.state === CONNECTOR_TOOL_STATE.SELECTING_INITIAL || this.state === CONNECTOR_TOOL_STATE.SELECTING_FINAL)) return;
@@ -26897,7 +26844,7 @@ var WeaveGuideToolAction = class extends WeaveAction {
26897
26844
  window.addEventListener("keyup", (e) => {
26898
26845
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
26899
26846
  if (isOptionAltPressed) this.guideDistanceToTargetInfo.cleanup();
26900
- }, { signal: this.instance.getEventsController()?.signal });
26847
+ }, { signal: this.instance.getEventsController().signal });
26901
26848
  window.addEventListener("keydown", (e) => {
26902
26849
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
26903
26850
  if (isOptionAltPressed && this.instance.getActiveAction() === GUIDE_TOOL_ACTION_NAME && this.state === GUIDE_TOOL_STATE.ADDING) this.moveGuide(true);
@@ -26917,7 +26864,7 @@ var WeaveGuideToolAction = class extends WeaveAction {
26917
26864
  this.cancelAction();
26918
26865
  }
26919
26866
  }
26920
- }, { signal: this.instance.getEventsController()?.signal });
26867
+ }, { signal: this.instance.getEventsController().signal });
26921
26868
  stage.on("pointermove", (e) => {
26922
26869
  if (this.state === GUIDE_TOOL_STATE.IDLE) return;
26923
26870
  this.setCursor();
@@ -27189,10 +27136,10 @@ var WeaveStageGridPlugin = class extends WeavePlugin {
27189
27136
  const stage = this.instance.getStage();
27190
27137
  window.addEventListener("keydown", (e) => {
27191
27138
  if (e.code === "Space") this.isSpaceKeyPressed = true;
27192
- }, { signal: this.instance.getEventsController()?.signal });
27139
+ }, { signal: this.instance.getEventsController().signal });
27193
27140
  window.addEventListener("keyup", (e) => {
27194
27141
  if (e.code === "Space") this.isSpaceKeyPressed = false;
27195
- }, { signal: this.instance.getEventsController()?.signal });
27142
+ }, { signal: this.instance.getEventsController().signal });
27196
27143
  this.instance.addEventListener("onStageMove", () => {
27197
27144
  this.onRender();
27198
27145
  });
@@ -27509,7 +27456,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27509
27456
  this.isSpaceKeyPressed = true;
27510
27457
  this.setCursor();
27511
27458
  }
27512
- }, { signal: this.instance.getEventsController()?.signal });
27459
+ }, { signal: this.instance.getEventsController().signal });
27513
27460
  window.addEventListener("keyup", (e) => {
27514
27461
  if (e.code === "Space") {
27515
27462
  this.getContextMenuPlugin()?.enable();
@@ -27517,7 +27464,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27517
27464
  this.isSpaceKeyPressed = false;
27518
27465
  this.disableMove();
27519
27466
  }
27520
- }, { signal: this.instance.getEventsController()?.signal });
27467
+ }, { signal: this.instance.getEventsController().signal });
27521
27468
  let lastPos = null;
27522
27469
  stage.on("pointerdown", (e) => {
27523
27470
  this.pointers.set(e.evt.pointerId, {
@@ -27593,7 +27540,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27593
27540
  const handleWheelThrottled = (0, import_throttle.default)(handleWheel, WEAVE_STAGE_PANNING_THROTTLE_MS);
27594
27541
  window.addEventListener("wheel", handleWheelThrottled, {
27595
27542
  passive: true,
27596
- signal: this.instance.getEventsController()?.signal
27543
+ signal: this.instance.getEventsController().signal
27597
27544
  });
27598
27545
  stage.on("dragstart", (e) => {
27599
27546
  const duration = 1e3 / 60;
@@ -27645,7 +27592,7 @@ var WeaveStagePanningPlugin = class extends WeavePlugin {
27645
27592
  e.preventDefault();
27646
27593
  }, {
27647
27594
  passive: false,
27648
- signal: this.instance.getEventsController()?.signal
27595
+ signal: this.instance.getEventsController().signal
27649
27596
  });
27650
27597
  }
27651
27598
  isPanning() {
@@ -27931,7 +27878,7 @@ var WeaveStageResizePlugin = class extends WeavePlugin {
27931
27878
  }, DEFAULT_THROTTLE_MS);
27932
27879
  window.addEventListener("resize", () => {
27933
27880
  throttledResize();
27934
- }, { signal: this.instance.getEventsController()?.signal });
27881
+ }, { signal: this.instance.getEventsController().signal });
27935
27882
  const resizeObserver = new ResizeObserver(() => {
27936
27883
  throttledResize();
27937
27884
  });
@@ -28655,6 +28602,215 @@ var WeaveUsersPresencePlugin = class extends WeavePlugin {
28655
28602
  }
28656
28603
  };
28657
28604
 
28605
+ //#endregion
28606
+ //#region src/plugins/context-menu/context-menu.ts
28607
+ var WeaveContextMenuPlugin = class extends WeavePlugin {
28608
+ getLayerName = void 0;
28609
+ initLayer = void 0;
28610
+ constructor(params) {
28611
+ super();
28612
+ const { config } = params ?? {};
28613
+ this.config = {
28614
+ xOffset: WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT,
28615
+ yOffset: WEAVE_CONTEXT_MENU_Y_OFFSET_DEFAULT,
28616
+ ...config
28617
+ };
28618
+ this.initialize();
28619
+ }
28620
+ initialize() {
28621
+ this.timer = null;
28622
+ this.tapHold = false;
28623
+ this.contextMenuVisible = false;
28624
+ this.tapStart = {
28625
+ x: 0,
28626
+ y: 0,
28627
+ time: 0
28628
+ };
28629
+ this.tapHoldTimeout = WEAVE_CONTEXT_MENU_TAP_HOLD_TIMEOUT;
28630
+ this.pointers = {};
28631
+ }
28632
+ getName() {
28633
+ return WEAVE_CONTEXT_MENU_PLUGIN_KEY;
28634
+ }
28635
+ onInit() {
28636
+ this.initEvents();
28637
+ }
28638
+ isPressed(e) {
28639
+ return e.evt.buttons > 0;
28640
+ }
28641
+ setTapStart(e) {
28642
+ this.tapStart = {
28643
+ x: e.evt.clientX,
28644
+ y: e.evt.clientY,
28645
+ time: performance.now()
28646
+ };
28647
+ }
28648
+ triggerContextMenu(eventTarget, target) {
28649
+ const stage = this.instance.getStage();
28650
+ const selectionPlugin = this.getSelectionPlugin();
28651
+ let nodes = [];
28652
+ if (target && target !== stage) {
28653
+ const nodeHandler = this.instance.getNodeHandler(target.getAttrs().nodeType);
28654
+ nodes = [{
28655
+ instance: target,
28656
+ node: nodeHandler?.serialize(target)
28657
+ }];
28658
+ }
28659
+ const eventTargetParent = eventTarget.getParent();
28660
+ if (eventTargetParent instanceof Konva.Transformer) nodes = eventTargetParent.nodes().map((node) => {
28661
+ const nodeHandler = this.instance.getNodeHandler(node.getAttrs().nodeType);
28662
+ return {
28663
+ instance: node,
28664
+ node: nodeHandler?.serialize(node)
28665
+ };
28666
+ });
28667
+ if (this.contextMenuVisible) this.closeContextMenu();
28668
+ let allNodesMutexUnlocked = true;
28669
+ let allNodesUnlocked = true;
28670
+ const actUser = this.instance.getStore().getUser();
28671
+ for (const node of nodes) {
28672
+ const locked = node.instance.getAttrs().locked;
28673
+ const mutexInfo = this.instance.getNodeMutexLock(node.node?.key ?? "");
28674
+ if (locked) {
28675
+ allNodesUnlocked = false;
28676
+ break;
28677
+ }
28678
+ if (mutexInfo && mutexInfo.user.id !== actUser.id) {
28679
+ allNodesMutexUnlocked = false;
28680
+ break;
28681
+ }
28682
+ }
28683
+ if (!allNodesMutexUnlocked || !allNodesUnlocked) return;
28684
+ if (selectionPlugin && !(eventTarget.getParent() instanceof Konva.Transformer && selectionPlugin.getSelectedNodes().length > 0)) {
28685
+ selectionPlugin.setSelectedNodes([...nodes.map((node) => node.instance)]);
28686
+ selectionPlugin.getHoverTransformer().nodes([]);
28687
+ }
28688
+ const containerRect = stage.container().getBoundingClientRect();
28689
+ const pointerPos = stage.getPointerPosition();
28690
+ const relativeClickPoint = stage.getRelativePointerPosition();
28691
+ if (containerRect && pointerPos && relativeClickPoint && allNodesUnlocked) {
28692
+ const contextMenuPoint = {
28693
+ x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
28694
+ y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
28695
+ };
28696
+ const stageClickPoint = this.getStageClickPoint(pointerPos);
28697
+ this.contextMenuVisible = true;
28698
+ this.instance.emitEvent("onNodeContextMenu", {
28699
+ selection: nodes,
28700
+ contextMenuPoint,
28701
+ clickPoint: pointerPos,
28702
+ stageClickPoint,
28703
+ visible: true
28704
+ });
28705
+ }
28706
+ }
28707
+ closeContextMenu() {
28708
+ this.contextMenuVisible = false;
28709
+ this.instance.emitEvent("onNodeContextMenu", {
28710
+ selection: [],
28711
+ contextMenuPoint: {
28712
+ x: 0,
28713
+ y: 0
28714
+ },
28715
+ clickPoint: {
28716
+ x: 0,
28717
+ y: 0
28718
+ },
28719
+ stageClickPoint: {
28720
+ x: 0,
28721
+ y: 0
28722
+ },
28723
+ visible: false
28724
+ });
28725
+ }
28726
+ getSelectionPlugin() {
28727
+ const selectionPlugin = this.instance.getPlugin(WEAVE_NODES_SELECTION_KEY);
28728
+ return selectionPlugin;
28729
+ }
28730
+ cancelLongPressTimer() {
28731
+ if (this.timer) {
28732
+ clearTimeout(this.timer);
28733
+ this.timer = null;
28734
+ }
28735
+ }
28736
+ initEvents() {
28737
+ const stage = this.instance.getStage();
28738
+ stage.on("pointerdown", (e) => {
28739
+ this.setTapStart(e);
28740
+ this.pointers[e.evt.pointerId] = e.evt;
28741
+ if (e.evt.buttons === 0) return;
28742
+ if (e.evt.pointerType === "mouse") return;
28743
+ if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length > 1) return;
28744
+ if (this.timer) return;
28745
+ this.timer = setTimeout(() => {
28746
+ this.tapHold = true;
28747
+ const actualActions = this.instance.getActiveAction();
28748
+ if (actualActions !== SELECTION_TOOL_ACTION_NAME) return;
28749
+ delete this.pointers[e.evt.pointerId];
28750
+ const selectedGroup = getTargetedNode(this.instance);
28751
+ this.triggerContextMenu(e.target, selectedGroup);
28752
+ }, this.tapHoldTimeout);
28753
+ });
28754
+ stage.on("pointerup", (e) => {
28755
+ delete this.pointers[e.evt.pointerId];
28756
+ if (e.evt.pointerType === "mouse") return;
28757
+ if (e.evt.pointerType === "touch" && Object.keys(this.pointers).length + 1 > 1) return;
28758
+ if (this.timer) {
28759
+ clearTimeout(this.timer);
28760
+ this.timer = null;
28761
+ this.tapHold = false;
28762
+ }
28763
+ });
28764
+ stage.on("contextmenu", (e) => {
28765
+ e.evt.preventDefault();
28766
+ if (!this.enabled) return;
28767
+ const selectedGroup = getTargetedNode(this.instance);
28768
+ this.triggerContextMenu(e.target, selectedGroup);
28769
+ });
28770
+ this.instance.addEventListener("onStageSelection", () => {
28771
+ if (this.tapHold) return;
28772
+ const containerRect = stage.container().getBoundingClientRect();
28773
+ const pointerPos = stage.getPointerPosition();
28774
+ if (containerRect && pointerPos) {
28775
+ const contextMenuPoint = {
28776
+ x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
28777
+ y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
28778
+ };
28779
+ const stageClickPoint = this.getStageClickPoint(pointerPos);
28780
+ this.instance.emitEvent("onNodeContextMenu", {
28781
+ selection: [],
28782
+ contextMenuPoint,
28783
+ clickPoint: pointerPos,
28784
+ stageClickPoint,
28785
+ visible: false
28786
+ });
28787
+ }
28788
+ });
28789
+ }
28790
+ getStageClickPoint(pointerPos) {
28791
+ const stage = this.instance.getStage();
28792
+ const scale = stage.scale();
28793
+ const position = stage.position();
28794
+ const stageClickPoint = {
28795
+ x: (pointerPos.x - position.x) / scale.x,
28796
+ y: (pointerPos.y - position.y) / scale.y
28797
+ };
28798
+ return stageClickPoint;
28799
+ }
28800
+ isContextMenuVisible() {
28801
+ return this.contextMenuVisible;
28802
+ }
28803
+ isTapHold() {
28804
+ return this.tapHold;
28805
+ }
28806
+ enable() {
28807
+ this.enabled = true;
28808
+ }
28809
+ disable() {
28810
+ this.enabled = false;
28811
+ }
28812
+ };
28813
+
28658
28814
  //#endregion
28659
28815
  //#region src/plugins/stage-drop-area/constants.ts
28660
28816
  const WEAVE_STAGE_DROP_AREA_KEY = "stageDropArea";
@@ -28682,18 +28838,18 @@ var WeaveStageDropAreaPlugin = class extends WeavePlugin {
28682
28838
  stage.container().addEventListener("dragover", (e) => {
28683
28839
  e.preventDefault();
28684
28840
  e.stopPropagation();
28685
- }, { signal: this.instance.getEventsController()?.signal });
28841
+ }, { signal: this.instance.getEventsController().signal });
28686
28842
  stage.container().addEventListener("drop", (e) => {
28687
28843
  e.preventDefault();
28688
28844
  e.stopPropagation();
28689
28845
  this.instance.emitEvent("onStageDrop", e);
28690
- }, { signal: this.instance.getEventsController()?.signal });
28846
+ }, { signal: this.instance.getEventsController().signal });
28691
28847
  window.addEventListener("dragover", (e) => e.preventDefault(), {
28692
- signal: this.instance.getEventsController()?.signal,
28848
+ signal: this.instance.getEventsController().signal,
28693
28849
  passive: false
28694
28850
  });
28695
28851
  window.addEventListener("drop", (e) => e.preventDefault(), {
28696
- signal: this.instance.getEventsController()?.signal,
28852
+ signal: this.instance.getEventsController().signal,
28697
28853
  passive: false
28698
28854
  });
28699
28855
  }
@@ -28861,7 +29017,7 @@ var WeaveStageKeyboardMovePlugin = class extends WeavePlugin {
28861
29017
  if (e.code === "ArrowLeft") this.handleNodesMovement(WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION.LEFT, { isShiftPressed });
28862
29018
  if (e.code === "ArrowRight") this.handleNodesMovement(WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION.RIGHT, { isShiftPressed });
28863
29019
  if (e.code === "ArrowDown") this.handleNodesMovement(WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION.DOWN, { isShiftPressed });
28864
- }, { signal: this.instance.getEventsController()?.signal });
29020
+ }, { signal: this.instance.getEventsController().signal });
28865
29021
  }
28866
29022
  enable() {
28867
29023
  this.enabled = true;
@@ -28929,18 +29085,18 @@ var WeaveNodesSnappingCustomGuides = class {
28929
29085
  const isOptionAltPressed = e.altKey;
28930
29086
  this.cleanupDistanceGuide();
28931
29087
  if (isOptionAltPressed && this.isDragging) this.handleDistanceGuide(isOptionAltPressed);
28932
- }, { signal: this.instance.getEventsController()?.signal });
29088
+ }, { signal: this.instance.getEventsController().signal });
28933
29089
  window.addEventListener("keyup", (e) => {
28934
29090
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
28935
29091
  if (isOptionAltPressed) this.cleanupDistanceGuide();
28936
- }, { signal: this.instance.getEventsController()?.signal });
29092
+ }, { signal: this.instance.getEventsController().signal });
28937
29093
  window.addEventListener("keydown", (e) => {
28938
29094
  const isOptionAltPressed = e.key === "Alt" || e.key === "Option";
28939
29095
  if (isOptionAltPressed && this.isDragging) {
28940
29096
  this.cleanupDistanceGuide();
28941
29097
  this.handleDistanceGuide(isOptionAltPressed);
28942
29098
  }
28943
- }, { signal: this.instance.getEventsController()?.signal });
29099
+ }, { signal: this.instance.getEventsController().signal });
28944
29100
  }
28945
29101
  getAllCustomGuides() {
28946
29102
  return this.customGuides;
@@ -28971,6 +29127,7 @@ var WeaveNodesSnappingCustomGuides = class {
28971
29127
  }
28972
29128
  saveCustomGuide(guide) {
28973
29129
  const containerId = guide.containerId;
29130
+ if (!this.customGuides) this.customGuides = {};
28974
29131
  if (!this.customGuides[containerId]) this.customGuides[containerId] = [];
28975
29132
  this.customGuides[containerId].push(guide);
28976
29133
  this.instance.emitEvent("snappingManager:onCustomGuidesChange", { guides: this.customGuides });
@@ -29138,7 +29295,7 @@ var WeaveNodesSnappingCustomGuides = class {
29138
29295
  this.setupEvents = false;
29139
29296
  }
29140
29297
  if (!this.noGuidesVisible() && !this.setupEvents) {
29141
- stage.container().addEventListener("keydown", this.handleArrowKeys, { signal: this.instance.getEventsController()?.signal });
29298
+ stage.container().addEventListener("keydown", this.handleArrowKeys, { signal: this.instance.getEventsController().signal });
29142
29299
  stage.on("pointerclick", this.handlePointerClick);
29143
29300
  this.instance.addEventListener("onNodesChange", this.handleOnNodesSelectedChange);
29144
29301
  this.instance.addEventListener("onStageMove", this.handleStagePanChange);