react-sync-board 0.4.5 → 0.5.2

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
@@ -4321,8 +4321,8 @@ function useResizeObserver(target, callback, enabled) {
4321
4321
  var img = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8' standalone='no'%3f%3e%3csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' version='1.1' x='0px' y='0px' viewBox='0 0 75.601318 94.9' xml:space='preserve' id='svg26' sodipodi:docname='lock.svg' width='75.601318' height='94.900002' inkscape:version='0.92.5 (2060ec1f9f%2c 2020-04-08)'%3e%3cmetadata id='metadata32'%3e%3crdf:RDF%3e%3ccc:Work rdf:about=''%3e%3cdc:format%3eimage/svg%2bxml%3c/dc:format%3e%3cdc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage' /%3e%3cdc:title%3e%3c/dc:title%3e%3c/cc:Work%3e%3c/rdf:RDF%3e%3c/metadata%3e%3cdefs id='defs30' /%3e%3csodipodi:namedview pagecolor='black' bordercolor='%23666666' borderopacity='1' objecttolerance='10' gridtolerance='10' guidetolerance='10' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:window-width='1848' inkscape:window-height='1016' id='namedview28' showgrid='false' fit-margin-top='0' fit-margin-left='0' fit-margin-right='0' fit-margin-bottom='0' inkscape:zoom='5.3400704' inkscape:cx='3.2640013' inkscape:cy='45.072152' inkscape:window-x='1512' inkscape:window-y='27' inkscape:window-maximized='1' inkscape:current-layer='g16' /%3e%3cg id='g16' transform='translate(-12.2%2c-2.5)'%3e%3cpath d='M 75.4%2c36.8 H 34.1 V 24.6 c 0%2c-8.8 7.1%2c-15.9 15.9%2c-15.9 8.8%2c0 15.9%2c7.1 15.9%2c15.9 0%2c1.7 1.4%2c3.1 3.1%2c3.1 1.7%2c0 3.1%2c-1.4 3.1%2c-3.1 C 72.1%2c12.4 62.2%2c2.5 50%2c2.5 37.8%2c2.5 27.9%2c12.4 27.9%2c24.6 v 12.2 h -3.3 c -6.9%2c0 -12.4%2c5.6 -12.4%2c12.4 V 85 c 0%2c6.9 5.6%2c12.4 12.4%2c12.4 h 50.8 c 6.9%2c0 12.4%2c-5.6 12.4%2c-12.4 V 49.2 C 87.9%2c42.3 82.3%2c36.8 75.4%2c36.8 Z m 6.2%2c48.3 c 0%2c3.4 -2.8%2c6.2 -6.2%2c6.2 H 24.6 c -3.4%2c0 -6.2%2c-2.8 -6.2%2c-6.2 V 49.2 c 0%2c-3.4 2.8%2c-6.2 6.2%2c-6.2 h 50.8 c 3.4%2c0 6.2%2c2.8 6.2%2c6.2 z' id='path12' inkscape:connector-curvature='0' style='fill:white%3bfill-opacity:1' /%3e%3cpath d='m 59.8%2c57.6 -12.5%2c12.5 -7%2c-7 c -1.2%2c-1.2 -3.2%2c-1.2 -4.4%2c0 -1.2%2c1.2 -1.2%2c3.2 0%2c4.4 l 9.2%2c9.2 c 0.6%2c0.6 1.4%2c0.9 2.2%2c0.9 0.8%2c0 1.6%2c-0.3 2.2%2c-0.9 L 64.2%2c62 c 1.2%2c-1.2 1.2%2c-3.2 0%2c-4.4 -1.2%2c-1.2 -3.2%2c-1.2 -4.4%2c0 z' id='path14' inkscape:connector-curvature='0' style='fill:white%3bfill-opacity:1' /%3e%3c/g%3e%3c/svg%3e";
4322
4322
 
4323
4323
  var _excluded$2 = ["type", "rotation", "id", "locked", "layer"],
4324
- _excluded2 = ["x", "y", "layer", "moving"],
4325
- _excluded3 = ["state", "boardSize"];
4324
+ _excluded2 = ["state", "boardSize", "currentUser"],
4325
+ _excluded3 = ["x", "y", "layer", "moving"];
4326
4326
 
4327
4327
  var _templateObject$2;
4328
4328
  var ItemWrapper = newStyled.div(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteral(["\n display: inline-block;\n transition: transform 150ms;\n user-select: none;\n padding: 4px;\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: 2px;\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"])), function (_ref) {
@@ -4372,7 +4372,7 @@ var ItemErrorBoundary = /*#__PURE__*/function (_React$Component) {
4372
4372
  key: "componentDidCatch",
4373
4373
  value: function componentDidCatch(error) {
4374
4374
  // eslint-disable-next-line no-console
4375
- console.log("Error for item ".concat(this.state.itemId), error, this.props.state);
4375
+ console.error("Error for item ".concat(this.state.itemId), error, this.props.state);
4376
4376
  }
4377
4377
  }, {
4378
4378
  key: "onReload",
@@ -4406,6 +4406,10 @@ var ItemErrorBoundary = /*#__PURE__*/function (_React$Component) {
4406
4406
  return ItemErrorBoundary;
4407
4407
  }(React__default['default'].Component);
4408
4408
 
4409
+ var removeClass = function removeClass(e) {
4410
+ e.target.className = "";
4411
+ };
4412
+
4409
4413
  var Item = function Item(_ref3) {
4410
4414
  var _itemMap$error;
4411
4415
 
@@ -4426,28 +4430,19 @@ var Item = function Item(_ref3) {
4426
4430
  itemMap = _ref3.itemMap,
4427
4431
  unlocked = _ref3.unlocked;
4428
4432
 
4429
- var isMountedRef = React__default['default'].useRef(false);
4430
4433
  var animateRef = React__default['default'].useRef(null);
4431
- var Component = itemMap[type].component || null;
4434
+
4435
+ var Component = itemMap[type].component || function () {
4436
+ return null;
4437
+ };
4438
+
4432
4439
  var updateState = React__default['default'].useCallback(function (callbackOrItem) {
4433
4440
  var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
4434
4441
  return setState(id, callbackOrItem, sync);
4435
- }, [setState, id]); // Update actual size when update
4436
-
4437
- React__default['default'].useEffect(function () {
4438
- isMountedRef.current = true;
4439
- return function () {
4440
- isMountedRef.current = false;
4441
- };
4442
- }, []);
4442
+ }, [setState, id]);
4443
4443
  React__default['default'].useEffect(function () {
4444
4444
  animateRef.current.className = animate;
4445
4445
  }, [animate]);
4446
-
4447
- var removeClass = function removeClass(e) {
4448
- e.target.className = "";
4449
- };
4450
-
4451
4446
  var className = "item ".concat(id);
4452
4447
 
4453
4448
  if (locked) {
@@ -4466,6 +4461,9 @@ var Item = function Item(_ref3) {
4466
4461
  "data-id": id,
4467
4462
  className: className
4468
4463
  }, /*#__PURE__*/React__default['default'].createElement("div", {
4464
+ style: {
4465
+ display: "flex"
4466
+ },
4469
4467
  ref: animateRef,
4470
4468
  onAnimationEnd: removeClass,
4471
4469
  onKeyDown: function onKeyDown(e) {
@@ -4503,31 +4501,42 @@ var MemoizedItem = /*#__PURE__*/React.memo(Item, function (_ref4, _ref5) {
4503
4501
  nextIsSelected = _ref5.isSelected,
4504
4502
  nextUnlocked = _ref5.unlocked;
4505
4503
  return prevIsSelected === nextIsSelected && prevUnlocked === nextUnlocked && prevSetState === nextSetState && JSON.stringify(prevState) === JSON.stringify(nextState);
4506
- }); // Exclude positionning from memoization
4504
+ }); // Exclude positioning from memoization
4507
4505
 
4508
4506
  var PositionedItem = function PositionedItem(_ref6) {
4509
- var _ref6$state = _ref6.state;
4510
- _ref6$state = _ref6$state === void 0 ? {} : _ref6$state;
4511
-
4512
- var _ref6$state$x = _ref6$state.x,
4513
- x = _ref6$state$x === void 0 ? 0 : _ref6$state$x,
4514
- _ref6$state$y = _ref6$state.y,
4515
- y = _ref6$state$y === void 0 ? 0 : _ref6$state$y,
4516
- layer = _ref6$state.layer,
4517
- moving = _ref6$state.moving,
4518
- stateRest = _objectWithoutProperties(_ref6$state, _excluded2),
4507
+ var _rest$itemMap$state$t;
4508
+
4509
+ var _ref6$state = _ref6.state,
4510
+ state = _ref6$state === void 0 ? {} : _ref6$state,
4519
4511
  boardSize = _ref6.boardSize,
4520
- rest = _objectWithoutProperties(_ref6, _excluded3);
4512
+ currentUser = _ref6.currentUser,
4513
+ rest = _objectWithoutProperties(_ref6, _excluded2);
4514
+
4515
+ var stateTrans = ((_rest$itemMap$state$t = rest.itemMap[state.type]) === null || _rest$itemMap$state$t === void 0 ? void 0 : _rest$itemMap$state$t.stateHook) || function (st) {
4516
+ return st;
4517
+ };
4518
+
4519
+ var _stateTrans = stateTrans(state, {
4520
+ currentUser: currentUser
4521
+ }),
4522
+ _stateTrans$x = _stateTrans.x,
4523
+ x = _stateTrans$x === void 0 ? 0 : _stateTrans$x,
4524
+ _stateTrans$y = _stateTrans.y,
4525
+ y = _stateTrans$y === void 0 ? 0 : _stateTrans$y,
4526
+ _stateTrans$layer = _stateTrans.layer,
4527
+ layer = _stateTrans$layer === void 0 ? 0 : _stateTrans$layer,
4528
+ moving = _stateTrans.moving,
4529
+ stateRest = _objectWithoutProperties(_stateTrans, _excluded3);
4521
4530
 
4522
4531
  return /*#__PURE__*/React__default['default'].createElement("div", {
4523
4532
  style: {
4524
- transform: "translate(".concat(x, "px, ").concat(y, "px)"),
4525
- display: "inline-block",
4526
- zIndex: ((layer || 0) + 4) * 10 + 100 + (moving ? 5 : 0),
4527
- // Items z-index between 100 and 200
4528
4533
  position: "absolute",
4529
4534
  top: "".concat(boardSize / 2, "px"),
4530
- left: "".concat(boardSize / 2, "px")
4535
+ left: "".concat(boardSize / 2, "px"),
4536
+ display: "inline-block",
4537
+ transform: "translate(".concat(x, "px, ").concat(y, "px)"),
4538
+ zIndex: (layer + 4) * 10 + 100 + (moving ? 5 : 0) // Items z-index between 100 and 200
4539
+
4531
4540
  }
4532
4541
  }, /*#__PURE__*/React__default['default'].createElement(MemoizedItem, _extends$1({}, rest, {
4533
4542
  state: stateRest
@@ -4536,6 +4545,211 @@ var PositionedItem = function PositionedItem(_ref6) {
4536
4545
 
4537
4546
  var MemoizedPositionedItem = /*#__PURE__*/React.memo(PositionedItem);
4538
4547
 
4548
+ var persistUser = function persistUser(user) {
4549
+ localStorage.setItem("user", JSON.stringify(user));
4550
+ };
4551
+ var colors = ["#037758", "#99092a", "#067070", "#c6650f", "#008726", "#3d7004", "#348402", "#057f58", "#b58612", "#c44c01", "#0a7704", "#0e910e", "#027377", "#c99e02", "#054160", "#157a01", "#b10de2", "#0d6289", "#bc5d03", "#ba0cd1", "#d39f10", "#0c4c7a", "#460782", "#a51f10", "#cecb10", "#9b0943", "#607f0c", "#007a4b", "#bf0daa", "#af0ad8"];
4552
+
4553
+ var getRandomColor = function getRandomColor() {
4554
+ return colors[Math.floor(Math.random() * colors.length)];
4555
+ }; // TODO remove user persistence
4556
+
4557
+
4558
+ var getUser = function getUser() {
4559
+ if (localStorage.user) {
4560
+ // Add some mandatory info if missing
4561
+ var localUser = _objectSpread2({
4562
+ name: "Player",
4563
+ color: getRandomColor(),
4564
+ uid: nanoid()
4565
+ }, JSON.parse(localStorage.user)); // Id is given by server
4566
+ // delete localUser.id;
4567
+
4568
+
4569
+ persistUser(localUser);
4570
+ return localUser;
4571
+ }
4572
+
4573
+ var newUser = {
4574
+ name: "Player",
4575
+ color: getRandomColor(),
4576
+ uid: nanoid()
4577
+ };
4578
+ persistUser(newUser);
4579
+ return newUser;
4580
+ };
4581
+ var userAtom = recoil.atom({
4582
+ key: "user",
4583
+ "default": getUser()
4584
+ });
4585
+ var usersAtom = recoil.atom({
4586
+ key: "users",
4587
+ "default": []
4588
+ });
4589
+ var localUsersAtom = recoil.selector({
4590
+ key: "localUsersAtom",
4591
+ get: function get(_ref) {
4592
+ var _get = _ref.get;
4593
+
4594
+ var currentUser = _get(userAtom);
4595
+
4596
+ var users = _get(usersAtom);
4597
+
4598
+ return users.filter(function (_ref2) {
4599
+ var space = _ref2.space;
4600
+ return space === currentUser.space;
4601
+ });
4602
+ }
4603
+ });
4604
+
4605
+ var useUsers = function useUsers() {
4606
+ var _useRecoilState = recoil.useRecoilState(userAtom),
4607
+ _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
4608
+ currentUser = _useRecoilState2[0],
4609
+ setCurrentUserState = _useRecoilState2[1];
4610
+
4611
+ var users = recoil.useRecoilValue(usersAtom);
4612
+ var localUsers = recoil.useRecoilValue(localUsersAtom);
4613
+ var setCurrentUser = React__default['default'].useCallback(function (callbackOrUser) {
4614
+ var callback = callbackOrUser;
4615
+
4616
+ if (_typeof(callbackOrUser) === "object") {
4617
+ callback = function callback() {
4618
+ return callbackOrUser;
4619
+ };
4620
+ }
4621
+
4622
+ setCurrentUserState(function (prevUser) {
4623
+ var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
4624
+ id: prevUser.id,
4625
+ uid: prevUser.uid
4626
+ });
4627
+
4628
+ persistUser(newUser);
4629
+ return newUser;
4630
+ });
4631
+ }, [setCurrentUserState]);
4632
+ React__default['default'].useEffect(function () {
4633
+ // eslint-disable-next-line no-console
4634
+ console.debug("Curent user is in space ".concat(currentUser.space));
4635
+ }, [currentUser.space]);
4636
+ return {
4637
+ currentUser: currentUser,
4638
+ setCurrentUser: setCurrentUser,
4639
+ users: users,
4640
+ localUsers: localUsers
4641
+ };
4642
+ };
4643
+
4644
+ var SubscribeUserEvents = function SubscribeUserEvents() {
4645
+ var usersRef = React__default['default'].useRef([]);
4646
+ var setUsers = recoil.useSetRecoilState(usersAtom);
4647
+
4648
+ var _useRecoilState = recoil.useRecoilState(userAtom),
4649
+ _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
4650
+ currentUser = _useRecoilState2[0],
4651
+ setCurrentUserState = _useRecoilState2[1];
4652
+
4653
+ var _useWire = useWire("room"),
4654
+ wire = _useWire.wire,
4655
+ isMaster = _useWire.isMaster,
4656
+ roomSpace = _useWire.room;
4657
+
4658
+ React__default['default'].useEffect(function () {
4659
+ setCurrentUserState(function (prevUser) {
4660
+ return _objectSpread2(_objectSpread2({}, prevUser), {}, {
4661
+ id: wire.userId,
4662
+ space: roomSpace
4663
+ });
4664
+ });
4665
+ return function () {
4666
+ setCurrentUserState(function (prevUser) {
4667
+ return _objectSpread2(_objectSpread2({}, prevUser), {}, {
4668
+ id: wire.userId,
4669
+ space: null
4670
+ });
4671
+ });
4672
+ };
4673
+ }, [wire.userId, roomSpace, setCurrentUserState]);
4674
+ React__default['default'].useEffect(function () {
4675
+ if (!isMaster) {
4676
+ var onGetUserList = function onGetUserList(userList) {
4677
+ usersRef.current = userList;
4678
+ setUsers(userList);
4679
+ };
4680
+
4681
+ wire.call("getUserList").then(onGetUserList, function () {
4682
+ // retry later
4683
+ setTimeout(function () {
4684
+ wire.call("getUserList") // eslint-disable-next-line no-console
4685
+ .then(onGetUserList, function (error) {
4686
+ return console.log(error);
4687
+ });
4688
+ }, 1000);
4689
+ });
4690
+ }
4691
+ }, [wire, isMaster, setUsers]); // eslint-disable-next-line react-hooks/exhaustive-deps
4692
+
4693
+ var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
4694
+ wire.publish("userUpdate", newUser, true);
4695
+ }, [wire], 500);
4696
+ React__default['default'].useEffect(function () {
4697
+ if (currentUser && currentUser.id) {
4698
+ debouncedEmitUpdateUser(currentUser);
4699
+ }
4700
+ }, [currentUser, debouncedEmitUpdateUser]);
4701
+ React__default['default'].useEffect(function () {
4702
+ var unsub = [];
4703
+
4704
+ if (isMaster) {
4705
+ wire.register("getUserList", function () {
4706
+ return usersRef.current;
4707
+ }).then(function (unregister) {
4708
+ unsub.push(unregister);
4709
+ });
4710
+ unsub.push(wire.subscribe("userUpdate", function (user) {
4711
+ if (usersRef.current.find(function (u) {
4712
+ return u.id === user.id;
4713
+ })) {
4714
+ var newUsers = usersRef.current.map(function (u) {
4715
+ return u.id === user.id ? user : u;
4716
+ });
4717
+ usersRef.current = newUsers;
4718
+ } else {
4719
+ var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
4720
+
4721
+ usersRef.current = _newUsers;
4722
+ }
4723
+
4724
+ setUsers(usersRef.current);
4725
+ wire.publish("updateUserList", usersRef.current);
4726
+ }));
4727
+ }
4728
+
4729
+ unsub.push(wire.subscribe("userLeave", function (userId) {
4730
+ usersRef.current = usersRef.current.filter(function (_ref) {
4731
+ var id = _ref.id;
4732
+ return id !== userId;
4733
+ });
4734
+ setUsers(usersRef.current);
4735
+
4736
+ if (isMaster) {
4737
+ wire.publish("updateUserList", usersRef.current);
4738
+ }
4739
+ }));
4740
+ unsub.push(wire.subscribe("updateUserList", function (newList) {
4741
+ usersRef.current = newList;
4742
+ setUsers(usersRef.current);
4743
+ }));
4744
+ return function () {
4745
+ unsub.forEach(function (u) {
4746
+ return u();
4747
+ });
4748
+ };
4749
+ }, [wire, isMaster, setUsers]);
4750
+ return null;
4751
+ };
4752
+
4539
4753
  /** Allow to operate on locked items while u or l key is pressed */
4540
4754
 
4541
4755
  var useUnlock = function useUnlock() {
@@ -4580,6 +4794,9 @@ var ItemList = function ItemList(_ref) {
4580
4794
  var _useRecoilValue = recoil.useRecoilValue(ConfigurationAtom),
4581
4795
  boardSize = _useRecoilValue.boardSize;
4582
4796
 
4797
+ var _useUsers = useUsers(),
4798
+ currentUser = _useUsers.currentUser;
4799
+
4583
4800
  var unlocked = useUnlock();
4584
4801
  return itemList.map(function (itemId) {
4585
4802
  return /*#__PURE__*/React__default['default'].createElement(MemoizedPositionedItem, {
@@ -4589,7 +4806,8 @@ var ItemList = function ItemList(_ref) {
4589
4806
  isSelected: selectedItems.includes(itemId),
4590
4807
  unlocked: unlocked,
4591
4808
  itemMap: itemTemplates,
4592
- boardSize: boardSize
4809
+ boardSize: boardSize,
4810
+ currentUser: currentUser
4593
4811
  });
4594
4812
  });
4595
4813
  };
@@ -5113,6 +5331,8 @@ var Gesture = function Gesture(_ref6) {
5113
5331
  deltaY: 0,
5114
5332
  startX: stateRef.current.startX,
5115
5333
  startY: stateRef.current.startY,
5334
+ clientX: stateRef.current.startX,
5335
+ clientY: stateRef.current.startY,
5116
5336
  distanceX: 0,
5117
5337
  distanceY: 0,
5118
5338
  button: stateRef.current.currentButton,
@@ -5135,6 +5355,8 @@ var Gesture = function Gesture(_ref6) {
5135
5355
  deltaY: deltaY,
5136
5356
  startX: stateRef.current.startX,
5137
5357
  startY: stateRef.current.startY,
5358
+ clientX: clientX,
5359
+ clientY: clientY,
5138
5360
  distanceX: distanceX,
5139
5361
  distanceY: distanceY,
5140
5362
  button: stateRef.current.currentButton,
@@ -5240,6 +5462,8 @@ var Gesture = function Gesture(_ref6) {
5240
5462
  deltaY: clientY - stateRef.current.prevY,
5241
5463
  startX: stateRef.current.startX,
5242
5464
  startY: stateRef.current.startY,
5465
+ clientX: clientX,
5466
+ clientY: clientY,
5243
5467
  distanceX: clientX - stateRef.current.startX,
5244
5468
  distanceY: clientY - stateRef.current.startY,
5245
5469
  button: stateRef.current.currentButton,
@@ -5321,6 +5545,9 @@ var Selector = function Selector(_ref) {
5321
5545
  var setSelected = recoil.useSetRecoilState(SelectedItemsAtom);
5322
5546
  var setBoardState = recoil.useSetRecoilState(BoardStateAtom);
5323
5547
 
5548
+ var _useItemActions = useItemActions(),
5549
+ findElementUnderPointer = _useItemActions.findElementUnderPointer;
5550
+
5324
5551
  var _React$useState = React__default['default'].useState({}),
5325
5552
  _React$useState2 = _slicedToArray(_React$useState, 2),
5326
5553
  selector = _React$useState2[0],
@@ -5385,50 +5612,68 @@ var Selector = function Selector(_ref) {
5385
5612
  }, [setSelected]);
5386
5613
  useThrottledEffect(updateSelected, [selector, updateSelected], 200);
5387
5614
 
5388
- var onDragStart = function onDragStart(_ref4) {
5389
- var button = _ref4.button,
5390
- altKey = _ref4.altKey,
5391
- ctrlKey = _ref4.ctrlKey,
5392
- metaKey = _ref4.metaKey,
5393
- target = _ref4.target;
5394
- var outsideItem = !insideClass(target, "item") || insideClass(target, "locked");
5395
- var metaKeyPressed = altKey || ctrlKey || metaKey;
5396
- var goodButton = moveFirst ? button === 1 || button === 0 && metaKeyPressed : button === 0 && !metaKeyPressed;
5615
+ var onDragStart = /*#__PURE__*/function () {
5616
+ var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(event) {
5617
+ var button, altKey, ctrlKey, metaKey, foundElement, metaKeyPressed, goodButton;
5618
+ return regeneratorRuntime.wrap(function _callee2$(_context2) {
5619
+ while (1) {
5620
+ switch (_context2.prev = _context2.next) {
5621
+ case 0:
5622
+ button = event.button, altKey = event.altKey, ctrlKey = event.ctrlKey, metaKey = event.metaKey;
5623
+ _context2.next = 3;
5624
+ return findElementUnderPointer(event);
5397
5625
 
5398
- if (goodButton && (outsideItem || moveFirst)) {
5399
- stateRef.current.moving = true;
5400
- setBoardState(function (prev) {
5401
- return _objectSpread2(_objectSpread2({}, prev), {}, {
5402
- selecting: true
5403
- });
5404
- });
5405
- wrapperRef.current.style.cursor = "crosshair";
5406
- }
5407
- };
5626
+ case 3:
5627
+ foundElement = _context2.sent;
5628
+ metaKeyPressed = altKey || ctrlKey || metaKey;
5629
+ goodButton = moveFirst ? button === 1 || button === 0 && metaKeyPressed : button === 0 && !metaKeyPressed;
5630
+
5631
+ if (goodButton && (!foundElement || moveFirst)) {
5632
+ stateRef.current.moving = true;
5633
+ setBoardState(function (prev) {
5634
+ return _objectSpread2(_objectSpread2({}, prev), {}, {
5635
+ selecting: true
5636
+ });
5637
+ });
5638
+ wrapperRef.current.style.cursor = "crosshair";
5639
+ }
5640
+
5641
+ case 7:
5642
+ case "end":
5643
+ return _context2.stop();
5644
+ }
5645
+ }
5646
+ }, _callee2);
5647
+ }));
5648
+
5649
+ return function onDragStart(_x) {
5650
+ return _ref4.apply(this, arguments);
5651
+ };
5652
+ }();
5408
5653
 
5409
5654
  var onDrag = recoil.useRecoilCallback(function (_ref5) {
5410
5655
  var snapshot = _ref5.snapshot;
5411
5656
  return /*#__PURE__*/function () {
5412
- var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref6) {
5657
+ var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref6) {
5413
5658
  var distanceY, distanceX, startX, startY, _wrapperRef$current$g, top, left, _yield$snapshot$getPr2, scale, displayX, displayY, displayDistanceX, displayDistanceY;
5414
5659
 
5415
- return regeneratorRuntime.wrap(function _callee2$(_context2) {
5660
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
5416
5661
  while (1) {
5417
- switch (_context2.prev = _context2.next) {
5662
+ switch (_context3.prev = _context3.next) {
5418
5663
  case 0:
5419
5664
  distanceY = _ref6.distanceY, distanceX = _ref6.distanceX, startX = _ref6.startX, startY = _ref6.startY;
5420
5665
 
5421
5666
  if (!stateRef.current.moving) {
5422
- _context2.next = 14;
5667
+ _context3.next = 14;
5423
5668
  break;
5424
5669
  }
5425
5670
 
5426
5671
  _wrapperRef$current$g = wrapperRef.current.getBoundingClientRect(), top = _wrapperRef$current$g.top, left = _wrapperRef$current$g.left;
5427
- _context2.next = 5;
5672
+ _context3.next = 5;
5428
5673
  return snapshot.getPromise(BoardTransformAtom);
5429
5674
 
5430
5675
  case 5:
5431
- _yield$snapshot$getPr2 = _context2.sent;
5676
+ _yield$snapshot$getPr2 = _context3.sent;
5432
5677
  scale = _yield$snapshot$getPr2.scale;
5433
5678
  displayX = (startX - left) / scale;
5434
5679
  displayY = (startY - top) / scale;
@@ -5457,13 +5702,13 @@ var Selector = function Selector(_ref) {
5457
5702
 
5458
5703
  case 14:
5459
5704
  case "end":
5460
- return _context2.stop();
5705
+ return _context3.stop();
5461
5706
  }
5462
5707
  }
5463
- }, _callee2);
5708
+ }, _callee3);
5464
5709
  }));
5465
5710
 
5466
- return function (_x) {
5711
+ return function (_x2) {
5467
5712
  return _ref7.apply(this, arguments);
5468
5713
  };
5469
5714
  }();
@@ -5496,43 +5741,47 @@ var Selector = function Selector(_ref) {
5496
5741
  var onTap = recoil.useRecoilCallback(function (_ref9) {
5497
5742
  var snapshot = _ref9.snapshot;
5498
5743
  return /*#__PURE__*/function () {
5499
- var _ref11 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref10) {
5500
- var target, ctrlKey, metaKey, foundItem, itemId, selectedItems;
5501
- return regeneratorRuntime.wrap(function _callee3$(_context3) {
5744
+ var _ref10 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(event) {
5745
+ var target, ctrlKey, metaKey, foundElement, itemId, selectedItems;
5746
+ return regeneratorRuntime.wrap(function _callee4$(_context4) {
5502
5747
  while (1) {
5503
- switch (_context3.prev = _context3.next) {
5748
+ switch (_context4.prev = _context4.next) {
5504
5749
  case 0:
5505
- target = _ref10.target, ctrlKey = _ref10.ctrlKey, metaKey = _ref10.metaKey;
5506
- foundItem = insideClass(target, "item");
5750
+ target = event.target, ctrlKey = event.ctrlKey, metaKey = event.metaKey;
5751
+ _context4.next = 3;
5752
+ return findElementUnderPointer(event);
5753
+
5754
+ case 3:
5755
+ foundElement = _context4.sent;
5507
5756
 
5508
- if (!((!foundItem || insideClass(foundItem, "locked")) && insideClass(target, "board"))) {
5509
- _context3.next = 6;
5757
+ if (!(!foundElement && insideClass(target, "board"))) {
5758
+ _context4.next = 8;
5510
5759
  break;
5511
5760
  }
5512
5761
 
5513
5762
  setSelected([]);
5514
- _context3.next = 14;
5763
+ _context4.next = 16;
5515
5764
  break;
5516
5765
 
5517
- case 6:
5518
- itemId = getIdFromElem(foundItem); // Being defensive here to avoid bug
5766
+ case 8:
5767
+ itemId = getIdFromElem(foundElement); // Being defensive here to avoid bug
5519
5768
 
5520
5769
  if (itemId) {
5521
- _context3.next = 10;
5770
+ _context4.next = 12;
5522
5771
  break;
5523
5772
  }
5524
5773
 
5525
5774
  setSelected([]);
5526
- return _context3.abrupt("return");
5775
+ return _context4.abrupt("return");
5527
5776
 
5528
- case 10:
5529
- _context3.next = 12;
5777
+ case 12:
5778
+ _context4.next = 14;
5530
5779
  return snapshot.getPromise(SelectedItemsAtom);
5531
5780
 
5532
- case 12:
5533
- selectedItems = _context3.sent;
5781
+ case 14:
5782
+ selectedItems = _context4.sent;
5534
5783
 
5535
- if (foundItem && !selectedItems.includes(itemId)) {
5784
+ if (foundElement && !selectedItems.includes(itemId)) {
5536
5785
  if (ctrlKey || metaKey) {
5537
5786
  setSelected(function (prev) {
5538
5787
  return [].concat(_toConsumableArray(prev), [itemId]);
@@ -5542,19 +5791,19 @@ var Selector = function Selector(_ref) {
5542
5791
  }
5543
5792
  }
5544
5793
 
5545
- case 14:
5794
+ case 16:
5546
5795
  case "end":
5547
- return _context3.stop();
5796
+ return _context4.stop();
5548
5797
  }
5549
5798
  }
5550
- }, _callee3);
5799
+ }, _callee4);
5551
5800
  }));
5552
5801
 
5553
- return function (_x2) {
5554
- return _ref11.apply(this, arguments);
5802
+ return function (_x3) {
5803
+ return _ref10.apply(this, arguments);
5555
5804
  };
5556
5805
  }();
5557
- }, [setSelected]);
5806
+ }, [findElementUnderPointer, setSelected]);
5558
5807
  return /*#__PURE__*/React__default['default'].createElement(Gesture, {
5559
5808
  onDragStart: onDragStart,
5560
5809
  onDrag: onDrag,
@@ -5578,11 +5827,11 @@ var ActionPane = function ActionPane(_ref) {
5578
5827
 
5579
5828
  var _useItemActions = useItemActions(),
5580
5829
  moveItems = _useItemActions.moveItems,
5581
- placeItems = _useItemActions.placeItems;
5830
+ placeItems = _useItemActions.placeItems,
5831
+ findElementUnderPointer = _useItemActions.findElementUnderPointer;
5582
5832
 
5583
5833
  var setSelectedItems = recoil.useSetRecoilState(SelectedItemsAtom);
5584
5834
  var setBoardState = recoil.useSetRecoilState(BoardStateAtom);
5585
- var wrapperRef = React__default['default'].useRef(null);
5586
5835
  var actionRef = React__default['default'].useRef({}); // Use ref because pointer events are faster than react state management
5587
5836
 
5588
5837
  var selectedItemRef = React__default['default'].useRef({
@@ -5591,30 +5840,25 @@ var ActionPane = function ActionPane(_ref) {
5591
5840
  var onDragStart = recoil.useRecoilCallback(function (_ref2) {
5592
5841
  var snapshot = _ref2.snapshot;
5593
5842
  return /*#__PURE__*/function () {
5594
- var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref3) {
5595
- var target, ctrlKey, metaKey, event, foundElement, selectedItems, itemId;
5843
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(event) {
5844
+ var ctrlKey, metaKey, originalEvent, foundElement, selectedItems, itemId;
5596
5845
  return regeneratorRuntime.wrap(function _callee$(_context) {
5597
5846
  while (1) {
5598
5847
  switch (_context.prev = _context.next) {
5599
5848
  case 0:
5600
- target = _ref3.target, ctrlKey = _ref3.ctrlKey, metaKey = _ref3.metaKey, event = _ref3.event;
5601
-
5602
- if (!["INPUT", "TEXTAREA"].includes(target.tagName)) {
5603
- _context.next = 3;
5604
- break;
5605
- }
5606
-
5607
- return _context.abrupt("return");
5849
+ ctrlKey = event.ctrlKey, metaKey = event.metaKey, originalEvent = event.event;
5850
+ _context.next = 3;
5851
+ return findElementUnderPointer(event);
5608
5852
 
5609
5853
  case 3:
5610
- foundElement = insideClass(target, "item");
5854
+ foundElement = _context.sent;
5611
5855
 
5612
- if (!(foundElement && !hasClass(foundElement, "locked"))) {
5856
+ if (!foundElement) {
5613
5857
  _context.next = 13;
5614
5858
  break;
5615
5859
  }
5616
5860
 
5617
- event.stopPropagation();
5861
+ originalEvent.stopPropagation();
5618
5862
  _context.next = 8;
5619
5863
  return snapshot.getPromise(SelectedItemsAtom);
5620
5864
 
@@ -5650,21 +5894,21 @@ var ActionPane = function ActionPane(_ref) {
5650
5894
  }));
5651
5895
 
5652
5896
  return function (_x) {
5653
- return _ref4.apply(this, arguments);
5897
+ return _ref3.apply(this, arguments);
5654
5898
  };
5655
5899
  }();
5656
- }, [setSelectedItems]);
5657
- var onDrag = recoil.useRecoilCallback(function (_ref5) {
5658
- var snapshot = _ref5.snapshot;
5900
+ }, [findElementUnderPointer, setSelectedItems]);
5901
+ var onDrag = recoil.useRecoilCallback(function (_ref4) {
5902
+ var snapshot = _ref4.snapshot;
5659
5903
  return /*#__PURE__*/function () {
5660
- var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref6) {
5904
+ var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref5) {
5661
5905
  var deltaX, deltaY, _yield$snapshot$getPr, scale, moveX, moveY;
5662
5906
 
5663
5907
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
5664
5908
  while (1) {
5665
5909
  switch (_context2.prev = _context2.next) {
5666
5910
  case 0:
5667
- deltaX = _ref6.deltaX, deltaY = _ref6.deltaY;
5911
+ deltaX = _ref5.deltaX, deltaY = _ref5.deltaY;
5668
5912
 
5669
5913
  if (!actionRef.current.moving) {
5670
5914
  _context2.next = 10;
@@ -5698,12 +5942,12 @@ var ActionPane = function ActionPane(_ref) {
5698
5942
  }));
5699
5943
 
5700
5944
  return function (_x2) {
5701
- return _ref7.apply(this, arguments);
5945
+ return _ref6.apply(this, arguments);
5702
5946
  };
5703
5947
  }();
5704
5948
  }, [moveItems, setBoardState]);
5705
- var onDragEnd = recoil.useRecoilCallback(function (_ref8) {
5706
- var snapshot = _ref8.snapshot;
5949
+ var onDragEnd = recoil.useRecoilCallback(function (_ref7) {
5950
+ var snapshot = _ref7.snapshot;
5707
5951
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
5708
5952
  var _yield$snapshot$getPr2, _yield$snapshot$getPr3, boardGridSize, gridSize;
5709
5953
 
@@ -5746,10 +5990,10 @@ var ActionPane = function ActionPane(_ref) {
5746
5990
  }, _callee3);
5747
5991
  }));
5748
5992
  }, [placeItems, setBoardState]);
5749
- var onKeyDown = recoil.useRecoilCallback(function (_ref10) {
5750
- var snapshot = _ref10.snapshot;
5993
+ var onKeyDown = recoil.useRecoilCallback(function (_ref9) {
5994
+ var snapshot = _ref9.snapshot;
5751
5995
  return /*#__PURE__*/function () {
5752
- var _ref11 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(e) {
5996
+ var _ref10 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(e) {
5753
5997
  var selectedItems, _yield$snapshot$getPr4, _yield$snapshot$getPr5, boardGridSize, moveX, moveY, gridSize;
5754
5998
 
5755
5999
  return regeneratorRuntime.wrap(function _callee4$(_context4) {
@@ -5842,7 +6086,7 @@ var ActionPane = function ActionPane(_ref) {
5842
6086
  }));
5843
6087
 
5844
6088
  return function (_x3) {
5845
- return _ref11.apply(this, arguments);
6089
+ return _ref10.apply(this, arguments);
5846
6090
  };
5847
6091
  }();
5848
6092
  }, [moveItems, placeItems]);
@@ -5856,9 +6100,7 @@ var ActionPane = function ActionPane(_ref) {
5856
6100
  onDragStart: onDragStart,
5857
6101
  onDrag: onDrag,
5858
6102
  onDragEnd: onDragEnd
5859
- }, /*#__PURE__*/React__default['default'].createElement("div", {
5860
- ref: wrapperRef
5861
- }, children));
6103
+ }, children);
5862
6104
  };
5863
6105
 
5864
6106
  function t(t, n, r) {
@@ -6053,313 +6295,108 @@ var Cursor = function Cursor(_ref3) {
6053
6295
  color: color,
6054
6296
  textColor: textColor
6055
6297
  }, text));
6056
- };
6057
-
6058
- var MemoizedCursor = /*#__PURE__*/React__default['default'].memo(Cursor);
6059
-
6060
- var PositionnedCursor = function PositionnedCursor(_ref4) {
6061
- var pos = _ref4.pos,
6062
- rest = _objectWithoutProperties(_ref4, _excluded$1);
6063
-
6064
- return /*#__PURE__*/React__default['default'].createElement("div", {
6065
- style: {
6066
- transform: "translate(".concat(pos.x - 5, "px, ").concat(pos.y - 3, "px)"),
6067
- top: 0,
6068
- left: 0,
6069
- zIndex: 210,
6070
- position: "fixed",
6071
- pointerEvents: "none"
6072
- }
6073
- }, /*#__PURE__*/React__default['default'].createElement(MemoizedCursor, rest));
6074
- };
6075
-
6076
- var Cursors = function Cursors(_ref) {
6077
- var users = _ref.users;
6078
-
6079
- var _useWire = useWire("board"),
6080
- wire = _useWire.wire;
6081
-
6082
- var _React$useState = React__default['default'].useState({}),
6083
- _React$useState2 = _slicedToArray(_React$useState, 2),
6084
- cursors = _React$useState2[0],
6085
- setCursors = _React$useState2[1];
6086
-
6087
- var preventRef = React__default['default'].useRef(false);
6088
- var usersById = React__default['default'].useMemo(function () {
6089
- return users.reduce(function (acc, user) {
6090
- acc[user.id] = user;
6091
- return acc;
6092
- }, {});
6093
- }, [users]); // Prevent race condition when removing user
6094
-
6095
- var currentCursor = React__default['default'].useMemo(function () {
6096
- return users.reduce(function (acc, user) {
6097
- if (cursors[user.id]) {
6098
- acc[user.id] = cursors[user.id];
6099
- }
6100
-
6101
- return acc;
6102
- }, {});
6103
- }, [users, cursors]);
6104
- React__default['default'].useEffect(function () {
6105
- setCursors(function (prevCursors) {
6106
- return users.reduce(function (acc, user) {
6107
- if (prevCursors[user.id]) {
6108
- acc[user.id] = prevCursors[user.id];
6109
- }
6110
-
6111
- return acc;
6112
- }, {});
6113
- });
6114
- }, [users]);
6115
- React__default['default'].useEffect(function () {
6116
- var unsub = [];
6117
- unsub.push(wire.subscribe("cursorMove", function (_ref2) {
6118
- var userId = _ref2.userId,
6119
- pos = _ref2.pos;
6120
- // Avoid move after cursor off
6121
- if (preventRef.current) return;
6122
- setCursors(function (prevCursors) {
6123
- return _objectSpread2(_objectSpread2({}, prevCursors), {}, _defineProperty({}, userId, pos));
6124
- });
6125
- }));
6126
- unsub.push(wire.subscribe("cursorOff", function (_ref3) {
6127
- var userId = _ref3.userId;
6128
- setCursors(function (prevCursors) {
6129
- var newCursors = _objectSpread2({}, prevCursors);
6130
-
6131
- delete newCursors[userId];
6132
- return newCursors;
6133
- }); // Prevent next moves
6134
-
6135
- preventRef.current = true;
6136
- setTimeout(function () {
6137
- preventRef.current = false;
6138
- }, 100);
6139
- }));
6140
- return function () {
6141
- unsub.map(function (c) {
6142
- return c();
6143
- });
6144
- };
6145
- }, [wire]);
6146
- return /*#__PURE__*/React__default['default'].createElement("div", null, Object.entries(currentCursor).map(function (_ref4) {
6147
- var _ref5 = _slicedToArray(_ref4, 2),
6148
- userId = _ref5[0],
6149
- pos = _ref5[1];
6150
-
6151
- return /*#__PURE__*/React__default['default'].createElement(PositionnedCursor, {
6152
- key: userId,
6153
- pos: pos,
6154
- text: usersById[userId].name,
6155
- color: usersById[userId].color
6156
- });
6157
- }));
6158
- };
6159
-
6160
- var persistUser = function persistUser(user) {
6161
- localStorage.setItem("user", JSON.stringify(user));
6162
- };
6163
- var colors = ["#037758", "#99092a", "#067070", "#c6650f", "#008726", "#3d7004", "#348402", "#057f58", "#b58612", "#c44c01", "#0a7704", "#0e910e", "#027377", "#c99e02", "#054160", "#157a01", "#b10de2", "#0d6289", "#bc5d03", "#ba0cd1", "#d39f10", "#0c4c7a", "#460782", "#a51f10", "#cecb10", "#9b0943", "#607f0c", "#007a4b", "#bf0daa", "#af0ad8"];
6164
-
6165
- var getRandomColor = function getRandomColor() {
6166
- return colors[Math.floor(Math.random() * colors.length)];
6167
- }; // TODO remove user persistence
6168
-
6169
-
6170
- var getUser = function getUser() {
6171
- if (localStorage.user) {
6172
- // Add some mandatory info if missing
6173
- var localUser = _objectSpread2({
6174
- name: "Player",
6175
- color: getRandomColor(),
6176
- uid: nanoid()
6177
- }, JSON.parse(localStorage.user)); // Id is given by server
6178
- // delete localUser.id;
6179
-
6180
-
6181
- persistUser(localUser);
6182
- return localUser;
6183
- }
6184
-
6185
- var newUser = {
6186
- name: "Player",
6187
- color: getRandomColor(),
6188
- uid: nanoid()
6189
- };
6190
- persistUser(newUser);
6191
- return newUser;
6192
- };
6193
- var userAtom = recoil.atom({
6194
- key: "user",
6195
- "default": getUser()
6196
- });
6197
- var usersAtom = recoil.atom({
6198
- key: "users",
6199
- "default": []
6200
- });
6201
- var localUsersAtom = recoil.selector({
6202
- key: "localUsersAtom",
6203
- get: function get(_ref) {
6204
- var _get = _ref.get;
6205
-
6206
- var currentUser = _get(userAtom);
6207
-
6208
- var users = _get(usersAtom);
6209
-
6210
- return users.filter(function (_ref2) {
6211
- var space = _ref2.space;
6212
- return space === currentUser.space;
6213
- });
6214
- }
6215
- });
6216
-
6217
- var useUsers = function useUsers() {
6218
- var _useRecoilState = recoil.useRecoilState(userAtom),
6219
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
6220
- currentUser = _useRecoilState2[0],
6221
- setCurrentUserState = _useRecoilState2[1];
6222
-
6223
- var users = recoil.useRecoilValue(usersAtom);
6224
- var localUsers = recoil.useRecoilValue(localUsersAtom);
6225
- var setCurrentUser = React__default['default'].useCallback(function (callbackOrUser) {
6226
- var callback = callbackOrUser;
6227
-
6228
- if (_typeof(callbackOrUser) === "object") {
6229
- callback = function callback() {
6230
- return callbackOrUser;
6231
- };
6232
- }
6298
+ };
6233
6299
 
6234
- setCurrentUserState(function (prevUser) {
6235
- var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
6236
- id: prevUser.id,
6237
- uid: prevUser.uid
6238
- });
6300
+ var MemoizedCursor = /*#__PURE__*/React__default['default'].memo(Cursor);
6239
6301
 
6240
- persistUser(newUser);
6241
- return newUser;
6242
- });
6243
- }, [setCurrentUserState]);
6244
- React__default['default'].useEffect(function () {
6245
- // eslint-disable-next-line no-console
6246
- console.debug("Curent user is in space ".concat(currentUser.space));
6247
- }, [currentUser.space]);
6248
- return {
6249
- currentUser: currentUser,
6250
- setCurrentUser: setCurrentUser,
6251
- users: users,
6252
- localUsers: localUsers
6253
- };
6302
+ var PositionnedCursor = function PositionnedCursor(_ref4) {
6303
+ var pos = _ref4.pos,
6304
+ rest = _objectWithoutProperties(_ref4, _excluded$1);
6305
+
6306
+ return /*#__PURE__*/React__default['default'].createElement("div", {
6307
+ style: {
6308
+ transform: "translate(".concat(pos.x - 5, "px, ").concat(pos.y - 3, "px)"),
6309
+ top: 0,
6310
+ left: 0,
6311
+ zIndex: 210,
6312
+ position: "fixed",
6313
+ pointerEvents: "none"
6314
+ }
6315
+ }, /*#__PURE__*/React__default['default'].createElement(MemoizedCursor, rest));
6254
6316
  };
6255
6317
 
6256
- var SubscribeUserEvents = function SubscribeUserEvents() {
6257
- var usersRef = React__default['default'].useRef([]);
6258
- var setUsers = recoil.useSetRecoilState(usersAtom);
6318
+ var Cursors = function Cursors(_ref) {
6319
+ var users = _ref.users;
6259
6320
 
6260
- var _useRecoilState = recoil.useRecoilState(userAtom),
6261
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
6262
- currentUser = _useRecoilState2[0],
6263
- setCurrentUserState = _useRecoilState2[1];
6321
+ var _useWire = useWire("board"),
6322
+ wire = _useWire.wire;
6264
6323
 
6265
- var _useWire = useWire("room"),
6266
- wire = _useWire.wire,
6267
- isMaster = _useWire.isMaster,
6268
- roomSpace = _useWire.room;
6324
+ var _React$useState = React__default['default'].useState({}),
6325
+ _React$useState2 = _slicedToArray(_React$useState, 2),
6326
+ cursors = _React$useState2[0],
6327
+ setCursors = _React$useState2[1];
6269
6328
 
6270
- React__default['default'].useEffect(function () {
6271
- setCurrentUserState(function (prevUser) {
6272
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
6273
- id: wire.userId,
6274
- space: roomSpace
6275
- });
6276
- });
6277
- return function () {
6278
- setCurrentUserState(function (prevUser) {
6279
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
6280
- id: wire.userId,
6281
- space: null
6282
- });
6283
- });
6284
- };
6285
- }, [wire.userId, roomSpace, setCurrentUserState]);
6286
- React__default['default'].useEffect(function () {
6287
- if (!isMaster) {
6288
- var onGetUserList = function onGetUserList(userList) {
6289
- usersRef.current = userList;
6290
- setUsers(userList);
6291
- };
6329
+ var preventRef = React__default['default'].useRef(false);
6330
+ var usersById = React__default['default'].useMemo(function () {
6331
+ return users.reduce(function (acc, user) {
6332
+ acc[user.id] = user;
6333
+ return acc;
6334
+ }, {});
6335
+ }, [users]); // Prevent race condition when removing user
6292
6336
 
6293
- wire.call("getUserList").then(onGetUserList, function () {
6294
- // retry later
6295
- setTimeout(function () {
6296
- wire.call("getUserList") // eslint-disable-next-line no-console
6297
- .then(onGetUserList, function (error) {
6298
- return console.log(error);
6299
- });
6300
- }, 1000);
6301
- });
6302
- }
6303
- }, [wire, isMaster, setUsers]); // eslint-disable-next-line react-hooks/exhaustive-deps
6337
+ var currentCursor = React__default['default'].useMemo(function () {
6338
+ return users.reduce(function (acc, user) {
6339
+ if (cursors[user.id]) {
6340
+ acc[user.id] = cursors[user.id];
6341
+ }
6304
6342
 
6305
- var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
6306
- wire.publish("userUpdate", newUser, true);
6307
- }, [wire], 500);
6343
+ return acc;
6344
+ }, {});
6345
+ }, [users, cursors]);
6308
6346
  React__default['default'].useEffect(function () {
6309
- if (currentUser && currentUser.id) {
6310
- debouncedEmitUpdateUser(currentUser);
6311
- }
6312
- }, [currentUser, debouncedEmitUpdateUser]);
6347
+ setCursors(function (prevCursors) {
6348
+ return users.reduce(function (acc, user) {
6349
+ if (prevCursors[user.id]) {
6350
+ acc[user.id] = prevCursors[user.id];
6351
+ }
6352
+
6353
+ return acc;
6354
+ }, {});
6355
+ });
6356
+ }, [users]);
6313
6357
  React__default['default'].useEffect(function () {
6314
6358
  var unsub = [];
6315
-
6316
- if (isMaster) {
6317
- wire.register("getUserList", function () {
6318
- return usersRef.current;
6319
- }).then(function (unregister) {
6320
- unsub.push(unregister);
6359
+ unsub.push(wire.subscribe("cursorMove", function (_ref2) {
6360
+ var userId = _ref2.userId,
6361
+ pos = _ref2.pos;
6362
+ // Avoid move after cursor off
6363
+ if (preventRef.current) return;
6364
+ setCursors(function (prevCursors) {
6365
+ return _objectSpread2(_objectSpread2({}, prevCursors), {}, _defineProperty({}, userId, pos));
6321
6366
  });
6322
- unsub.push(wire.subscribe("userUpdate", function (user) {
6323
- if (usersRef.current.find(function (u) {
6324
- return u.id === user.id;
6325
- })) {
6326
- var newUsers = usersRef.current.map(function (u) {
6327
- return u.id === user.id ? user : u;
6328
- });
6329
- usersRef.current = newUsers;
6330
- } else {
6331
- var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
6332
-
6333
- usersRef.current = _newUsers;
6334
- }
6335
-
6336
- setUsers(usersRef.current);
6337
- wire.publish("updateUserList", usersRef.current);
6338
- }));
6339
- }
6367
+ }));
6368
+ unsub.push(wire.subscribe("cursorOff", function (_ref3) {
6369
+ var userId = _ref3.userId;
6370
+ setCursors(function (prevCursors) {
6371
+ var newCursors = _objectSpread2({}, prevCursors);
6340
6372
 
6341
- unsub.push(wire.subscribe("userLeave", function (userId) {
6342
- usersRef.current = usersRef.current.filter(function (_ref) {
6343
- var id = _ref.id;
6344
- return id !== userId;
6345
- });
6346
- setUsers(usersRef.current);
6373
+ delete newCursors[userId];
6374
+ return newCursors;
6375
+ }); // Prevent next moves
6347
6376
 
6348
- if (isMaster) {
6349
- wire.publish("updateUserList", usersRef.current);
6350
- }
6351
- }));
6352
- unsub.push(wire.subscribe("updateUserList", function (newList) {
6353
- usersRef.current = newList;
6354
- setUsers(usersRef.current);
6377
+ preventRef.current = true;
6378
+ setTimeout(function () {
6379
+ preventRef.current = false;
6380
+ }, 100);
6355
6381
  }));
6356
6382
  return function () {
6357
- unsub.forEach(function (u) {
6358
- return u();
6383
+ unsub.map(function (c) {
6384
+ return c();
6359
6385
  });
6360
6386
  };
6361
- }, [wire, isMaster, setUsers]);
6362
- return null;
6387
+ }, [wire]);
6388
+ return /*#__PURE__*/React__default['default'].createElement("div", null, Object.entries(currentCursor).map(function (_ref4) {
6389
+ var _ref5 = _slicedToArray(_ref4, 2),
6390
+ userId = _ref5[0],
6391
+ pos = _ref5[1];
6392
+
6393
+ return /*#__PURE__*/React__default['default'].createElement(PositionnedCursor, {
6394
+ key: userId,
6395
+ pos: pos,
6396
+ text: usersById[userId].name,
6397
+ color: usersById[userId].color
6398
+ });
6399
+ }));
6363
6400
  };
6364
6401
 
6365
6402
  var CursorPane = function CursorPane(_ref) {
@@ -6431,8 +6468,8 @@ var CursorPane = function CursorPane(_ref) {
6431
6468
  };
6432
6469
 
6433
6470
  return /*#__PURE__*/React__default['default'].createElement("div", {
6434
- onMouseMove: onMouseMove,
6435
- onMouseLeave: onLeave
6471
+ onPointerMove: onMouseMove,
6472
+ onPointerLeave: onLeave
6436
6473
  }, children, /*#__PURE__*/React__default['default'].createElement(Cursors, {
6437
6474
  users: users
6438
6475
  }));
@@ -6961,7 +6998,8 @@ var Board = function Board(_ref) {
6961
6998
  _ref$itemTemplates = _ref.itemTemplates,
6962
6999
  itemTemplates = _ref$itemTemplates === void 0 ? {} : _ref$itemTemplates,
6963
7000
  _ref$boardSize = _ref.boardSize,
6964
- boardSize = _ref$boardSize === void 0 ? DEFAULT_BOARD_MAX_SIZE : _ref$boardSize;
7001
+ boardSize = _ref$boardSize === void 0 ? DEFAULT_BOARD_MAX_SIZE : _ref$boardSize,
7002
+ children = _ref.children;
6965
7003
  var setConfiguration = recoil.useSetRecoilState(ConfigurationAtom);
6966
7004
 
6967
7005
  var _useDim = useDim(),
@@ -6999,7 +7037,7 @@ var Board = function Board(_ref) {
6999
7037
  className: "board"
7000
7038
  }, /*#__PURE__*/React__default['default'].createElement(ItemList, {
7001
7039
  itemTemplates: itemTemplates
7002
- })))))), /*#__PURE__*/React__default['default'].createElement(Selection, null));
7040
+ }), children))))), /*#__PURE__*/React__default['default'].createElement(Selection, null));
7003
7041
  };
7004
7042
 
7005
7043
  var TOLERANCE = 100;
@@ -7361,14 +7399,7 @@ var useItemInteraction = function useItemInteraction(interaction) {
7361
7399
  var setInteractions = recoil.useSetRecoilState(ItemInteractionsAtom);
7362
7400
  var register = React__default['default'].useCallback(function (callback) {
7363
7401
  setInteractions(function (prev) {
7364
- if (!prev[interaction]) {
7365
- // eslint-disable-next-line no-param-reassign
7366
- prev[interaction] = [];
7367
- }
7368
-
7369
- var newInter = _toConsumableArray(prev[interaction]);
7370
-
7371
- newInter.push(callback);
7402
+ var newInter = Array.isArray(prev[interaction]) ? [].concat(_toConsumableArray(prev[interaction]), [callback]) : [callback];
7372
7403
  return _objectSpread2(_objectSpread2({}, prev), {}, _defineProperty({}, interaction, newInter));
7373
7404
  });
7374
7405
  return function () {
@@ -8008,6 +8039,133 @@ var useItemActions = function useItemActions() {
8008
8039
  };
8009
8040
  }();
8010
8041
  }, []);
8042
+ var findElementUnderPointer = recoil.useRecoilCallback(function (_ref16) {
8043
+ var snapshot = _ref16.snapshot;
8044
+ return /*#__PURE__*/function () {
8045
+ var _ref18 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8(_ref17) {
8046
+ var target,
8047
+ clientX,
8048
+ clientY,
8049
+ _ref19,
8050
+ _ref19$returnLocked,
8051
+ returnLocked,
8052
+ _ref19$passLocked,
8053
+ passLocked,
8054
+ foundElement,
8055
+ isPassthrough,
8056
+ itemList,
8057
+ _yield$snapshot$getPr2,
8058
+ boardWrapper,
8059
+ elems,
8060
+ i,
8061
+ elem,
8062
+ _args8 = arguments;
8063
+
8064
+ return regeneratorRuntime.wrap(function _callee8$(_context8) {
8065
+ while (1) {
8066
+ switch (_context8.prev = _context8.next) {
8067
+ case 0:
8068
+ target = _ref17.target, clientX = _ref17.clientX, clientY = _ref17.clientY;
8069
+ _ref19 = _args8.length > 1 && _args8[1] !== undefined ? _args8[1] : {}, _ref19$returnLocked = _ref19.returnLocked, returnLocked = _ref19$returnLocked === void 0 ? false : _ref19$returnLocked, _ref19$passLocked = _ref19.passLocked, passLocked = _ref19$passLocked === void 0 ? false : _ref19$passLocked;
8070
+
8071
+ if (!["INPUT", "TEXTAREA"].includes(target.tagName)) {
8072
+ _context8.next = 4;
8073
+ break;
8074
+ }
8075
+
8076
+ return _context8.abrupt("return", null);
8077
+
8078
+ case 4:
8079
+ foundElement = insideClass(target, "item");
8080
+
8081
+ if (!foundElement) {
8082
+ _context8.next = 27;
8083
+ break;
8084
+ }
8085
+
8086
+ if (!(!passLocked && hasClass(foundElement, "locked") && !hasClass(foundElement, "selected"))) {
8087
+ _context8.next = 8;
8088
+ break;
8089
+ }
8090
+
8091
+ return _context8.abrupt("return", null);
8092
+
8093
+ case 8:
8094
+ // Is it a passthrough element?
8095
+ isPassthrough = (hasClass(target, "passthrough") || !returnLocked && hasClass(foundElement, "locked")) && !hasClass(foundElement, "selected");
8096
+
8097
+ if (!isPassthrough) {
8098
+ _context8.next = 27;
8099
+ break;
8100
+ }
8101
+
8102
+ _context8.next = 12;
8103
+ return snapshot.getPromise(ItemListAtom);
8104
+
8105
+ case 12:
8106
+ itemList = _context8.sent;
8107
+ _context8.next = 15;
8108
+ return snapshot.getPromise(ConfigurationAtom);
8109
+
8110
+ case 15:
8111
+ _yield$snapshot$getPr2 = _context8.sent;
8112
+ boardWrapper = _yield$snapshot$getPr2.boardWrapper;
8113
+ // Found element under the cursor
8114
+ elems = itemList.reduce(function (prev, itemId) {
8115
+ var elem = getItemElem(boardWrapper, itemId);
8116
+ var itemRect = elem.getBoundingClientRect();
8117
+
8118
+ if (isPointInsideRect({
8119
+ x: clientX,
8120
+ y: clientY
8121
+ }, itemRect)) {
8122
+ prev.unshift(elem);
8123
+ }
8124
+
8125
+ return prev;
8126
+ }, []); // Figure out if one can be returned
8127
+
8128
+ i = 0;
8129
+
8130
+ case 19:
8131
+ if (!(i < elems.length)) {
8132
+ _context8.next = 26;
8133
+ break;
8134
+ }
8135
+
8136
+ elem = elems[i];
8137
+
8138
+ if (!(elem !== foundElement && (returnLocked || !hasClass(elem, "locked")))) {
8139
+ _context8.next = 23;
8140
+ break;
8141
+ }
8142
+
8143
+ return _context8.abrupt("return", elem);
8144
+
8145
+ case 23:
8146
+ i += 1;
8147
+ _context8.next = 19;
8148
+ break;
8149
+
8150
+ case 26:
8151
+ return _context8.abrupt("return", null);
8152
+
8153
+ case 27:
8154
+ return _context8.abrupt("return", foundElement);
8155
+
8156
+ case 28:
8157
+ case "end":
8158
+ return _context8.stop();
8159
+ }
8160
+ }
8161
+ }, _callee8);
8162
+ }));
8163
+
8164
+ return function (_x13) {
8165
+ return _ref18.apply(this, arguments);
8166
+ };
8167
+ }();
8168
+ }, []);
8011
8169
  return {
8012
8170
  putItemsOnTop: putItemsOnTop,
8013
8171
  batchUpdateItems: batchUpdateItems,
@@ -8022,6 +8180,7 @@ var useItemActions = function useItemActions() {
8022
8180
  pushItems: pushItems,
8023
8181
  removeItems: removeItems,
8024
8182
  getItemList: getItemList,
8183
+ findElementUnderPointer: findElementUnderPointer,
8025
8184
  getItems: getItems
8026
8185
  };
8027
8186
  };