react-sync-board 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -4138,10 +4138,6 @@ var useItemList = function useItemList() {
4138
4138
  return items;
4139
4139
  };
4140
4140
 
4141
- var useSelectedItems = function useSelectedItems() {
4142
- return recoil.useRecoilValue(SelectedItemsAtom);
4143
- };
4144
-
4145
4141
  /**
4146
4142
  * Run effect only when component is unmounted.
4147
4143
  *
@@ -4329,6 +4325,28 @@ function useThrottledCallback(callback, deps, delay, noTrailing) {
4329
4325
  }, __spreadArray([delay, noTrailing], deps, true));
4330
4326
  }
4331
4327
 
4328
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4329
+ /**
4330
+ * Like `useEffect`, but passed function is debounced.
4331
+ *
4332
+ * @param callback Callback like for `useEffect`, but without ability to return
4333
+ * a cleanup function.
4334
+ * @param deps Dependencies list that will be passed to underlying `useEffect`
4335
+ * and `useDebouncedCallback`.
4336
+ * @param delay Debounce delay.
4337
+ * @param maxWait Maximum amount of milliseconds that function can be delayed
4338
+ * before it's force execution. 0 means no max wait.
4339
+ */
4340
+
4341
+ function useDebouncedEffect(callback, deps, delay, maxWait) {
4342
+ if (maxWait === void 0) {
4343
+ maxWait = 0;
4344
+ } // eslint-disable-next-line react-hooks/exhaustive-deps
4345
+
4346
+
4347
+ React.useEffect(useDebouncedCallback(callback, deps, delay, maxWait), deps);
4348
+ }
4349
+
4332
4350
  /* eslint-disable @typescript-eslint/no-explicit-any */
