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/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import React__default, { forwardRef, useContext, createContext, createElement, Fragment, useRef, useLayoutEffect, useEffect, useMemo, memo } from 'react';
2
+ import React__default, { forwardRef, useContext, createContext, createElement, Fragment, useRef, useLayoutEffect, useEffect, useMemo, memo, useCallback } from 'react';
3
3
  import { atom, selector, useRecoilValue, useRecoilCallback, useRecoilState, useSetRecoilState, RecoilRoot } from 'recoil';
4
4
 
5
5
  function ownKeys(object, enumerableOnly) {
@@ -4110,10 +4110,6 @@ var useItemList = function useItemList() {
4110
4110
  return items;
4111
4111
  };
4112
4112
 
4113
- var useSelectedItems = function useSelectedItems() {
4114
- return useRecoilValue(SelectedItemsAtom);
4115
- };
4116
-
4117
4113
  /**
4118
4114
  * Run effect only when component is unmounted.
4119
4115
  *
@@ -4301,6 +4297,28 @@ function useThrottledCallback(callback, deps, delay, noTrailing) {
4301
4297
  }, __spreadArray([delay, noTrailing], deps, true));
4302
4298
  }
4303
4299
 
4300
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4301
+ /**
4302
+ * Like `useEffect`, but passed function is debounced.
4303
+ *
4304
+ * @param callback Callback like for `useEffect`, but without ability to return
4305
+ * a cleanup function.
4306
+ * @param deps Dependencies list that will be passed to underlying `useEffect`
4307
+ * and `useDebouncedCallback`.
4308
+ * @param delay Debounce delay.
4309
+ * @param maxWait Maximum amount of milliseconds that function can be delayed
4310
+ * before it's force execution. 0 means no max wait.
4311
+ */
4312
+
4313
+ function useDebouncedEffect(callback, deps, delay, maxWait) {
4314
+ if (maxWait === void 0) {
4315
+ maxWait = 0;
4316
+ } // eslint-disable-next-line react-hooks/exhaustive-deps
4317
+
4318
+
4319
+ useEffect(useDebouncedCallback(callback, deps, delay, maxWait), deps);
4320
+ }
4321
+
4304
4322
  /* eslint-disable @typescript-eslint/no-explicit-any */
4305
4323
  /**
4306
4324
  * Like `useEffect`, but passed function is throttled.
@@ -4445,6 +4463,45 @@ function useResizeObserver(target, callback, enabled) {
4445
4463
  }, [target, ro]);
4446
4464
  }
4447
4465
 
4466
+ var useDebouncedItems = function useDebouncedItems() {
4467
+ var items = useRecoilValue(AllItemsSelector);
4468
+
4469
+ var _React$useState = React__default.useState(items),
4470
+ _React$useState2 = _slicedToArray(_React$useState, 2),
4471
+ debouncedItems = _React$useState2[0],
4472
+ setDebouncedItems = _React$useState2[1];
4473
+
4474
+ var updateDebouncedItems = useRecoilCallback(function (_ref) {
4475
+ var snapshot = _ref.snapshot;
4476
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
4477
+ var currentItemMap;
4478
+ return regeneratorRuntime.wrap(function _callee$(_context) {
4479
+ while (1) {
4480
+ switch (_context.prev = _context.next) {
4481
+ case 0:
4482
+ _context.next = 2;
4483
+ return snapshot.getPromise(AllItemsSelector);
4484
+
4485
+ case 2:
4486
+ currentItemMap = _context.sent;
4487
+ setDebouncedItems(currentItemMap);
4488
+
4489
+ case 4:
4490
+ case "end":
4491
+ return _context.stop();
4492
+ }
4493
+ }
4494
+ }, _callee);
4495
+ }));
4496
+ }, []);
4497
+ useDebouncedEffect(updateDebouncedItems, [items], 300);
4498
+ return debouncedItems;
4499
+ };
4500
+
4501
+ var useSelectedItems = function useSelectedItems() {
4502
+ return useRecoilValue(SelectedItemsAtom);
4503
+ };
4504
+
4448
4505
  var isMacOS = function isMacOS() {
4449
4506
  var userAgent = navigator.userAgent.toLowerCase();
4450
4507
  return /mac os ?x 10/.test(userAgent);
@@ -4539,7 +4596,9 @@ var Gesture = function Gesture(_ref6) {
4539
4596
  onLongTap = _ref6$onLongTap === void 0 ? empty : _ref6$onLongTap,
4540
4597
  _ref6$onDoubleTap = _ref6.onDoubleTap,
4541
4598
  onDoubleTap = _ref6$onDoubleTap === void 0 ? empty : _ref6$onDoubleTap,
4542
- onZoom = _ref6.onZoom;
4599
+ onZoom = _ref6.onZoom,
4600
+ _ref6$mainAction = _ref6.mainAction,
4601
+ mainAction = _ref6$mainAction === void 0 ? "drag" : _ref6$mainAction;
4543
4602
  var wrapperRef = React__default.useRef(null);
4544
4603
  var stateRef = React__default.useRef({
4545
4604
  moving: false,
@@ -4747,6 +4806,7 @@ var Gesture = function Gesture(_ref6) {
4747
4806
  altKey = e.altKey,
4748
4807
  ctrlKey = e.ctrlKey,
4749
4808
  metaKey = e.metaKey,
4809
+ buttons = e.buttons,
4750
4810
  pointerType = e.pointerType;
4751
4811
 
4752
4812
  if (stateRef.current.mainPointer !== pointerId) {
@@ -4780,13 +4840,20 @@ var Gesture = function Gesture(_ref6) {
4780
4840
  clientY = eventClientY;
4781
4841
  } // We drag if
4782
4842
  // On non touch device
4783
- // - Button is 0
4784
- // - Alt key is no pressed
4843
+ // - Only button is pressed (1)
4844
+ // - any special key is no pressed
4785
4845
  // or on touch devices
4786
4846
  // - We use only one finger
4787
4847
 
4788
4848
 
4789
- var shouldDrag = pointerType !== "touch" ? stateRef.current.currentButton === 0 && !altKey : !twoFingers;
4849
+ var altAction = altKey || ctrlKey || metaKey || buttons !== 1;
4850
+
4851
+ if (mainAction !== "drag") {
4852
+ altAction = !altAction;
4853
+ }
4854
+
4855
+ var shouldDrag = pointerType !== "touch" ? !altAction : !twoFingers;
4856
+ var shouldPan = pointerType !== "touch" ? altAction : twoFingers;
4790
4857
 
4791
4858
  if (shouldDrag) {
4792
4859
  // Send drag start on first move
@@ -4835,7 +4902,9 @@ var Gesture = function Gesture(_ref6) {
4835
4902
  target: stateRef.current.target,
4836
4903
  event: e
4837
4904
  });
4838
- } else {
4905
+ }
4906
+
4907
+ if (shouldPan) {
4839
4908
  if (!stateRef.current.gestureStart) {
4840
4909
  wrapperRef.current.style.cursor = "move";
4841
4910
  stateRef.current.gestureStart = true; // Clear tap timeout on first move
@@ -4879,7 +4948,7 @@ var Gesture = function Gesture(_ref6) {
4879
4948
  stateRef.current.prevX = clientX;
4880
4949
  stateRef.current.prevY = clientY;
4881
4950
  }
4882
- }, [onDrag, onDragStart, onPan, onZoom, queue]);
4951
+ }, [mainAction, onDrag, onDragStart, onPan, onZoom, queue]);
4883
4952
  var onPointerUp = React__default.useCallback(function (e) {
4884
4953
  var clientX = e.clientX,
4885
4954
  clientY = e.clientY,
@@ -5033,7 +5102,7 @@ var _excluded$2 = ["type", "rotation", "id", "locked", "layer"],
5033
5102
  _excluded3 = ["x", "y", "layer", "moving"];
5034
5103
 
5035
5104
  var _templateObject$2;
5036
- 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) {
5105
+ 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) {
5037
5106
  var rotation = _ref.rotation;
5038
5107
  return rotation;
5039
5108
  }, img);
@@ -5287,6 +5356,8 @@ var Item = function Item(_ref5) {
5287
5356
  className: "corner bottom-right"
5288
5357
  }), /*#__PURE__*/React__default.createElement("div", {
5289
5358
  className: "corner bottom-left"
5359
+ }), /*#__PURE__*/React__default.createElement("div", {
5360
+ className: "center"
5290
5361
  }), isSelected && showResizeHandle && /*#__PURE__*/React__default.createElement(React__default.Fragment, null, resizeDirections.b && /*#__PURE__*/React__default.createElement(ResizeHandler, {
5291
5362
  className: "resize resize-ratio",
5292
5363
  onResize: onResizeRatio
@@ -5319,8 +5390,6 @@ var PositionedItem = function PositionedItem(_ref12) {
5319
5390
  rest = _objectWithoutProperties(_ref12, _excluded2);
5320
5391
 
5321
5392
  if (!rest.itemMap[state.type]) {
5322
- // eslint-disable-next-line no-console
5323
- console.warn("Item type ".concat(state.type, " not recognized!"));
5324
5393
  return null;
5325
5394
  }
5326
5395
 
@@ -5854,24 +5923,20 @@ var Selector = function Selector(_ref) {
5854
5923
  }));
5855
5924
  }, [setSelected]);
5856
5925
  useThrottledEffect(updateSelected, [selector, updateSelected], 200);
5857
-
5858
- var onDragStart = /*#__PURE__*/function () {
5926
+ var onDragStart = React__default.useCallback( /*#__PURE__*/function () {
5859
5927
  var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(event) {
5860
- var button, altKey, ctrlKey, metaKey, foundElement, metaKeyPressed, goodButton;
5928
+ var foundElement;
5861
5929
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
5862
5930
  while (1) {
5863
5931
  switch (_context2.prev = _context2.next) {
5864
5932
  case 0:
5865
- button = event.button, altKey = event.altKey, ctrlKey = event.ctrlKey, metaKey = event.metaKey;
5866
- _context2.next = 3;
5933
+ _context2.next = 2;
5867
5934
  return findElementUnderPointer(event);
5868
5935
 
5869
- case 3:
5936
+ case 2:
5870
5937
  foundElement = _context2.sent;
5871
- metaKeyPressed = altKey || ctrlKey || metaKey;
5872
- goodButton = moveFirst ? button === 1 || button === 0 && metaKeyPressed : button === 0 && !metaKeyPressed;
5873
5938
 
5874
- if (goodButton && (!foundElement || moveFirst)) {
5939
+ if (!foundElement) {
5875
5940
  stateRef.current.moving = true;
5876
5941
  setBoardState(function (prev) {
5877
5942
  return _objectSpread2(_objectSpread2({}, prev), {}, {
@@ -5881,7 +5946,7 @@ var Selector = function Selector(_ref) {
5881
5946
  wrapperRef.current.style.cursor = "crosshair";
5882
5947
  }
5883
5948
 
5884
- case 7:
5949
+ case 4:
5885
5950
  case "end":
5886
5951
  return _context2.stop();
5887
5952
  }
@@ -5889,11 +5954,10 @@ var Selector = function Selector(_ref) {
5889
5954
  }, _callee2);
5890
5955
  }));
5891
5956
 
5892
- return function onDragStart(_x) {
5957
+ return function (_x) {
5893
5958
  return _ref4.apply(this, arguments);
5894
5959
  };
5895
- }();
5896
-
5960
+ }(), [findElementUnderPointer, setBoardState]);
5897
5961
  var onDrag = useRecoilCallback(function (_ref5) {
5898
5962
  var snapshot = _ref5.snapshot;
5899
5963
  return /*#__PURE__*/function () {
@@ -5956,8 +6020,7 @@ var Selector = function Selector(_ref) {
5956
6020
  };
5957
6021
  }();
5958
6022
  }, []);
5959
-
5960
- var onDragEnd = function onDragEnd() {
6023
+ var onDragEnd = React__default.useCallback(function () {
5961
6024
  if (stateRef.current.moving) {
5962
6025
  setBoardState(function (prev) {
5963
6026
  return _objectSpread2(_objectSpread2({}, prev), {}, {
@@ -5970,8 +6033,7 @@ var Selector = function Selector(_ref) {
5970
6033
  });
5971
6034
  wrapperRef.current.style.cursor = "auto";
5972
6035
  }
5973
- };
5974
-
6036
+ }, [setBoardState]);
5975
6037
  var onLongTap = React__default.useCallback(function (_ref8) {
5976
6038
  var target = _ref8.target;
5977
6039
  var foundElement = insideClass(target, "item");
@@ -6052,7 +6114,8 @@ var Selector = function Selector(_ref) {
6052
6114
  onDrag: onDrag,
6053
6115
  onDragEnd: onDragEnd,
6054
6116
  onTap: onTap,
6055
- onLongTap: onLongTap
6117
+ onLongTap: onLongTap,
6118
+ mainAction: moveFirst ? "pan" : "drag"
6056
6119
  }, /*#__PURE__*/React__default.createElement("div", {
6057
6120
  ref: wrapperRef
6058
6121
  }, selector.moving && /*#__PURE__*/React__default.createElement("div", {
@@ -6067,6 +6130,7 @@ var Selector = function Selector(_ref) {
6067
6130
 
6068
6131
  var ActionPane = function ActionPane(_ref) {
6069
6132
  var children = _ref.children;
6133
+ _ref.moveFirst;
6070
6134
 
6071
6135
  var _useItemActions = useItemActions(),
6072
6136
  moveItems = _useItemActions.moveItems,
@@ -6901,8 +6965,6 @@ var usePositionNavigator = function usePositionNavigator() {
6901
6965
  return null;
6902
6966
  };
6903
6967
 
6904
- var SCALE_TOLERANCE = 0.8;
6905
-
6906
6968
  var PanZoom = function PanZoom(_ref) {
6907
6969
  var children = _ref.children,
6908
6970
  _ref$moveFirst = _ref.moveFirst,
@@ -6912,7 +6974,8 @@ var PanZoom = function PanZoom(_ref) {
6912
6974
 
6913
6975
  var _useDim = useDim(),
6914
6976
  setDim = _useDim.setDim,
6915
- zoomTo = _useDim.zoomTo;
6977
+ zoomToCenter = _useDim.zoomToCenter,
6978
+ zoomToExtent = _useDim.zoomToExtent;
6916
6979
 
6917
6980
  var _useRecoilValue = useRecoilValue(ConfigurationAtom),
6918
6981
  itemExtentGlobal = _useRecoilValue.itemExtent;
@@ -6928,10 +6991,14 @@ var PanZoom = function PanZoom(_ref) {
6928
6991
  var getMouseInfo = useMousePosition(wrappedRef); // Hooks to save/restore position
6929
6992
 
6930
6993
  usePositionNavigator();
6994
+ /**
6995
+ * Center board on startup
6996
+ */
6997
+
6931
6998
  var centerBoard = useRecoilCallback(function (_ref2) {
6932
6999
  var snapshot = _ref2.snapshot;
6933
7000
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
6934
- var _yield$snapshot$getPr, _yield$snapshot$getPr2, left, top, width, height, boardWrapperRect, scaleX, scaleY, newScale, scaleWithTolerance, centerX, centerY;
7001
+ var _yield$snapshot$getPr, itemExtent;
6935
7002
 
6936
7003
  return regeneratorRuntime.wrap(function _callee$(_context) {
6937
7004
  while (1) {
@@ -6942,34 +7009,17 @@ var PanZoom = function PanZoom(_ref) {
6942
7009
 
6943
7010
  case 2:
6944
7011
  _yield$snapshot$getPr = _context.sent;
6945
- _yield$snapshot$getPr2 = _yield$snapshot$getPr.itemExtent;
6946
- left = _yield$snapshot$getPr2.left;
6947
- top = _yield$snapshot$getPr2.top;
6948
- width = _yield$snapshot$getPr2.width;
6949
- height = _yield$snapshot$getPr2.height;
6950
- boardWrapperRect = _yield$snapshot$getPr.boardWrapperRect;
6951
- scaleX = boardWrapperRect.width / width;
6952
- scaleY = boardWrapperRect.height / height;
6953
- newScale = Math.min(scaleX, scaleY);
6954
- scaleWithTolerance = newScale * SCALE_TOLERANCE;
6955
- centerX = boardWrapperRect.width / 2 - (left + width / 2) * scaleWithTolerance;
6956
- centerY = boardWrapperRect.height / 2 - (top + height / 2) * scaleWithTolerance;
6957
- setDim(function (prev) {
6958
- return _objectSpread2(_objectSpread2({}, prev), {}, {
6959
- translateX: centerX,
6960
- translateY: centerY,
6961
- scale: scaleWithTolerance
6962
- });
6963
- });
7012
+ itemExtent = _yield$snapshot$getPr.itemExtent;
7013
+ zoomToExtent(itemExtent);
6964
7014
 
6965
- case 16:
7015
+ case 5:
6966
7016
  case "end":
6967
7017
  return _context.stop();
6968
7018
  }
6969
7019
  }
6970
7020
  }, _callee);
6971
7021
  }));
6972
- }, [setDim]);
7022
+ }, [zoomToExtent]);
6973
7023
  React__default.useEffect(function () {
6974
7024
  if (!centered && itemExtentGlobal.left) {
6975
7025
  // Center board on first valid extent
@@ -6981,7 +7031,7 @@ var PanZoom = function PanZoom(_ref) {
6981
7031
  var clientX = _ref4.clientX,
6982
7032
  clientY = _ref4.clientY,
6983
7033
  scale = _ref4.scale;
6984
- zoomTo(1 - scale / 500, {
7034
+ zoomToCenter(1 - scale / 500, {
6985
7035
  x: clientX,
6986
7036
  y: clientY
6987
7037
  }); // Update the board zooming state
@@ -6999,15 +7049,25 @@ var PanZoom = function PanZoom(_ref) {
6999
7049
  zooming: true
7000
7050
  }) : prev;
7001
7051
  });
7002
- }, [setBoardState, zoomTo]);
7052
+ }, [setBoardState, zoomToCenter]);
7003
7053
  var onPan = React__default.useCallback( /*#__PURE__*/function () {
7004
7054
  var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref5) {
7005
- var deltaX, deltaY;
7055
+ var deltaX, deltaY, target, insideItem;
7006
7056
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
7007
7057
  while (1) {
7008
7058
  switch (_context2.prev = _context2.next) {
7009
7059
  case 0:
7010
- deltaX = _ref5.deltaX, deltaY = _ref5.deltaY;
7060
+ deltaX = _ref5.deltaX, deltaY = _ref5.deltaY, target = _ref5.target;
7061
+ insideItem = insideClass(target, "item") && !insideClass(target, "locked");
7062
+
7063
+ if (!(insideItem && moveFirst)) {
7064
+ _context2.next = 4;
7065
+ break;
7066
+ }
7067
+
7068
+ return _context2.abrupt("return");
7069
+
7070
+ case 4:
7011
7071
  setDim(function (prev) {
7012
7072
  return _objectSpread2(_objectSpread2({}, prev), {}, {
7013
7073
  translateX: prev.translateX + deltaX,
@@ -7029,7 +7089,7 @@ var PanZoom = function PanZoom(_ref) {
7029
7089
  }) : prev;
7030
7090
  });
7031
7091
 
7032
- case 5:
7092
+ case 8:
7033
7093
  case "end":
7034
7094
  return _context2.stop();
7035
7095
  }
@@ -7040,15 +7100,7 @@ var PanZoom = function PanZoom(_ref) {
7040
7100
  return function (_x) {
7041
7101
  return _ref6.apply(this, arguments);
7042
7102
  };
7043
- }(), [setBoardState, setDim]);
7044
- var onDrag = React__default.useCallback(function (state) {
7045
- var target = state.target;
7046
- var outsideItem = !insideClass(target, "item") || insideClass(target, "locked");
7047
-
7048
- if (moveFirst && outsideItem) {
7049
- onPan(state);
7050
- }
7051
- }, [moveFirst, onPan]);
7103
+ }(), [moveFirst, setBoardState, setDim]);
7052
7104
  var onKeyDown = useRecoilCallback(function (_ref7) {
7053
7105
  var snapshot = _ref7.snapshot;
7054
7106
  return /*#__PURE__*/function () {
@@ -7133,14 +7185,14 @@ var PanZoom = function PanZoom(_ref) {
7133
7185
  translateX: prev.translateX + moveX
7134
7186
  });
7135
7187
  });
7136
- zoomTo(zoom);
7188
+ zoomToCenter(zoom);
7137
7189
  e.preventDefault();
7138
7190
 
7139
7191
  case 31:
7140
7192
  // Temporary zoom
7141
7193
  if (e.key === " " && !e.repeat) {
7142
7194
  if (getMouseInfo().hover) {
7143
- zoomTo(3, getMouseInfo());
7195
+ zoomToCenter(3, getMouseInfo());
7144
7196
  }
7145
7197
  }
7146
7198
 
@@ -7156,15 +7208,15 @@ var PanZoom = function PanZoom(_ref) {
7156
7208
  return _ref8.apply(this, arguments);
7157
7209
  };
7158
7210
  }();
7159
- }, [setDim, zoomTo, getMouseInfo]);
7211
+ }, [setDim, zoomToCenter, getMouseInfo]);
7160
7212
  var onKeyUp = React__default.useCallback(function (e) {
7161
7213
  // Ignore text in Input or Textarea
7162
7214
  if (["INPUT", "TEXTAREA"].includes(e.target.tagName)) return; // Zoom out on release
7163
7215
 
7164
7216
  if (e.key === " " && getMouseInfo().hover) {
7165
- zoomTo(1 / 3, getMouseInfo());
7217
+ zoomToCenter(1 / 3, getMouseInfo());
7166
7218
  }
7167
- }, [getMouseInfo, zoomTo]);
7219
+ }, [getMouseInfo, zoomToCenter]);
7168
7220
  React__default.useEffect(function () {
7169
7221
  document.addEventListener("keydown", onKeyDown);
7170
7222
  document.addEventListener("keyup", onKeyUp);
@@ -7176,7 +7228,7 @@ var PanZoom = function PanZoom(_ref) {
7176
7228
  return /*#__PURE__*/React__default.createElement(Gesture, {
7177
7229
  onPan: onPan,
7178
7230
  onZoom: onZoom,
7179
- onDrag: onDrag
7231
+ mainAction: moveFirst ? "pan" : "drag"
7180
7232
  }, /*#__PURE__*/React__default.createElement("div", {
7181
7233
  style: {
7182
7234
  display: "inline-block",
@@ -7344,7 +7396,9 @@ var Board = function Board(_ref) {
7344
7396
  moveFirst: moveFirst
7345
7397
  }, /*#__PURE__*/React__default.createElement(Selector, {
7346
7398
  moveFirst: moveFirst
7347
- }, /*#__PURE__*/React__default.createElement(ActionPane, null, /*#__PURE__*/React__default.createElement(CursorPane, null, /*#__PURE__*/React__default.createElement("div", {
7399
+ }, /*#__PURE__*/React__default.createElement(ActionPane, {
7400
+ moveFirst: moveFirst
7401
+ }, /*#__PURE__*/React__default.createElement(CursorPane, null, /*#__PURE__*/React__default.createElement("div", {
7348
7402
  onContextMenu: function onContextMenu(e) {
7349
7403
  e.preventDefault();
7350
7404
  },
@@ -7355,6 +7409,7 @@ var Board = function Board(_ref) {
7355
7409
 
7356
7410
  var TOLERANCE = 100;
7357
7411
  var MIN_SIZE = 1000;
7412
+ var SCALE_TOLERANCE = 0.8;
7358
7413
 
7359
7414
  var translateBoundaries = function translateBoundaries(_ref) {
7360
7415
  var x = _ref.x,
@@ -7472,7 +7527,7 @@ var useDim = function useDim() {
7472
7527
  };
7473
7528
  }();
7474
7529
  }, [setDim]);
7475
- var zoomTo = useRecoilCallback(function (_ref5) {
7530
+ var zoomToCenter = useRecoilCallback(function (_ref5) {
7476
7531
  var snapshot = _ref5.snapshot;
7477
7532
  return /*#__PURE__*/function () {
7478
7533
  var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(factor, zoomCenter) {
@@ -7551,24 +7606,68 @@ var useDim = function useDim() {
7551
7606
  };
7552
7607
  }();
7553
7608
  }, [setDim]);
7554
- var updateScaleBoundaries = useRecoilCallback(function (_ref7) {
7609
+ var zoomToExtent = useRecoilCallback(function (_ref7) {
7555
7610
  var snapshot = _ref7.snapshot;
7556
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
7557
- var _yield$snapshot$getPr3, _yield$snapshot$getPr4, width, height, boardWrapperRect, scaleX, scaleY, newScale;
7611
+ return /*#__PURE__*/function () {
7612
+ var _ref9 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref8) {
7613
+ var left, top, width, height, _yield$snapshot$getPr3, boardWrapperRect, scaleX, scaleY, newScale, scaleWithTolerance, centerX, centerY;
7558
7614
 
7559
- return regeneratorRuntime.wrap(function _callee3$(_context3) {
7615
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
7616
+ while (1) {
7617
+ switch (_context3.prev = _context3.next) {
7618
+ case 0:
7619
+ left = _ref8.left, top = _ref8.top, width = _ref8.width, height = _ref8.height;
7620
+ _context3.next = 3;
7621
+ return snapshot.getPromise(ConfigurationAtom);
7622
+
7623
+ case 3:
7624
+ _yield$snapshot$getPr3 = _context3.sent;
7625
+ boardWrapperRect = _yield$snapshot$getPr3.boardWrapperRect;
7626
+ scaleX = boardWrapperRect.width / width;
7627
+ scaleY = boardWrapperRect.height / height;
7628
+ newScale = Math.min(scaleX, scaleY);
7629
+ scaleWithTolerance = newScale * SCALE_TOLERANCE;
7630
+ centerX = boardWrapperRect.width / 2 - (left + width / 2) * scaleWithTolerance;
7631
+ centerY = boardWrapperRect.height / 2 - (top + height / 2) * scaleWithTolerance;
7632
+ setDim(function (prev) {
7633
+ return _objectSpread2(_objectSpread2({}, prev), {}, {
7634
+ translateX: centerX,
7635
+ translateY: centerY,
7636
+ scale: scaleWithTolerance
7637
+ });
7638
+ });
7639
+
7640
+ case 12:
7641
+ case "end":
7642
+ return _context3.stop();
7643
+ }
7644
+ }
7645
+ }, _callee3);
7646
+ }));
7647
+
7648
+ return function (_x4) {
7649
+ return _ref9.apply(this, arguments);
7650
+ };
7651
+ }();
7652
+ }, [setDim]);
7653
+ var updateScaleBoundaries = useRecoilCallback(function (_ref10) {
7654
+ var snapshot = _ref10.snapshot;
7655
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
7656
+ var _yield$snapshot$getPr4, _yield$snapshot$getPr5, width, height, boardWrapperRect, scaleX, scaleY, newScale;
7657
+
7658
+ return regeneratorRuntime.wrap(function _callee4$(_context4) {
7560
7659
  while (1) {
7561
- switch (_context3.prev = _context3.next) {
7660
+ switch (_context4.prev = _context4.next) {
7562
7661
  case 0:
7563
- _context3.next = 2;
7662
+ _context4.next = 2;
7564
7663
  return snapshot.getPromise(ConfigurationAtom);
7565
7664
 
7566
7665
  case 2:
7567
- _yield$snapshot$getPr3 = _context3.sent;
7568
- _yield$snapshot$getPr4 = _yield$snapshot$getPr3.itemExtent;
7569
- width = _yield$snapshot$getPr4.width;
7570
- height = _yield$snapshot$getPr4.height;
7571
- boardWrapperRect = _yield$snapshot$getPr3.boardWrapperRect;
7666
+ _yield$snapshot$getPr4 = _context4.sent;
7667
+ _yield$snapshot$getPr5 = _yield$snapshot$getPr4.itemExtent;
7668
+ width = _yield$snapshot$getPr5.width;
7669
+ height = _yield$snapshot$getPr5.height;
7670
+ boardWrapperRect = _yield$snapshot$getPr4.boardWrapperRect;
7572
7671
  scaleX = boardWrapperRect.width / width;
7573
7672
  scaleY = boardWrapperRect.height / height;
7574
7673
  newScale = Math.min(scaleX, scaleY);
@@ -7576,86 +7675,86 @@ var useDim = function useDim() {
7576
7675
 
7577
7676
  case 11:
7578
7677
  case "end":
7579
- return _context3.stop();
7678
+ return _context4.stop();
7580
7679
  }
7581
7680
  }
7582
- }, _callee3);
7681
+ }, _callee4);
7583
7682
  }));
7584
7683
  }, []);
7585
- var getCenterCoordinates = useRecoilCallback(function (_ref9) {
7586
- var snapshot = _ref9.snapshot;
7587
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
7588
- var _yield$snapshot$getPr5, boardWrapperRect, boardSize, _yield$snapshot$getPr6, translateX, translateY, scale;
7684
+ var getCenterCoordinates = useRecoilCallback(function (_ref12) {
7685
+ var snapshot = _ref12.snapshot;
7686
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
7687
+ var _yield$snapshot$getPr6, boardWrapperRect, boardSize, _yield$snapshot$getPr7, translateX, translateY, scale;
7589
7688
 
7590
- return regeneratorRuntime.wrap(function _callee4$(_context4) {
7689
+ return regeneratorRuntime.wrap(function _callee5$(_context5) {
7591
7690
  while (1) {
7592
- switch (_context4.prev = _context4.next) {
7691
+ switch (_context5.prev = _context5.next) {
7593
7692
  case 0:
7594
- _context4.next = 2;
7693
+ _context5.next = 2;
7595
7694
  return snapshot.getPromise(ConfigurationAtom);
7596
7695
 
7597
7696
  case 2:
7598
- _yield$snapshot$getPr5 = _context4.sent;
7599
- boardWrapperRect = _yield$snapshot$getPr5.boardWrapperRect;
7600
- boardSize = _yield$snapshot$getPr5.boardSize;
7601
- _context4.next = 7;
7697
+ _yield$snapshot$getPr6 = _context5.sent;
7698
+ boardWrapperRect = _yield$snapshot$getPr6.boardWrapperRect;
7699
+ boardSize = _yield$snapshot$getPr6.boardSize;
7700
+ _context5.next = 7;
7602
7701
  return snapshot.getPromise(BoardTransformAtom);
7603
7702
 
7604
7703
  case 7:
7605
- _yield$snapshot$getPr6 = _context4.sent;
7606
- translateX = _yield$snapshot$getPr6.translateX;
7607
- translateY = _yield$snapshot$getPr6.translateY;
7608
- scale = _yield$snapshot$getPr6.scale;
7609
- return _context4.abrupt("return", {
7704
+ _yield$snapshot$getPr7 = _context5.sent;
7705
+ translateX = _yield$snapshot$getPr7.translateX;
7706
+ translateY = _yield$snapshot$getPr7.translateY;
7707
+ scale = _yield$snapshot$getPr7.scale;
7708
+ return _context5.abrupt("return", {
7610
7709
  x: (boardWrapperRect.width / 2 - translateX) / scale - boardSize / 2,
7611
7710
  y: (boardWrapperRect.height / 2 - translateY) / scale - boardSize / 2
7612
7711
  });
7613
7712
 
7614
7713
  case 12:
7615
7714
  case "end":
7616
- return _context4.stop();
7715
+ return _context5.stop();
7617
7716
  }
7618
7717
  }
7619
- }, _callee4);
7718
+ }, _callee5);
7620
7719
  }));
7621
7720
  }, []);
7622
- var updateItemExtent = useRecoilCallback(function (_ref11) {
7623
- var snapshot = _ref11.snapshot,
7624
- set = _ref11.set;
7625
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
7626
- var itemIds, _yield$snapshot$getPr7, boardWrapperRect, boardWrapper, boardSize, _yield$snapshot$getPr8, scale, translateX, translateY, _ref13, left, top, width, height, relativeExtent, delta, _delta;
7721
+ var updateItemExtent = useRecoilCallback(function (_ref14) {
7722
+ var snapshot = _ref14.snapshot,
7723
+ set = _ref14.set;
7724
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {
7725
+ var itemIds, _yield$snapshot$getPr8, boardWrapperRect, boardWrapper, boardSize, _yield$snapshot$getPr9, scale, translateX, translateY, _ref16, left, top, width, height, relativeExtent, delta, _delta;
7627
7726
 
7628
- return regeneratorRuntime.wrap(function _callee5$(_context5) {
7727
+ return regeneratorRuntime.wrap(function _callee6$(_context6) {
7629
7728
  while (1) {
7630
- switch (_context5.prev = _context5.next) {
7729
+ switch (_context6.prev = _context6.next) {
7631
7730
  case 0:
7632
- _context5.next = 2;
7731
+ _context6.next = 2;
7633
7732
  return snapshot.getPromise(ItemListAtom);
7634
7733
 
7635
7734
  case 2:
7636
- itemIds = _context5.sent;
7637
- _context5.next = 5;
7735
+ itemIds = _context6.sent;
7736
+ _context6.next = 5;
7638
7737
  return snapshot.getPromise(ConfigurationAtom);
7639
7738
 
7640
7739
  case 5:
7641
- _yield$snapshot$getPr7 = _context5.sent;
7642
- boardWrapperRect = _yield$snapshot$getPr7.boardWrapperRect;
7643
- boardWrapper = _yield$snapshot$getPr7.boardWrapper;
7644
- boardSize = _yield$snapshot$getPr7.boardSize;
7645
- _context5.next = 11;
7740
+ _yield$snapshot$getPr8 = _context6.sent;
7741
+ boardWrapperRect = _yield$snapshot$getPr8.boardWrapperRect;
7742
+ boardWrapper = _yield$snapshot$getPr8.boardWrapper;
7743
+ boardSize = _yield$snapshot$getPr8.boardSize;
7744
+ _context6.next = 11;
7646
7745
  return snapshot.getPromise(BoardTransformAtom);
7647
7746
 
7648
7747
  case 11:
7649
- _yield$snapshot$getPr8 = _context5.sent;
7650
- scale = _yield$snapshot$getPr8.scale;
7651
- translateX = _yield$snapshot$getPr8.translateX;
7652
- translateY = _yield$snapshot$getPr8.translateY;
7653
- _ref13 = getItemBoundingBox(itemIds, boardWrapper) || {
7748
+ _yield$snapshot$getPr9 = _context6.sent;
7749
+ scale = _yield$snapshot$getPr9.scale;
7750
+ translateX = _yield$snapshot$getPr9.translateX;
7751
+ translateY = _yield$snapshot$getPr9.translateY;
7752
+ _ref16 = getItemBoundingBox(itemIds, boardWrapper) || {
7654
7753
  left: boardSize / 2 * scale + boardWrapperRect.left + translateX,
7655
7754
  top: boardSize / 2 * scale + boardWrapperRect.top + translateY,
7656
7755
  width: 0,
7657
7756
  height: 0
7658
- }, left = _ref13.left, top = _ref13.top, width = _ref13.width, height = _ref13.height;
7757
+ }, left = _ref16.left, top = _ref16.top, width = _ref16.width, height = _ref16.height;
7659
7758
  relativeExtent = {
7660
7759
  left: (left - boardWrapperRect.left - translateX) / scale,
7661
7760
  top: (top - boardWrapperRect.top - translateY) / scale,
@@ -7687,10 +7786,10 @@ var useDim = function useDim() {
7687
7786
 
7688
7787
  case 22:
7689
7788
  case "end":
7690
- return _context5.stop();
7789
+ return _context6.stop();
7691
7790
  }
7692
7791
  }
7693
- }, _callee5);
7792
+ }, _callee6);
7694
7793
  }));
7695
7794
  }, []);
7696
7795
  var debouncedUpdateItemExtent = useDebouncedCallback(updateItemExtent, [], 300);
@@ -7702,7 +7801,9 @@ var useDim = function useDim() {
7702
7801
  return {
7703
7802
  setDim: setDimSafe,
7704
7803
  getDim: getDim,
7705
- zoomTo: zoomTo,
7804
+ zoomTo: zoomToCenter,
7805
+ zoomToCenter: zoomToCenter,
7806
+ zoomToExtent: zoomToExtent,
7706
7807
  getCenter: getCenterCoordinates,
7707
7808
  updateItemExtent: debouncedUpdateItemExtent
7708
7809
  };
@@ -8658,8 +8759,10 @@ var getActionsFromItem = function getActionsFromItem(item, itemMap) {
8658
8759
  };
8659
8760
 
8660
8761
  var useAvailableActions = function useAvailableActions() {
8762
+ var itemMap = useRecoilValue(ItemMapAtom);
8763
+
8661
8764
  var _useRecoilValue = useRecoilValue(ConfigurationAtom),
8662
- itemMap = _useRecoilValue.itemTemplates;
8765
+ itemTemplates = _useRecoilValue.itemTemplates;
8663
8766
 
8664
8767
  var selected = useRecoilValue(SelectedItemsAtom);
8665
8768
 
@@ -8669,6 +8772,13 @@ var useAvailableActions = function useAvailableActions() {
8669
8772
  setAvailableActions = _React$useState2[1];
8670
8773
 
8671
8774
  var isMountedRef = React__default.useRef(false);
8775
+ React__default.useEffect(function () {
8776
+ // Mounted guard
8777
+ isMountedRef.current = true;
8778
+ return function () {
8779
+ isMountedRef.current = false;
8780
+ };
8781
+ }, []);
8672
8782
  var getItemListOrSelected = useRecoilCallback(function (_ref) {
8673
8783
  var snapshot = _ref.snapshot;
8674
8784
  return /*#__PURE__*/function () {
@@ -8716,19 +8826,12 @@ var useAvailableActions = function useAvailableActions() {
8716
8826
  };
8717
8827
  }();
8718
8828
  }, []);
8719
- React__default.useEffect(function () {
8720
- // Mounted guard
8721
- isMountedRef.current = true;
8722
- return function () {
8723
- isMountedRef.current = false;
8724
- };
8725
- }, []);
8726
8829
  /**
8727
8830
  * Returns available actions for selected items. An action is kept only if all
8728
8831
  * items have this exact same action with same parameters.
8729
8832
  */
8730
8833
 
8731
- var updateAvailableActions = React__default.useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
8834
+ var updateAvailableActions = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
8732
8835
  var _yield$getItemListOrS, _yield$getItemListOrS2, selectedItemIds, selectedItemList, allActions;
8733
8836
 
8734
8837
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
@@ -8758,13 +8861,13 @@ var useAvailableActions = function useAvailableActions() {
8758
8861
 
8759
8862
  case 9:
8760
8863
  allActions = selectedItemList.reduce(function (acc, item) {
8761
- var itemActions = getActionsFromItem(item, itemMap);
8864
+ var itemActions = getActionsFromItem(item, itemTemplates);
8762
8865
  return acc.filter(function (value) {
8763
8866
  return itemActions.some(function (itemAction) {
8764
8867
  return es6(value, itemAction);
8765
8868
  });
8766
8869
  });
8767
- }, getActionsFromItem(selectedItemList[0], itemMap));
8870
+ }, getActionsFromItem(selectedItemList[0], itemTemplates));
8768
8871
  setAvailableActions(allActions);
8769
8872
  _context2.next = 14;
8770
8873
  break;
@@ -8778,11 +8881,11 @@ var useAvailableActions = function useAvailableActions() {
8778
8881
  }
8779
8882
  }
8780
8883
  }, _callee2);
8781
- })), [getItemListOrSelected, itemMap]); // Update available actions when selection change
8884
+ })), [getItemListOrSelected, itemTemplates]); // Update available actions when selection change
8782
8885
 
8783
- React__default.useEffect(function () {
8784
- updateAvailableActions();
8785
- }, [updateAvailableActions, selected]);
8886
+ React__default.useEffect(updateAvailableActions, [updateAvailableActions, selected]); // Debounced update available actions when items change
8887
+
8888
+ useDebouncedEffect(updateAvailableActions, [itemMap, updateAvailableActions], 300);
8786
8889
  return {
8787
8890
  availableActions: availableActions
8788
8891
  };
@@ -9367,7 +9470,11 @@ var SyncBoard = function SyncBoard(_ref) {
9367
9470
  });
9368
9471
  }, [setConfiguration, uid]);
9369
9472
  useResizeObserver(boardWrapperRef, function () {
9370
- return setConfiguration(function (prev) {
9473
+ if (!boardWrapperRef.current) {
9474
+ return;
9475
+ }
9476
+
9477
+ setConfiguration(function (prev) {
9371
9478
  return _objectSpread2(_objectSpread2({}, prev), {}, {
9372
9479
  boardWrapperRect: boardWrapperRef.current.getBoundingClientRect()
9373
9480
  });
@@ -9435,5 +9542,5 @@ var ConnectedSyncRoom = function ConnectedSyncRoom(_ref) {
9435
9542
  }, /*#__PURE__*/React__default.createElement(SubscribeUserEvents, null), children));
9436
9543
  };
9437
9544
 
9438
- export { Board, ConnectedSyncBoard as BoardWrapper, ConnectedSyncRoom as RoomWrapper, useAvailableActions, useBoardConfig, useDim as useBoardPosition, useBoardState, useItemActions, useItemInteraction, useItemList as useItems, useMessage, useSelectedItems, useSelectionBox, useUsers, useWire };
9545
+ export { Board, ConnectedSyncBoard as BoardWrapper, ConnectedSyncRoom as RoomWrapper, useAvailableActions, useBoardConfig, useDim as useBoardPosition, useBoardState, useDebouncedItems, useItemActions, useItemInteraction, useItemList as useItems, useMessage, useSelectedItems, useSelectionBox, useUsers, useWire };
9439
9546
  //# sourceMappingURL=index.js.map