4333
4351
  /**
4334
4352
  * Like `useEffect`, but passed function is throttled.
@@ -4473,6 +4491,45 @@ function useResizeObserver(target, callback, enabled) {
4473
4491
  }, [target, ro]);
4474
4492
  }
4475
4493
 
4494
+ var useDebouncedItems = function useDebouncedItems() {
4495
+ var items = recoil.useRecoilValue(AllItemsSelector);
4496
+
4497
+ var _React$useState = React__default['default'].useState(items),
4498
+ _React$useState2 = _slicedToArray(_React$useState, 2),
4499
+ debouncedItems = _React$useState2[0],
4500
+ setDebouncedItems = _React$useState2[1];
4501
+
4502
+ var updateDebouncedItems = recoil.useRecoilCallback(function (_ref) {
4503
+ var snapshot = _ref.snapshot;
4504
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
4505
+ var currentItemMap;
4506
+ return regeneratorRuntime.wrap(function _callee$(_context) {
4507
+ while (1) {
4508
+ switch (_context.prev = _context.next) {
4509
+ case 0:
4510
+ _context.next = 2;
4511
+ return snapshot.getPromise(AllItemsSelector);
4512
+
4513
+ case 2:
4514
+ currentItemMap = _context.sent;
4515
+ setDebouncedItems(currentItemMap);
4516
+
4517
+ case 4:
4518
+ case "end":
4519
+ return _context.stop();
4520
+ }
4521
+ }
4522
+ }, _callee);
4523
+ }));
4524
+ }, []);
4525
+ useDebouncedEffect(updateDebouncedItems, [items], 300);
4526
+ return debouncedItems;
4527
+ };
4528
+
4529
+ var useSelectedItems = function useSelectedItems() {
4530
+ return recoil.useRecoilValue(SelectedItemsAtom);
4531
+ };
4532
+
4476
4533
  var isMacOS = function isMacOS() {
4477
4534
  var userAgent = navigator.userAgent.toLowerCase();
4478
4535
  return /mac os ?x 10/.test(userAgent);
@@ -4567,7 +4624,9 @@ var Gesture = function Gesture(_ref6) {
4567
4624
  onLongTap = _ref6$onLongTap === void 0 ? empty : _ref6$onLongTap,
4568
4625
  _ref6$onDoubleTap = _ref6.onDoubleTap,
4569
4626
  onDoubleTap = _ref6$onDoubleTap === void 0 ? empty : _ref6$onDoubleTap,
4570
- onZoom = _ref6.onZoom;
4627
+ onZoom = _ref6.onZoom,
4628
+ _ref6$mainAction = _ref6.mainAction,
4629
+ mainAction = _ref6$mainAction === void 0 ? "drag" : _ref6$mainAction;
4571
4630
  var wrapperRef = React__default['default'].useRef(null);
4572
4631
  var stateRef = React__default['default'].useRef({
4573
4632
  moving: false,
@@ -4775,6 +4834,7 @@ var Gesture = function Gesture(_ref6) {
4775
4834
  altKey = e.altKey,
4776
4835
  ctrlKey = e.ctrlKey,
4777
4836
  metaKey = e.metaKey,
4837
+ buttons = e.buttons,
4778
4838
  pointerType = e.pointerType;
4779
4839
 
4780
4840
  if (stateRef.current.mainPointer !== pointerId) {
@@ -4808,13 +4868,20 @@ var Gesture = function Gesture(_ref6) {
4808
4868
  clientY = eventClientY;
4809
4869
  } // We drag if
4810
4870
  // On non touch device
4811
- // - Button is 0
4812
- // - Alt key is no pressed
4871
+ // - Only button is pressed (1)
4872
+ // - any special key is no pressed
4813
4873
  // or on touch devices
4814
4874
  // - We use only one finger
4815
4875
 
4816
4876
 
4817
- var shouldDrag = pointerType !== "touch" ? stateRef.current.currentButton === 0 && !altKey : !twoFingers;
4877
+ var altAction = altKey || ctrlKey || metaKey || buttons !== 1;
4878
+
4879
+ if (mainAction !== "drag") {
4880
+ altAction = !altAction;
4881
+ }
4882
+
4883
+ var shouldDrag = pointerType !== "touch" ? !altAction : !twoFingers;
4884
+ var shouldPan = pointerType !== "touch" ? altAction : twoFingers;
4818
4885
 
4819
4886
  if (shouldDrag) {
4820
4887
  // Send drag start on first move
@@ -4863,7 +4930,9 @@ var Gesture = function Gesture(_ref6) {
4863
4930
  target: stateRef.current.target,
4864
4931
  event: e
4865
4932
  });
4866
- } else {
4933
+ }
4934
+
4935
+ if (shouldPan) {
4867
4936
  if (!stateRef.current.gestureStart) {
4868
4937
  wrapperRef.current.style.cursor = "move";
4869
4938
  stateRef.current.gestureStart = true; // Clear tap timeout on first move
@@ -4907,7 +4976,7 @@ var Gesture = function Gesture(_ref6) {
4907
4976
  stateRef.current.prevX = clientX;
4908
4977
  stateRef.current.prevY = clientY;
4909
4978
  }
4910
- }, [onDrag, onDragStart, onPan, onZoom, queue]);
4979
+ }, [mainAction, onDrag, onDragStart, onPan, onZoom, queue]);
4911
4980
  var onPointerUp = React__default['default'].useCallback(function (e) {
4912
4981
  var clientX = e.clientX,
4913
4982
  clientY = e.clientY,
@@ -5061,7 +5130,7 @@ var _excluded$2 = ["type", "rotation", "id", "locked", "layer"],
5061
5130
  _excluded3 = ["x", "y", "layer", "moving"];
5062
5131
 
5063
5132
  var _templateObject$2;
5064
- var ItemWrapper = newStyled.div(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteral(["\n display: inline-block;\n transition: transform 150ms;\n user-select: none;\n padding: 2px;\n box-sizing: border-box;\n transform: rotate(", "deg);\n\n & .corner {\n position: absolute;\n width: 0px;\n height: 0px;\n }\n\n & .top-left {\n top: 0;\n left: 0;\n }\n & .top-right {\n top: 0;\n right: 0;\n }\n & .bottom-left {\n bottom: 0;\n left: 0;\n }\n & .bottom-right {\n bottom: 0;\n right: 0;\n }\n\n &.selected {\n border: 2px dashed #db5034;\n padding: 0px;\n cursor: pointer;\n }\n\n &.locked::after {\n content: \"\";\n position: absolute;\n width: 24px;\n height: 30px;\n top: 4px;\n right: 4px;\n opacity: 0.1;\n background-image: url(\"", "\");\n background-size: cover;\n user-select: none;\n }\n\n &.locked:hover::after {\n opacity: 0.3;\n }\n\n & .resize {\n position: absolute;\n\n width: 10px;\n height: 10px;\n border: 2px solid #db5034;\n background-color: #db5034;\n cursor: move;\n\n &.resize-width {\n cursor: ew-resize;\n right: -6px;\n top: calc(50% - 5px);\n }\n &.resize-height {\n cursor: ns-resize;\n bottom: -6px;\n left: calc(50% - 5px);\n }\n &.resize-ratio {\n cursor: nwse-resize;\n bottom: -6px;\n right: -6px;\n }\n }\n"])), function (_ref) {
5133
+ var ItemWrapper = newStyled.div(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteral(["\n display: inline-block;\n transition: transform 150ms;\n user-select: none;\n padding: 2px;\n box-sizing: border-box;\n transform: rotate(", "deg);\n\n & .corner {\n position: absolute;\n width: 0px;\n height: 0px;\n }\n\n & .top-left {\n top: 0;\n left: 0;\n }\n & .top-right {\n top: 0;\n right: 0;\n }\n & .bottom-left {\n bottom: 0;\n left: 0;\n }\n & .bottom-right {\n bottom: 0;\n right: 0;\n }\n\n & .center {\n position: absolute;\n width: 0px;\n height: 0px;\n top: 50%;\n left: 50%;\n }\n\n &.selected {\n border: 2px dashed #db5034;\n padding: 0px;\n cursor: pointer;\n }\n\n &.locked::after {\n content: \"\";\n position: absolute;\n width: 24px;\n height: 30px;\n top: 4px;\n right: 4px;\n opacity: 0.1;\n background-image: url(\"", "\");\n background-size: cover;\n user-select: none;\n }\n\n &.locked:hover::after {\n opacity: 0.3;\n }\n\n & .resize {\n position: absolute;\n\n width: 10px;\n height: 10px;\n border: 2px solid #db5034;\n background-color: #db5034;\n cursor: move;\n\n &.resize-width {\n cursor: ew-resize;\n right: -6px;\n top: calc(50% - 5px);\n }\n &.resize-height {\n cursor: ns-resize;\n bottom: -6px;\n left: calc(50% - 5px);\n }\n &.resize-ratio {\n cursor: nwse-resize;\n bottom: -6px;\n right: -6px;\n }\n }\n"])), function (_ref) {
5065
5134
  var rotation = _ref.rotation;
5066
5135
  return rotation;
5067
5136
  }, img);
@@ -5315,6 +5384,8 @@ var Item = function Item(_ref5) {
5315
5384
  className: "corner bottom-right"
5316
5385
  }), /*#__PURE__*/React__default['default'].createElement("div", {
5317
5386
  className: "corner bottom-left"
5387
+ }), /*#__PURE__*/React__default['default'].createElement("div", {
5388
+ className: "center"
5318
5389
  }), isSelected && showResizeHandle && /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, resizeDirections.b && /*#__PURE__*/React__default['default'].createElement(ResizeHandler, {
5319
5390
  className: "resize resize-ratio",
5320
5391
  onResize: onResizeRatio
@@ -5347,8 +5418,6 @@ var PositionedItem = function PositionedItem(_ref12) {
5347
5418
  rest = _objectWithoutProperties(_ref12, _excluded2);
5348
5419
 
5349
5420
  if (!rest.itemMap[state.type]) {
5350
- // eslint-disable-next-line no-console
5351
- console.warn("Item type ".concat(state.type, " not recognized!"));
5352
5421
  return null;
5353
5422
  }
5354
5423
 
@@ -5882,24 +5951,20 @@ var Selector = function Selector(_ref) {
5882
5951
  }));
5883
5952
  }, [setSelected]);
5884
5953
  useThrottledEffect(updateSelected, [selector, updateSelected], 200);
5885
-
5886
- var onDragStart = /*#__PURE__*/function () {
5954
+ var onDragStart = React__default['default'].useCallback( /*#__PURE__*/function () {
5887
5955
  var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(event) {
5888
- var button, altKey, ctrlKey, metaKey, foundElement, metaKeyPressed, goodButton;
5956
+ var foundElement;
5889
5957
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
5890
5958
  while (1) {
5891
5959
  switch (_context2.prev = _context2.next) {
5892
5960
  case 0:
5893
- button = event.button, altKey = event.altKey, ctrlKey = event.ctrlKey, metaKey = event.metaKey;
5894
- _context2.next = 3;
5961
+ _context2.next = 2;
5895
5962
  return findElementUnderPointer(event);
5896
5963
 
5897
- case 3:
5964
+ case 2:
5898
5965
  foundElement = _context2.sent;
5899
- metaKeyPressed = altKey || ctrlKey || metaKey;
5900
- goodButton = moveFirst ? button === 1 || button === 0 && metaKeyPressed : button === 0 && !metaKeyPressed;
5901
5966
 
5902
- if (goodButton && (!foundElement || moveFirst)) {
5967
+ if (!foundElement) {
5903
5968
  stateRef.current.moving = true;
5904
5969
  setBoardState(function (prev) {
5905
5970
  return _objectSpread2(_objectSpread2({}, prev), {}, {
@@ -5909,7 +5974,7 @@ var Selector = function Selector(_ref) {
5909
5974
  wrapperRef.current.style.cursor = "crosshair";
5910
5975
  }
5911
5976
 
5912
- case 7:
5977
+ case 4:
5913
5978
  case "end":
5914
5979
  return _context2.stop();
5915
5980
  }
@@ -5917,11 +5982,10 @@ var Selector = function Selector(_ref) {
5917
5982
  }, _callee2);
5918
5983
  }));
5919
5984
 
5920
- return function onDragStart(_x) {
5985
+ return function (_x) {
5921
5986
  return _ref4.apply(this, arguments);
5922
5987
  };
5923
- }();
5924
-
5988
+ }(), [findElementUnderPointer, setBoardState]);
5925
5989
  var onDrag = recoil.useRecoilCallback(function (_ref5) {
5926
5990
  var snapshot = _ref5.snapshot;
5927
5991
  return /*#__PURE__*/function () {
@@ -5984,8 +6048,7 @@ var Selector = function Selector(_ref) {
5984
6048
  };
5985
6049
  }();
5986
6050
  }, []);
5987
-
5988
- var onDragEnd = function onDragEnd() {
6051
+ var onDragEnd = React__default['default'].useCallback(function () {
5989
6052
  if (stateRef.current.moving) {
5990
6053
  setBoardState(function (prev) {
5991
6054
  return _objectSpread2(_objectSpread2({}, prev), {}, {
@@ -5998,8 +6061,7 @@ var Selector = function Selector(_ref) {
5998
6061
  });
5999
6062
  wrapperRef.current.style.cursor = "auto";
6000
6063
  }
6001
- };
6002
-
6064
+ }, [setBoardState]);
6003
6065
  var onLongTap = React__default['default'].useCallback(function (_ref8) {
6004
6066
  var target = _ref8.target;
6005
6067
  var foundElement = insideClass(target, "item");
@@ -6080,7 +6142,8 @@ var Selector = function Selector(_ref) {
6080
6142
  onDrag: onDrag,
6081
6143
  onDragEnd: onDragEnd,
6082
6144
  onTap: onTap,
6083
- onLongTap: onLongTap
6145
+ onLongTap: onLongTap,
6146
+ mainAction: moveFirst ? "pan" : "drag"
6084
6147
  }, /*#__PURE__*/React__default['default'].createElement("div", {
6085
6148
  ref: wrapperRef
6086
6149
  }, selector.moving && /*#__PURE__*/React__default['default'].createElement("div", {
@@ -6095,6 +6158,7 @@ var Selector = function Selector(_ref) {
6095
6158
 
6096
6159
  var ActionPane = function ActionPane(_ref) {
6097
6160
  var children = _ref.children;
6161
+ _ref.moveFirst;
6098
6162
 
6099
6163
  var _useItemActions = useItemActions(),
6100
6164
  moveItems = _useItemActions.moveItems,
@@ -6929,8 +6993,6 @@ var usePositionNavigator = function usePositionNavigator() {
6929
6993
  return null;
6930
6994
  };
6931
6995
 
6932
- var SCALE_TOLERANCE = 0.8;
6933
-
6934
6996
  var PanZoom = function PanZoom(_ref) {
6935
6997
  var children = _ref.children,
6936
6998
  _ref$moveFirst = _ref.moveFirst,
@@ -6940,7 +7002,8 @@ var PanZoom = function PanZoom(_ref) {
6940
7002
 
6941
7003
  var _useDim = useDim(),
6942
7004
  setDim = _useDim.setDim,
6943
- zoomTo = _useDim.zoomTo;
7005
+ zoomToCenter = _useDim.zoomToCenter,
7006
+ zoomToExtent = _useDim.zoomToExtent;
6944
7007
 
6945
7008
  var _useRecoilValue = recoil.useRecoilValue(ConfigurationAtom),
6946
7009
  itemExtentGlobal = _useRecoilValue.itemExtent;
@@ -6956,10 +7019,14 @@ var PanZoom = function PanZoom(_ref) {
6956
7019
  var getMouseInfo = useMousePosition(wrappedRef); // Hooks to save/restore position
6957
7020
 
6958
7021
  usePositionNavigator();
7022
+ /**
7023
+ * Center board on startup
7024
+ */
7025
+
6959
7026
  var centerBoard = recoil.useRecoilCallback(function (_ref2) {
6960
7027
  var snapshot = _ref2.snapshot;
6961
7028
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
6962
- var _yield$snapshot$getPr, _yield$snapshot$getPr2, left, top, width, height, boardWrapperRect, scaleX, scaleY, newScale, scaleWithTolerance, centerX, centerY;
7029
+ var _yield$snapshot$getPr, itemExtent;
6963
7030
 
6964
7031
  return regeneratorRuntime.wrap(function _callee$(_context) {
6965
7032
  while (1) {
@@ -6970,34 +7037,17 @@ var PanZoom = function PanZoom(_ref) {
6970
7037
 
6971
7038
  case 2:
6972
7039
  _yield$snapshot$getPr = _context.sent;
6973
- _yield$snapshot$getPr2 = _yield$snapshot$getPr.itemExtent;
6974
- left = _yield$snapshot$getPr2.left;
6975
- top = _yield$snapshot$getPr2.top;
6976
- width = _yield$snapshot$getPr2.width;
6977
- height = _yield$snapshot$getPr2.height;
6978
- boardWrapperRect = _yield$snapshot$getPr.boardWrapperRect;
6979
- scaleX = boardWrapperRect.width / width;
6980
- scaleY = boardWrapperRect.height / height;
6981
- newScale = Math.min(scaleX, scaleY);
6982
- scaleWithTolerance = newScale * SCALE_TOLERANCE;
6983
- centerX = boardWrapperRect.width / 2 - (left + width / 2) * scaleWithTolerance;
6984
- centerY = boardWrapperRect.height / 2 - (top + height / 2) * scaleWithTolerance;
6985
- setDim(function (prev) {
6986
- return _objectSpread2(_objectSpread2({}, prev), {}, {
6987
- translateX: centerX,
6988
- translateY: centerY,
6989
- scale: scaleWithTolerance
6990
- });
6991
- });
7040
+ itemExtent = _yield$snapshot$getPr.itemExtent;
7041
+ zoomToExtent(itemExtent);
6992
7042
 
6993
- case 16:
7043
+ case 5:
6994
7044
  case "end":
6995
7045
  return _context.stop();
6996
7046
  }
6997
7047
  }
6998
7048
  }, _callee);
6999
7049
  }));
7000
- }, [setDim]);
7050
+ }, [zoomToExtent]);
7001
7051
  React__default['default'].useEffect(function () {
7002
7052
  if (!centered && itemExtentGlobal.left) {
7003
7053
  // Center board on first valid extent
@@ -7009,7 +7059,7 @@ var PanZoom = function PanZoom(_ref) {
7009
7059
  var clientX = _ref4.clientX,
7010
7060
  clientY = _ref4.clientY,
7011
7061
  scale = _ref4.scale;
7012
- zoomTo(1 - scale / 500, {
7062
+ zoomToCenter(1 - scale / 500, {
7013
7063
  x: clientX,
7014
7064
  y: clientY
7015
7065
  }); // Update the board zooming state
@@ -7027,15 +7077,25 @@ var PanZoom = function PanZoom(_ref) {
7027
7077
  zooming: true
7028
7078
  }) : prev;
7029
7079
  });
7030
- }, [setBoardState, zoomTo]);
7080
+ }, [setBoardState, zoomToCenter]);
7031
7081
  var onPan = React__default['default'].useCallback( /*#__PURE__*/function () {
7032
7082
  var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref5) {
7033
- var deltaX, deltaY;
7083
+ var deltaX, deltaY, target, insideItem;
7034
7084
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
7035
7085
  while (1) {
7036
7086
  switch (_context2.prev = _context2.next) {
7037
7087
  case 0:
7038
- deltaX = _ref5.deltaX, deltaY = _ref5.deltaY;
7088
+ deltaX = _ref5.deltaX, deltaY = _ref5.deltaY, target = _ref5.target;
7089
+ insideItem = insideClass(target, "item") && !insideClass(target, "locked");
7090
+
7091
+ if (!(insideItem && moveFirst)) {
7092
+ _context2.next = 4;
7093
+ break;
7094
+ }
7095
+
7096
+ return _context2.abrupt("return");
7097
+
7098
+ case 4:
7039
7099
  setDim(function (prev) {
7040
7100
  return _objectSpread2(_objectSpread2({}, prev), {}, {
7041
7101
  translateX: prev.translateX + deltaX,
@@ -7057,7 +7117,7 @@ var PanZoom = function PanZoom(_ref) {
7057
7117
  }) : prev;
7058
7118
  });
7059
7119
 
7060
- case 5:
7120
+ case 8:
7061
7121
  case "end":
7062
7122
  return _context2.stop();
7063
7123
  }
@@ -7068,15 +7128,7 @@ var PanZoom = function PanZoom(_ref) {
7068
7128
  return function (_x) {
7069
7129
  return _ref6.apply(this, arguments);
7070
7130
  };
7071
- }(), [setBoardState, setDim]);
7072
- var onDrag = React__default['default'].useCallback(function (state) {
7073
- var target = state.target;
7074
- var outsideItem = !insideClass(target, "item") || insideClass(target, "locked");
7075
-
7076
- if (moveFirst && outsideItem) {
7077
- onPan(state);
7078
- }
7079
- }, [moveFirst, onPan]);
7131
+ }(), [moveFirst, setBoardState, setDim]);
7080
7132
  var onKeyDown = recoil.useRecoilCallback(function (_ref7) {
7081
7133
  var snapshot = _ref7.snapshot;
7082
7134
  return /*#__PURE__*/function () {
@@ -7161,14 +7213,14 @@ var PanZoom = function PanZoom(_ref) {
7161
7213
  translateX: prev.translateX + moveX
7162
7214
  });
7163
7215
  });
7164
- zoomTo(zoom);
7216
+ zoomToCenter(zoom);
7165
7217
  e.preventDefault();
7166
7218
 
7167
7219
  case 31:
7168
7220
  // Temporary zoom
7169
7221
  if (e.key === " " && !e.repeat) {
7170
7222
  if (getMouseInfo().hover) {
7171
- zoomTo(3, getMouseInfo());
7223
+ zoomToCenter(3, getMouseInfo());
7172
7224
  }
7173
7225
  }
7174
7226
 
@@ -7184,15 +7236,15 @@ var PanZoom = function PanZoom(_ref) {
7184
7236
  return _ref8.apply(this, arguments);
7185
7237
  };
7186
7238
  }();
7187
- }, [setDim, zoomTo, getMouseInfo]);
7239
+ }, [setDim, zoomToCenter, getMouseInfo]);
7188
7240
  var onKeyUp = React__default['default'].useCallback(function (e) {
7189
7241
  // Ignore text in Input or Textarea
7190
7242
  if (["INPUT", "TEXTAREA"].includes(e.target.tagName)) return; // Zoom out on release
7191
7243
 
7192
7244
  if (e.key === " " && getMouseInfo().hover) {
7193
- zoomTo(1 / 3, getMouseInfo());
7245
+ zoomToCenter(1 / 3, getMouseInfo());
7194
7246
  }
7195
- }, [getMouseInfo, zoomTo]);
7247
+ }, [getMouseInfo, zoomToCenter]);
7196
7248
  React__default['default'].useEffect(function () {
7197
7249
  document.addEventListener("keydown", onKeyDown);
7198
7250
  document.addEventListener("keyup", onKeyUp);
@@ -7204,7 +7256,7 @@ var PanZoom = function PanZoom(_ref) {
7204
7256
  return /*#__PURE__*/React__default['default'].createElement(Gesture, {
7205
7257
  onPan: onPan,
7206
7258
  onZoom: onZoom,
7207
- onDrag: onDrag
7259
+ mainAction: moveFirst ? "pan" : "drag"
7208
7260
  }, /*#__PURE__*/React__default['default'].createElement("div", {
7209
7261
  style: {
7210
7262
  display: "inline-block",
@@ -7372,7 +7424,9 @@ var Board = function Board(_ref) {
7372
7424
  moveFirst: moveFirst
7373
7425
  }, /*#__PURE__*/React__default['default'].createElement(Selector, {
7374
7426
  moveFirst: moveFirst
7375
- }, /*#__PURE__*/React__default['default'].createElement(ActionPane, null, /*#__PURE__*/React__default['default'].createElement(CursorPane, null, /*#__PURE__*/React__default['default'].createElement("div", {
7427
+ }, /*#__PURE__*/React__default['default'].createElement(ActionPane, {
7428
+ moveFirst: moveFirst
7429
+ }, /*#__PURE__*/React__default['default'].createElement(CursorPane, null, /*#__PURE__*/React__default['default'].createElement("div", {
7376
7430
  onContextMenu: function onContextMenu(e) {
7377
7431
  e.preventDefault();
7378
7432
  },
@@ -7383,6 +7437,7 @@ var Board = function Board(_ref) {
7383
7437
 
7384
7438
  var TOLERANCE = 100;
7385
7439
  var MIN_SIZE = 1000;
7440
+ var SCALE_TOLERANCE = 0.8;
7386
7441
 
7387
7442
  var translateBoundaries = function translateBoundaries(_ref) {
7388
7443
  var x = _ref.x,
@@ -7500,7 +7555,7 @@ var useDim = function useDim() {
7500
7555
  };
7501
7556
  }();
7502
7557
  }, [setDim]);
7503
- var zoomTo = recoil.useRecoilCallback(function (_ref5) {
7558
+ var zoomToCenter = recoil.useRecoilCallback(function (_ref5) {
7504
7559
  var snapshot = _ref5.snapshot;
7505
7560
  return /*#__PURE__*/function () {
7506
7561
  var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(factor, zoomCenter) {
@@ -7579,24 +7634,68 @@ var useDim = function useDim() {
7579
7634
  };
7580
7635
  }();
7581
7636
  }, [setDim]);
7582
- var updateScaleBoundaries = recoil.useRecoilCallback(function (_ref7) {
7637
+ var zoomToExtent = recoil.useRecoilCallback(function (_ref7) {
7583
7638
  var snapshot = _ref7.snapshot;
7584
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
7585
- var _yield$snapshot$getPr3, _yield$snapshot$getPr4, width, height, boardWrapperRect, scaleX, scaleY, newScale;
7639
+ return /*#__PURE__*/function () {
7640
+ var _ref9 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref8) {
7641
+ var left, top, width, height, _yield$snapshot$getPr3, boardWrapperRect, scaleX, scaleY, newScale, scaleWithTolerance, centerX, centerY;
7586
7642
 
7587
- return regeneratorRuntime.wrap(function _callee3$(_context3) {
7643
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
7644
+ while (1) {
7645
+ switch (_context3.prev = _context3.next) {
7646
+ case 0:
7647
+ left = _ref8.left, top = _ref8.top, width = _ref8.width, height = _ref8.height;
7648
+ _context3.next = 3;
7649
+ return snapshot.getPromise(ConfigurationAtom);
7650
+
7651
+ case 3:
7652
+ _yield$snapshot$getPr3 = _context3.sent;
7653
+ boardWrapperRect = _yield$snapshot$getPr3.boardWrapperRect;
7654
+ scaleX = boardWrapperRect.width / width;
7655
+ scaleY = boardWrapperRect.height / height;
7656
+ newScale = Math.min(scaleX, scaleY);
7657
+ scaleWithTolerance = newScale * SCALE_TOLERANCE;
7658
+ centerX = boardWrapperRect.width / 2 - (left + width / 2) * scaleWithTolerance;
7659
+ centerY = boardWrapperRect.height / 2 - (top + height / 2) * scaleWithTolerance;
7660
+ setDim(function (prev) {
7661
+ return _objectSpread2(_objectSpread2({}, prev), {}, {
7662
+ translateX: centerX,
7663
+ translateY: centerY,
7664
+ scale: scaleWithTolerance
7665
+ });
7666
+ });
7667
+
7668
+ case 12:
7669
+ case "end":
7670
+ return _context3.stop();
7671
+ }
7672
+ }
7673
+ }, _callee3);
7674
+ }));
7675
+
7676
+ return function (_x4) {
7677
+ return _ref9.apply(this, arguments);
7678
+ };
7679
+ }();
7680
+ }, [setDim]);
7681
+ var updateScaleBoundaries = recoil.useRecoilCallback(function (_ref10) {
7682
+ var snapshot = _ref10.snapshot;
7683
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
7684
+ var _yield$snapshot$getPr4, _yield$snapshot$getPr5, width, height, boardWrapperRect, scaleX, scaleY, newScale;
7685
+
7686
+ return regeneratorRuntime.wrap(function _callee4$(_context4) {
7588
7687
  while (1) {
7589
- switch (_context3.prev = _context3.next) {
7688
+ switch (_context4.prev = _context4.next) {
7590
7689
  case 0:
7591
- _context3.next = 2;
7690
+ _context4.next = 2;
7592
7691
  return snapshot.getPromise(ConfigurationAtom);
7593
7692
 
7594
7693
  case 2:
7595
- _yield$snapshot$getPr3 = _context3.sent;
7596
- _yield$snapshot$getPr4 = _yield$snapshot$getPr3.itemExtent;
7597
- width = _yield$snapshot$getPr4.width;
7598
- height = _yield$snapshot$getPr4.height;
7599
- boardWrapperRect = _yield$snapshot$getPr3.boardWrapperRect;
7694
+ _yield$snapshot$getPr4 = _context4.sent;
7695
+ _yield$snapshot$getPr5 = _yield$snapshot$getPr4.itemExtent;
7696
+ width = _yield$snapshot$getPr5.width;
7697
+ height = _yield$snapshot$getPr5.height;
7698
+ boardWrapperRect = _yield$snapshot$getPr4.boardWrapperRect;
7600
7699
  scaleX = boardWrapperRect.width / width;
7601
7700
  scaleY = boardWrapperRect.height / height;
7602
7701
  newScale = Math.min(scaleX, scaleY);
@@ -7604,86 +7703,86 @@ var useDim = function useDim() {
7604
7703
 
7605
7704
  case 11:
7606
7705
  case "end":
7607
- return _context3.stop();
7706
+ return _context4.stop();
7608
7707
  }
7609
7708
  }
7610
- }, _callee3);
7709
+ }, _callee4);
7611
7710
  }));
7612
7711
  }, []);
7613
- var getCenterCoordinates = recoil.useRecoilCallback(function (_ref9) {
7614
- var snapshot = _ref9.snapshot;
7615
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
7616
- var _yield$snapshot$getPr5, boardWrapperRect, boardSize, _yield$snapshot$getPr6, translateX, translateY, scale;
7712
+ var getCenterCoordinates = recoil.useRecoilCallback(function (_ref12) {
7713
+ var snapshot = _ref12.snapshot;
7714
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
7715
+ var _yield$snapshot$getPr6, boardWrapperRect, boardSize, _yield$snapshot$getPr7, translateX, translateY, scale;
7617
7716
 
7618
- return regeneratorRuntime.wrap(function _callee4$(_context4) {
7717
+ return regeneratorRuntime.wrap(function _callee5$(_context5) {
7619
7718
  while (1) {
7620
- switch (_context4.prev = _context4.next) {
7719
+ switch (_context5.prev = _context5.next) {
7621
7720
  case 0:
7622
- _context4.next = 2;
7721
+ _context5.next = 2;
7623
7722
  return snapshot.getPromise(ConfigurationAtom);
7624
7723
 
7625
7724
  case 2:
7626
- _yield$snapshot$getPr5 = _context4.sent;
7627
- boardWrapperRect = _yield$snapshot$getPr5.boardWrapperRect;
7628
- boardSize = _yield$snapshot$getPr5.boardSize;
7629
- _context4.next = 7;
7725
+ _yield$snapshot$getPr6 = _context5.sent;
7726
+ boardWrapperRect = _yield$snapshot$getPr6.boardWrapperRect;
7727
+ boardSize = _yield$snapshot$getPr6.boardSize;
7728
+ _context5.next = 7;
7630
7729
  return snapshot.getPromise(BoardTransformAtom);
7631
7730
 
7632
7731
  case 7:
7633
- _yield$snapshot$getPr6 = _context4.sent;
7634
- translateX = _yield$snapshot$getPr6.translateX;
7635
- translateY = _yield$snapshot$getPr6.translateY;
7636
- scale = _yield$snapshot$getPr6.scale;
7637
- return _context4.abrupt("return", {
7732
+ _yield$snapshot$getPr7 = _context5.sent;
7733
+ translateX = _yield$snapshot$getPr7.translateX;
7734
+ translateY = _yield$snapshot$getPr7.translateY;
7735
+ scale = _yield$snapshot$getPr7.scale;
7736
+ return _context5.abrupt("return", {
7638
7737
  x: (boardWrapperRect.width / 2 - translateX) / scale - boardSize / 2,
7639
7738
  y: (boardWrapperRect.height / 2 - translateY) / scale - boardSize / 2
7640
7739
  });
7641
7740
 
7642
7741
  case 12:
7643
7742
  case "end":
7644
- return _context4.stop();
7743
+ return _context5.stop();
7645
7744
  }
7646
7745
  }
7647
- }, _callee4);
7746
+ }, _callee5);
7648
7747
  }));
7649
7748
  }, []);
7650
- var updateItemExtent = recoil.useRecoilCallback(function (_ref11) {
7651
- var snapshot = _ref11.snapshot,
7652
- set = _ref11.set;
7653
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
7654
- var itemIds, _yield$snapshot$getPr7, boardWrapperRect, boardWrapper, boardSize, _yield$snapshot$getPr8, scale, translateX, translateY, _ref13, left, top, width, height, relativeExtent, delta, _delta;
7749
+ var updateItemExtent = recoil.useRecoilCallback(function (_ref14) {
7750
+ var snapshot = _ref14.snapshot,
7751
+ set = _ref14.set;
7752
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {
7753
+ var itemIds, _yield$snapshot$getPr8, boardWrapperRect, boardWrapper, boardSize, _yield$snapshot$getPr9, scale, translateX, translateY, _ref16, left, top, width, height, relativeExtent, delta, _delta;
7655
7754
 
7656
- return regeneratorRuntime.wrap(function _callee5$(_context5) {
7755
+ return regeneratorRuntime.wrap(function _callee6$(_context6) {
7657
7756
  while (1) {
7658
- switch (_context5.prev = _context5.next) {
7757
+ switch (_context6.prev = _context6.next) {
7659
7758
  case 0:
7660
- _context5.next = 2;
7759
+ _context6.next = 2;
7661
7760
  return snapshot.getPromise(ItemListAtom);
7662
7761
 
7663
7762
  case 2:
7664
- itemIds = _context5.sent;
7665
- _context5.next = 5;
7763
+ itemIds = _context6.sent;
7764
+ _context6.next = 5;
7666
7765
  return snapshot.getPromise(ConfigurationAtom);
7667
7766
 
7668
7767
  case 5:
7669
- _yield$snapshot$getPr7 = _context5.sent;
7670
- boardWrapperRect = _yield$snapshot$getPr7.boardWrapperRect;
7671
- boardWrapper = _yield$snapshot$getPr7.boardWrapper;
7672
- boardSize = _yield$snapshot$getPr7.boardSize;
7673
- _context5.next = 11;
7768
+ _yield$snapshot$getPr8 = _context6.sent;
7769
+ boardWrapperRect = _yield$snapshot$getPr8.boardWrapperRect;
7770
+ boardWrapper = _yield$snapshot$getPr8.boardWrapper;
7771
+ boardSize = _yield$snapshot$getPr8.boardSize;
7772
+ _context6.next = 11;
7674
7773
  return snapshot.getPromise(BoardTransformAtom);
7675
7774
 
7676
7775
  case 11:
7677
- _yield$snapshot$getPr8 = _context5.sent;
7678
- scale = _yield$snapshot$getPr8.scale;
7679
- translateX = _yield$snapshot$getPr8.translateX;
7680
- translateY = _yield$snapshot$getPr8.translateY;
7681
- _ref13 = getItemBoundingBox(itemIds, boardWrapper) || {
7776
+ _yield$snapshot$getPr9 = _context6.sent;
7777
+ scale = _yield$snapshot$getPr9.scale;
7778
+ translateX = _yield$snapshot$getPr9.translateX;
7779
+ translateY = _yield$snapshot$getPr9.translateY;
7780
+ _ref16 = getItemBoundingBox(itemIds, boardWrapper) || {
7682
7781
  left: boardSize / 2 * scale + boardWrapperRect.left + translateX,
7683
7782
  top: boardSize / 2 * scale + boardWrapperRect.top + translateY,
7684
7783
  width: 0,
7685
7784
  height: 0
7686
- }, left = _ref13.left, top = _ref13.top, width = _ref13.width, height = _ref13.height;
7785
+ }, left = _ref16.left, top = _ref16.top, width = _ref16.width, height = _ref16.height;
7687
7786
  relativeExtent = {
7688
7787
  left: (left - boardWrapperRect.left - translateX) / scale,
7689
7788
  top: (top - boardWrapperRect.top - translateY) / scale,
@@ -7715,10 +7814,10 @@ var useDim = function useDim() {
7715
7814
 
7716
7815
  case 22:
7717
7816
  case "end":
7718
- return _context5.stop();
7817
+ return _context6.stop();
7719
7818
  }
7720
7819
  }
7721
- }, _callee5);
7820
+ }, _callee6);
7722
7821
  }));
7723
7822
  }, []);
7724
7823
  var debouncedUpdateItemExtent = useDebouncedCallback(updateItemExtent, [], 300);
@@ -7730,7 +7829,9 @@ var useDim = function useDim() {
7730
7829
  return {
7731
7830
  setDim: setDimSafe,
7732
7831
  getDim: getDim,
7733
- zoomTo: zoomTo,
7832
+ zoomTo: zoomToCenter,
7833
+ zoomToCenter: zoomToCenter,
7834
+ zoomToExtent: zoomToExtent,
7734
7835
  getCenter: getCenterCoordinates,
7735
7836
  updateItemExtent: debouncedUpdateItemExtent
7736
7837
  };
@@ -8686,8 +8787,10 @@ var getActionsFromItem = function getActionsFromItem(item, itemMap) {
8686
8787
  };
8687
8788
 
8688
8789
  var useAvailableActions = function useAvailableActions() {
8790
+ var itemMap = recoil.useRecoilValue(ItemMapAtom);
8791
+
8689
8792
  var _useRecoilValue = recoil.useRecoilValue(ConfigurationAtom),
8690
- itemMap = _useRecoilValue.itemTemplates;
8793
+ itemTemplates = _useRecoilValue.itemTemplates;
8691
8794
 
8692
8795
  var selected = recoil.useRecoilValue(SelectedItemsAtom);
8693
8796
 
@@ -8697,6 +8800,13 @@ var useAvailableActions = function useAvailableActions() {
8697
8800
  setAvailableActions = _React$useState2[1];
8698
8801
 
8699
8802
  var isMountedRef = React__default['default'].useRef(false);
8803
+ React__default['default'].useEffect(function () {
8804
+ // Mounted guard
8805
+ isMountedRef.current = true;
8806
+ return function () {
8807
+ isMountedRef.current = false;
8808
+ };
8809
+ }, []);
8700
8810
  var getItemListOrSelected = recoil.useRecoilCallback(function (_ref) {
8701
8811
  var snapshot = _ref.snapshot;
8702
8812
  return /*#__PURE__*/function () {
@@ -8744,19 +8854,12 @@ var useAvailableActions = function useAvailableActions() {
8744
8854
  };
8745
8855
  }();
8746
8856
  }, []);
8747
- React__default['default'].useEffect(function () {
8748
- // Mounted guard
8749
- isMountedRef.current = true;
8750
- return function () {
8751
- isMountedRef.current = false;
8752
- };
8753
- }, []);
8754
8857
  /**
8755
8858
  * Returns available actions for selected items. An action is kept only if all
8756
8859
  * items have this exact same action with same parameters.
8757
8860
  */
8758
8861
 
8759
- var updateAvailableActions = React__default['default'].useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
8862
+ var updateAvailableActions = React.useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
8760
8863
  var _yield$getItemListOrS, _yield$getItemListOrS2, selectedItemIds, selectedItemList, allActions;
8761
8864
 
8762
8865
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
@@ -8786,13 +8889,13 @@ var useAvailableActions = function useAvailableActions() {
8786
8889
 
8787
8890
  case 9:
8788
8891
  allActions = selectedItemList.reduce(function (acc, item) {
8789
- var itemActions = getActionsFromItem(item, itemMap);
8892
+ var itemActions = getActionsFromItem(item, itemTemplates);
8790
8893
  return acc.filter(function (value) {
8791
8894
  return itemActions.some(function (itemAction) {
8792
8895
  return es6(value, itemAction);
8793
8896
  });
8794
8897
  });
8795
- }, getActionsFromItem(selectedItemList[0], itemMap));
8898
+ }, getActionsFromItem(selectedItemList[0], itemTemplates));
8796
8899
  setAvailableActions(allActions);
8797
8900
  _context2.next = 14;
8798
8901
  break;
@@ -8806,11 +8909,11 @@ var useAvailableActions = function useAvailableActions() {
8806
8909
  }
8807
8910
  }
8808
8911
  }, _callee2);
8809
- })), [getItemListOrSelected, itemMap]); // Update available actions when selection change
8912
+ })), [getItemListOrSelected, itemTemplates]); // Update available actions when selection change
8810
8913
 
8811
- React__default['default'].useEffect(function () {
8812
- updateAvailableActions();
8813
- }, [updateAvailableActions, selected]);
8914
+ React__default['default'].useEffect(updateAvailableActions, [updateAvailableActions, selected]); // Debounced update available actions when items change
8915
+
8916
+ useDebouncedEffect(updateAvailableActions, [itemMap, updateAvailableActions], 300);
8814
8917
  return {
8815
8918
  availableActions: availableActions
8816
8919
  };
@@ -9395,7 +9498,11 @@ var SyncBoard = function SyncBoard(_ref) {
9395
9498
  });
9396
9499
  }, [setConfiguration, uid]);
9397
9500
  useResizeObserver(boardWrapperRef, function () {
9398
- return setConfiguration(function (prev) {
9501
+ if (!boardWrapperRef.current) {
9502
+ return;
9503
+ }
9504
+
9505
+ setConfiguration(function (prev) {
9399
9506
  return _objectSpread2(_objectSpread2({}, prev), {}, {
9400
9507
  boardWrapperRect: boardWrapperRef.current.getBoundingClientRect()
9401
9508
  });
@@ -9470,6 +9577,7 @@ exports.useAvailableActions = useAvailableActions;
9470
9577
  exports.useBoardConfig = useBoardConfig;
9471
9578
  exports.useBoardPosition = useDim;
9472
9579
  exports.useBoardState = useBoardState;
9580
+ exports.useDebouncedItems = useDebouncedItems;
9473
9581
  exports.useItemActions = useItemActions;
9474
9582
  exports.useItemInteraction = useItemInteraction;
9475
9583
  exports.useItems = useItemList;