react-sync-board 0.4.3 → 0.5.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 React, { forwardRef, useContext, createContext, createElement, useRef, useLayoutEffect, useEffect, useMemo, memo } from 'react';
2
- import { atom, selector, useRecoilValue, useSetRecoilState, useRecoilCallback, useRecoilState, RecoilRoot } from 'recoil';
2
+ import { atom, selector, useRecoilValue, useRecoilState, useSetRecoilState, useRecoilCallback, RecoilRoot } from 'recoil';
3
3
 
4
4
  function ownKeys(object, enumerableOnly) {
5
5
  var keys = Object.keys(object);
@@ -4313,8 +4313,8 @@ function useResizeObserver(target, callback, enabled) {
4313
4313
  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";
4314
4314
 
4315
4315
  var _excluded$2 = ["type", "rotation", "id", "locked", "layer"],
4316
- _excluded2 = ["x", "y", "layer", "moving"],
4317
- _excluded3 = ["state", "boardSize"];
4316
+ _excluded2 = ["state", "boardSize", "currentUser"],
4317
+ _excluded3 = ["x", "y", "layer", "moving"];
4318
4318
 
4319
4319
  var _templateObject$2;
4320
4320
  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) {
@@ -4364,7 +4364,7 @@ var ItemErrorBoundary = /*#__PURE__*/function (_React$Component) {
4364
4364
  key: "componentDidCatch",
4365
4365
  value: function componentDidCatch(error) {
4366
4366
  // eslint-disable-next-line no-console
4367
- console.log("Error for item ".concat(this.state.itemId), error, this.props.state);
4367
+ console.error("Error for item ".concat(this.state.itemId), error, this.props.state);
4368
4368
  }
4369
4369
  }, {
4370
4370
  key: "onReload",
@@ -4398,6 +4398,10 @@ var ItemErrorBoundary = /*#__PURE__*/function (_React$Component) {
4398
4398
  return ItemErrorBoundary;
4399
4399
  }(React.Component);
4400
4400
 
4401
+ var removeClass = function removeClass(e) {
4402
+ e.target.className = "";
4403
+ };
4404
+
4401
4405
  var Item = function Item(_ref3) {
4402
4406
  var _itemMap$error;
4403
4407
 
@@ -4418,28 +4422,19 @@ var Item = function Item(_ref3) {
4418
4422
  itemMap = _ref3.itemMap,
4419
4423
  unlocked = _ref3.unlocked;
4420
4424
 
4421
- var isMountedRef = React.useRef(false);
4422
4425
  var animateRef = React.useRef(null);
4423
- var Component = itemMap[type].component || null;
4426
+
4427
+ var Component = itemMap[type].component || function () {
4428
+ return null;
4429
+ };
4430
+
4424
4431
  var updateState = React.useCallback(function (callbackOrItem) {
4425
4432
  var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
4426
4433
  return setState(id, callbackOrItem, sync);
4427
- }, [setState, id]); // Update actual size when update
4428
-
4429
- React.useEffect(function () {
4430
- isMountedRef.current = true;
4431
- return function () {
4432
- isMountedRef.current = false;
4433
- };
4434
- }, []);
4434
+ }, [setState, id]);
4435
4435
  React.useEffect(function () {
4436
4436
  animateRef.current.className = animate;
4437
4437
  }, [animate]);
4438
-
4439
- var removeClass = function removeClass(e) {
4440
- e.target.className = "";
4441
- };
4442
-
4443
4438
  var className = "item ".concat(id);
4444
4439
 
4445
4440
  if (locked) {
@@ -4458,6 +4453,9 @@ var Item = function Item(_ref3) {
4458
4453
  "data-id": id,
4459
4454
  className: className
4460
4455
  }, /*#__PURE__*/React.createElement("div", {
4456
+ style: {
4457
+ display: "flex"
4458
+ },
4461
4459
  ref: animateRef,
4462
4460
  onAnimationEnd: removeClass,
4463
4461
  onKeyDown: function onKeyDown(e) {
@@ -4495,31 +4493,42 @@ var MemoizedItem = /*#__PURE__*/memo(Item, function (_ref4, _ref5) {
4495
4493
  nextIsSelected = _ref5.isSelected,
4496
4494
  nextUnlocked = _ref5.unlocked;
4497
4495
  return prevIsSelected === nextIsSelected && prevUnlocked === nextUnlocked && prevSetState === nextSetState && JSON.stringify(prevState) === JSON.stringify(nextState);
4498
- }); // Exclude positionning from memoization
4496
+ }); // Exclude positioning from memoization
4499
4497
 
4500
4498
  var PositionedItem = function PositionedItem(_ref6) {
4501
- var _ref6$state = _ref6.state;
4502
- _ref6$state = _ref6$state === void 0 ? {} : _ref6$state;
4503
-
4504
- var _ref6$state$x = _ref6$state.x,
4505
- x = _ref6$state$x === void 0 ? 0 : _ref6$state$x,
4506
- _ref6$state$y = _ref6$state.y,
4507
- y = _ref6$state$y === void 0 ? 0 : _ref6$state$y,
4508
- layer = _ref6$state.layer,
4509
- moving = _ref6$state.moving,
4510
- stateRest = _objectWithoutProperties(_ref6$state, _excluded2),
4499
+ var _rest$itemMap$state$t;
4500
+
4501
+ var _ref6$state = _ref6.state,
4502
+ state = _ref6$state === void 0 ? {} : _ref6$state,
4511
4503
  boardSize = _ref6.boardSize,
4512
- rest = _objectWithoutProperties(_ref6, _excluded3);
4504
+ currentUser = _ref6.currentUser,
4505
+ rest = _objectWithoutProperties(_ref6, _excluded2);
4506
+
4507
+ 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) {
4508
+ return st;
4509
+ };
4510
+
4511
+ var _stateTrans = stateTrans(state, {
4512
+ currentUser: currentUser
4513
+ }),
4514
+ _stateTrans$x = _stateTrans.x,
4515
+ x = _stateTrans$x === void 0 ? 0 : _stateTrans$x,
4516
+ _stateTrans$y = _stateTrans.y,
4517
+ y = _stateTrans$y === void 0 ? 0 : _stateTrans$y,
4518
+ _stateTrans$layer = _stateTrans.layer,
4519
+ layer = _stateTrans$layer === void 0 ? 0 : _stateTrans$layer,
4520
+ moving = _stateTrans.moving,
4521
+ stateRest = _objectWithoutProperties(_stateTrans, _excluded3);
4513
4522
 
4514
4523
  return /*#__PURE__*/React.createElement("div", {
4515
4524
  style: {
4516
- transform: "translate(".concat(x, "px, ").concat(y, "px)"),
4517
- display: "inline-block",
4518
- zIndex: ((layer || 0) + 4) * 10 + 100 + (moving ? 5 : 0),
4519
- // Items z-index between 100 and 200
4520
4525
  position: "absolute",
4521
4526
  top: "".concat(boardSize / 2, "px"),
4522
- left: "".concat(boardSize / 2, "px")
4527
+ left: "".concat(boardSize / 2, "px"),
4528
+ display: "inline-block",
4529
+ transform: "translate(".concat(x, "px, ").concat(y, "px)"),
4530
+ zIndex: (layer + 4) * 10 + 100 + (moving ? 5 : 0) // Items z-index between 100 and 200
4531
+
4523
4532
  }
4524
4533
  }, /*#__PURE__*/React.createElement(MemoizedItem, _extends$1({}, rest, {
4525
4534
  state: stateRest
@@ -4528,6 +4537,211 @@ var PositionedItem = function PositionedItem(_ref6) {
4528
4537
 
4529
4538
  var MemoizedPositionedItem = /*#__PURE__*/memo(PositionedItem);
4530
4539
 
4540
+ var persistUser = function persistUser(user) {
4541
+ localStorage.setItem("user", JSON.stringify(user));
4542
+ };
4543
+ 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"];
4544
+
4545
+ var getRandomColor = function getRandomColor() {
4546
+ return colors[Math.floor(Math.random() * colors.length)];
4547
+ }; // TODO remove user persistence
4548
+
4549
+
4550
+ var getUser = function getUser() {
4551
+ if (localStorage.user) {
4552
+ // Add some mandatory info if missing
4553
+ var localUser = _objectSpread2({
4554
+ name: "Player",
4555
+ color: getRandomColor(),
4556
+ uid: nanoid()
4557
+ }, JSON.parse(localStorage.user)); // Id is given by server
4558
+ // delete localUser.id;
4559
+
4560
+
4561
+ persistUser(localUser);
4562
+ return localUser;
4563
+ }
4564
+
4565
+ var newUser = {
4566
+ name: "Player",
4567
+ color: getRandomColor(),
4568
+ uid: nanoid()
4569
+ };
4570
+ persistUser(newUser);
4571
+ return newUser;
4572
+ };
4573
+ var userAtom = atom({
4574
+ key: "user",
4575
+ "default": getUser()
4576
+ });
4577
+ var usersAtom = atom({
4578
+ key: "users",
4579
+ "default": []
4580
+ });
4581
+ var localUsersAtom = selector({
4582
+ key: "localUsersAtom",
4583
+ get: function get(_ref) {
4584
+ var _get = _ref.get;
4585
+
4586
+ var currentUser = _get(userAtom);
4587
+
4588
+ var users = _get(usersAtom);
4589
+
4590
+ return users.filter(function (_ref2) {
4591
+ var space = _ref2.space;
4592
+ return space === currentUser.space;
4593
+ });
4594
+ }
4595
+ });
4596
+
4597
+ var useUsers = function useUsers() {
4598
+ var _useRecoilState = useRecoilState(userAtom),
4599
+ _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
4600
+ currentUser = _useRecoilState2[0],
4601
+ setCurrentUserState = _useRecoilState2[1];
4602
+
4603
+ var users = useRecoilValue(usersAtom);
4604
+ var localUsers = useRecoilValue(localUsersAtom);
4605
+ var setCurrentUser = React.useCallback(function (callbackOrUser) {
4606
+ var callback = callbackOrUser;
4607
+
4608
+ if (_typeof(callbackOrUser) === "object") {
4609
+ callback = function callback() {
4610
+ return callbackOrUser;
4611
+ };
4612
+ }
4613
+
4614
+ setCurrentUserState(function (prevUser) {
4615
+ var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
4616
+ id: prevUser.id,
4617
+ uid: prevUser.uid
4618
+ });
4619
+
4620
+ persistUser(newUser);
4621
+ return newUser;
4622
+ });
4623
+ }, [setCurrentUserState]);
4624
+ React.useEffect(function () {
4625
+ // eslint-disable-next-line no-console
4626
+ console.debug("Curent user is in space ".concat(currentUser.space));
4627
+ }, [currentUser.space]);
4628
+ return {
4629
+ currentUser: currentUser,
4630
+ setCurrentUser: setCurrentUser,
4631
+ users: users,
4632
+ localUsers: localUsers
4633
+ };
4634
+ };
4635
+
4636
+ var SubscribeUserEvents = function SubscribeUserEvents() {
4637
+ var usersRef = React.useRef([]);
4638
+ var setUsers = useSetRecoilState(usersAtom);
4639
+
4640
+ var _useRecoilState = useRecoilState(userAtom),
4641
+ _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
4642
+ currentUser = _useRecoilState2[0],
4643
+ setCurrentUserState = _useRecoilState2[1];
4644
+
4645
+ var _useWire = useWire("room"),
4646
+ wire = _useWire.wire,
4647
+ isMaster = _useWire.isMaster,
4648
+ roomSpace = _useWire.room;
4649
+
4650
+ React.useEffect(function () {
4651
+ setCurrentUserState(function (prevUser) {
4652
+ return _objectSpread2(_objectSpread2({}, prevUser), {}, {
4653
+ id: wire.userId,
4654
+ space: roomSpace
4655
+ });
4656
+ });
4657
+ return function () {
4658
+ setCurrentUserState(function (prevUser) {
4659
+ return _objectSpread2(_objectSpread2({}, prevUser), {}, {
4660
+ id: wire.userId,
4661
+ space: null
4662
+ });
4663
+ });
4664
+ };
4665
+ }, [wire.userId, roomSpace, setCurrentUserState]);
4666
+ React.useEffect(function () {
4667
+ if (!isMaster) {
4668
+ var onGetUserList = function onGetUserList(userList) {
4669
+ usersRef.current = userList;
4670
+ setUsers(userList);
4671
+ };
4672
+
4673
+ wire.call("getUserList").then(onGetUserList, function () {
4674
+ // retry later
4675
+ setTimeout(function () {
4676
+ wire.call("getUserList") // eslint-disable-next-line no-console
4677
+ .then(onGetUserList, function (error) {
4678
+ return console.log(error);
4679
+ });
4680
+ }, 1000);
4681
+ });
4682
+ }
4683
+ }, [wire, isMaster, setUsers]); // eslint-disable-next-line react-hooks/exhaustive-deps
4684
+
4685
+ var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
4686
+ wire.publish("userUpdate", newUser, true);
4687
+ }, [wire], 500);
4688
+ React.useEffect(function () {
4689
+ if (currentUser && currentUser.id) {
4690
+ debouncedEmitUpdateUser(currentUser);
4691
+ }
4692
+ }, [currentUser, debouncedEmitUpdateUser]);
4693
+ React.useEffect(function () {
4694
+ var unsub = [];
4695
+
4696
+ if (isMaster) {
4697
+ wire.register("getUserList", function () {
4698
+ return usersRef.current;
4699
+ }).then(function (unregister) {
4700
+ unsub.push(unregister);
4701
+ });
4702
+ unsub.push(wire.subscribe("userUpdate", function (user) {
4703
+ if (usersRef.current.find(function (u) {
4704
+ return u.id === user.id;
4705
+ })) {
4706
+ var newUsers = usersRef.current.map(function (u) {
4707
+ return u.id === user.id ? user : u;
4708
+ });
4709
+ usersRef.current = newUsers;
4710
+ } else {
4711
+ var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
4712
+
4713
+ usersRef.current = _newUsers;
4714
+ }
4715
+
4716
+ setUsers(usersRef.current);
4717
+ wire.publish("updateUserList", usersRef.current);
4718
+ }));
4719
+ }
4720
+
4721
+ unsub.push(wire.subscribe("userLeave", function (userId) {
4722
+ usersRef.current = usersRef.current.filter(function (_ref) {
4723
+ var id = _ref.id;
4724
+ return id !== userId;
4725
+ });
4726
+ setUsers(usersRef.current);
4727
+
4728
+ if (isMaster) {
4729
+ wire.publish("updateUserList", usersRef.current);
4730
+ }
4731
+ }));
4732
+ unsub.push(wire.subscribe("updateUserList", function (newList) {
4733
+ usersRef.current = newList;
4734
+ setUsers(usersRef.current);
4735
+ }));
4736
+ return function () {
4737
+ unsub.forEach(function (u) {
4738
+ return u();
4739
+ });
4740
+ };
4741
+ }, [wire, isMaster, setUsers]);
4742
+ return null;
4743
+ };
4744
+
4531
4745
  /** Allow to operate on locked items while u or l key is pressed */
4532
4746
 
4533
4747
  var useUnlock = function useUnlock() {
@@ -4572,6 +4786,9 @@ var ItemList = function ItemList(_ref) {
4572
4786
  var _useRecoilValue = useRecoilValue(ConfigurationAtom),
4573
4787
  boardSize = _useRecoilValue.boardSize;
4574
4788
 
4789
+ var _useUsers = useUsers(),
4790
+ currentUser = _useUsers.currentUser;
4791
+
4575
4792
  var unlocked = useUnlock();
4576
4793
  return itemList.map(function (itemId) {
4577
4794
  return /*#__PURE__*/React.createElement(MemoizedPositionedItem, {
@@ -4581,7 +4798,8 @@ var ItemList = function ItemList(_ref) {
4581
4798
  isSelected: selectedItems.includes(itemId),
4582
4799
  unlocked: unlocked,
4583
4800
  itemMap: itemTemplates,
4584
- boardSize: boardSize
4801
+ boardSize: boardSize,
4802
+ currentUser: currentUser
4585
4803
  });
4586
4804
  });
4587
4805
  };
@@ -5105,6 +5323,8 @@ var Gesture = function Gesture(_ref6) {
5105
5323
  deltaY: 0,
5106
5324
  startX: stateRef.current.startX,
5107
5325
  startY: stateRef.current.startY,
5326
+ clientX: stateRef.current.startX,
5327
+ clientY: stateRef.current.startY,
5108
5328
  distanceX: 0,
5109
5329
  distanceY: 0,
5110
5330
  button: stateRef.current.currentButton,
@@ -5127,6 +5347,8 @@ var Gesture = function Gesture(_ref6) {
5127
5347
  deltaY: deltaY,
5128
5348
  startX: stateRef.current.startX,
5129
5349
  startY: stateRef.current.startY,
5350
+ clientX: clientX,
5351
+ clientY: clientY,
5130
5352
  distanceX: distanceX,
5131
5353
  distanceY: distanceY,
5132
5354
  button: stateRef.current.currentButton,
@@ -5232,6 +5454,8 @@ var Gesture = function Gesture(_ref6) {
5232
5454
  deltaY: clientY - stateRef.current.prevY,
5233
5455
  startX: stateRef.current.startX,
5234
5456
  startY: stateRef.current.startY,
5457
+ clientX: clientX,
5458
+ clientY: clientY,
5235
5459
  distanceX: clientX - stateRef.current.startX,
5236
5460
  distanceY: clientY - stateRef.current.startY,
5237
5461
  button: stateRef.current.currentButton,
@@ -5313,6 +5537,9 @@ var Selector = function Selector(_ref) {
5313
5537
  var setSelected = useSetRecoilState(SelectedItemsAtom);
5314
5538
  var setBoardState = useSetRecoilState(BoardStateAtom);
5315
5539
 
5540
+ var _useItemActions = useItemActions(),
5541
+ findElementUnderPointer = _useItemActions.findElementUnderPointer;
5542
+
5316
5543
  var _React$useState = React.useState({}),
5317
5544
  _React$useState2 = _slicedToArray(_React$useState, 2),
5318
5545
  selector = _React$useState2[0],
@@ -5377,50 +5604,68 @@ var Selector = function Selector(_ref) {
5377
5604
  }, [setSelected]);
5378
5605
  useThrottledEffect(updateSelected, [selector, updateSelected], 200);
5379
5606
 
5380
- var onDragStart = function onDragStart(_ref4) {
5381
- var button = _ref4.button,
5382
- altKey = _ref4.altKey,
5383
- ctrlKey = _ref4.ctrlKey,
5384
- metaKey = _ref4.metaKey,
5385
- target = _ref4.target;
5386
- var outsideItem = !insideClass(target, "item") || insideClass(target, "locked");
5387
- var metaKeyPressed = altKey || ctrlKey || metaKey;
5388
- var goodButton = moveFirst ? button === 1 || button === 0 && metaKeyPressed : button === 0 && !metaKeyPressed;
5607
+ var onDragStart = /*#__PURE__*/function () {
5608
+ var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(event) {
5609
+ var button, altKey, ctrlKey, metaKey, foundElement, metaKeyPressed, goodButton;
5610
+ return regeneratorRuntime.wrap(function _callee2$(_context2) {
5611
+ while (1) {
5612
+ switch (_context2.prev = _context2.next) {
5613
+ case 0:
5614
+ button = event.button, altKey = event.altKey, ctrlKey = event.ctrlKey, metaKey = event.metaKey;
5615
+ _context2.next = 3;
5616
+ return findElementUnderPointer(event);
5389
5617
 
5390
- if (goodButton && (outsideItem || moveFirst)) {
5391
- stateRef.current.moving = true;
5392
- setBoardState(function (prev) {
5393
- return _objectSpread2(_objectSpread2({}, prev), {}, {
5394
- selecting: true
5395
- });
5396
- });
5397
- wrapperRef.current.style.cursor = "crosshair";
5398
- }
5399
- };
5618
+ case 3:
5619
+ foundElement = _context2.sent;
5620
+ metaKeyPressed = altKey || ctrlKey || metaKey;
5621
+ goodButton = moveFirst ? button === 1 || button === 0 && metaKeyPressed : button === 0 && !metaKeyPressed;
5622
+
5623
+ if (goodButton && (!foundElement || moveFirst)) {
5624
+ stateRef.current.moving = true;
5625
+ setBoardState(function (prev) {
5626
+ return _objectSpread2(_objectSpread2({}, prev), {}, {
5627
+ selecting: true
5628
+ });
5629
+ });
5630
+ wrapperRef.current.style.cursor = "crosshair";
5631
+ }
5632
+
5633
+ case 7:
5634
+ case "end":
5635
+ return _context2.stop();
5636
+ }
5637
+ }
5638
+ }, _callee2);
5639
+ }));
5640
+
5641
+ return function onDragStart(_x) {
5642
+ return _ref4.apply(this, arguments);
5643
+ };
5644
+ }();
5400
5645
 
5401
5646
  var onDrag = useRecoilCallback(function (_ref5) {
5402
5647
  var snapshot = _ref5.snapshot;
5403
5648
  return /*#__PURE__*/function () {
5404
- var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref6) {
5649
+ var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref6) {
5405
5650
  var distanceY, distanceX, startX, startY, _wrapperRef$current$g, top, left, _yield$snapshot$getPr2, scale, displayX, displayY, displayDistanceX, displayDistanceY;
5406
5651
 
5407
- return regeneratorRuntime.wrap(function _callee2$(_context2) {
5652
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
5408
5653
  while (1) {
5409
- switch (_context2.prev = _context2.next) {
5654
+ switch (_context3.prev = _context3.next) {
5410
5655
  case 0:
5411
5656
  distanceY = _ref6.distanceY, distanceX = _ref6.distanceX, startX = _ref6.startX, startY = _ref6.startY;
5412
5657
 
5413
5658
  if (!stateRef.current.moving) {
5414
- _context2.next = 14;
5659
+ _context3.next = 14;
5415
5660
  break;
5416
5661
  }
5417
5662
 
5418
5663
  _wrapperRef$current$g = wrapperRef.current.getBoundingClientRect(), top = _wrapperRef$current$g.top, left = _wrapperRef$current$g.left;
5419
- _context2.next = 5;
5664
+ _context3.next = 5;
5420
5665
  return snapshot.getPromise(BoardTransformAtom);
5421
5666
 
5422
5667
  case 5:
5423
- _yield$snapshot$getPr2 = _context2.sent;
5668
+ _yield$snapshot$getPr2 = _context3.sent;
5424
5669
  scale = _yield$snapshot$getPr2.scale;
5425
5670
  displayX = (startX - left) / scale;
5426
5671
  displayY = (startY - top) / scale;
@@ -5449,13 +5694,13 @@ var Selector = function Selector(_ref) {
5449
5694
 
5450
5695
  case 14:
5451
5696
  case "end":
5452
- return _context2.stop();
5697
+ return _context3.stop();
5453
5698
  }
5454
5699
  }
5455
- }, _callee2);
5700
+ }, _callee3);
5456
5701
  }));
5457
5702
 
5458
- return function (_x) {
5703
+ return function (_x2) {
5459
5704
  return _ref7.apply(this, arguments);
5460
5705
  };
5461
5706
  }();
@@ -5488,43 +5733,47 @@ var Selector = function Selector(_ref) {
5488
5733
  var onTap = useRecoilCallback(function (_ref9) {
5489
5734
  var snapshot = _ref9.snapshot;
5490
5735
  return /*#__PURE__*/function () {
5491
- var _ref11 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref10) {
5492
- var target, ctrlKey, metaKey, foundItem, itemId, selectedItems;
5493
- return regeneratorRuntime.wrap(function _callee3$(_context3) {
5736
+ var _ref10 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(event) {
5737
+ var target, ctrlKey, metaKey, foundElement, itemId, selectedItems;
5738
+ return regeneratorRuntime.wrap(function _callee4$(_context4) {
5494
5739
  while (1) {
5495
- switch (_context3.prev = _context3.next) {
5740
+ switch (_context4.prev = _context4.next) {
5496
5741
  case 0:
5497
- target = _ref10.target, ctrlKey = _ref10.ctrlKey, metaKey = _ref10.metaKey;
5498
- foundItem = insideClass(target, "item");
5742
+ target = event.target, ctrlKey = event.ctrlKey, metaKey = event.metaKey;
5743
+ _context4.next = 3;
5744
+ return findElementUnderPointer(event);
5745
+
5746
+ case 3:
5747
+ foundElement = _context4.sent;
5499
5748
 
5500
- if (!((!foundItem || insideClass(foundItem, "locked")) && insideClass(target, "board"))) {
5501
- _context3.next = 6;
5749
+ if (!(!foundElement && insideClass(target, "board"))) {
5750
+ _context4.next = 8;
5502
5751
  break;
5503
5752
  }
5504
5753
 
5505
5754
  setSelected([]);
5506
- _context3.next = 14;
5755
+ _context4.next = 16;
5507
5756
  break;
5508
5757
 
5509
- case 6:
5510
- itemId = getIdFromElem(foundItem); // Being defensive here to avoid bug
5758
+ case 8:
5759
+ itemId = getIdFromElem(foundElement); // Being defensive here to avoid bug
5511
5760
 
5512
5761
  if (itemId) {
5513
- _context3.next = 10;
5762
+ _context4.next = 12;
5514
5763
  break;
5515
5764
  }
5516
5765
 
5517
5766
  setSelected([]);
5518
- return _context3.abrupt("return");
5767
+ return _context4.abrupt("return");
5519
5768
 
5520
- case 10:
5521
- _context3.next = 12;
5769
+ case 12:
5770
+ _context4.next = 14;
5522
5771
  return snapshot.getPromise(SelectedItemsAtom);
5523
5772
 
5524
- case 12:
5525
- selectedItems = _context3.sent;
5773
+ case 14:
5774
+ selectedItems = _context4.sent;
5526
5775
 
5527
- if (foundItem && !selectedItems.includes(itemId)) {
5776
+ if (foundElement && !selectedItems.includes(itemId)) {
5528
5777
  if (ctrlKey || metaKey) {
5529
5778
  setSelected(function (prev) {
5530
5779
  return [].concat(_toConsumableArray(prev), [itemId]);
@@ -5534,19 +5783,19 @@ var Selector = function Selector(_ref) {
5534
5783
  }
5535
5784
  }
5536
5785
 
5537
- case 14:
5786
+ case 16:
5538
5787
  case "end":
5539
- return _context3.stop();
5788
+ return _context4.stop();
5540
5789
  }
5541
5790
  }
5542
- }, _callee3);
5791
+ }, _callee4);
5543
5792
  }));
5544
5793
 
5545
- return function (_x2) {
5546
- return _ref11.apply(this, arguments);
5794
+ return function (_x3) {
5795
+ return _ref10.apply(this, arguments);
5547
5796
  };
5548
5797
  }();
5549
- }, [setSelected]);
5798
+ }, [findElementUnderPointer, setSelected]);
5550
5799
  return /*#__PURE__*/React.createElement(Gesture, {
5551
5800
  onDragStart: onDragStart,
5552
5801
  onDrag: onDrag,
@@ -5570,11 +5819,11 @@ var ActionPane = function ActionPane(_ref) {
5570
5819
 
5571
5820
  var _useItemActions = useItemActions(),
5572
5821
  moveItems = _useItemActions.moveItems,
5573
- placeItems = _useItemActions.placeItems;
5822
+ placeItems = _useItemActions.placeItems,
5823
+ findElementUnderPointer = _useItemActions.findElementUnderPointer;
5574
5824
 
5575
5825
  var setSelectedItems = useSetRecoilState(SelectedItemsAtom);
5576
5826
  var setBoardState = useSetRecoilState(BoardStateAtom);
5577
- var wrapperRef = React.useRef(null);
5578
5827
  var actionRef = React.useRef({}); // Use ref because pointer events are faster than react state management
5579
5828
 
5580
5829
  var selectedItemRef = React.useRef({
@@ -5583,30 +5832,25 @@ var ActionPane = function ActionPane(_ref) {
5583
5832
  var onDragStart = useRecoilCallback(function (_ref2) {
5584
5833
  var snapshot = _ref2.snapshot;
5585
5834
  return /*#__PURE__*/function () {
5586
- var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref3) {
5587
- var target, ctrlKey, metaKey, event, foundElement, selectedItems, itemId;
5835
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(event) {
5836
+ var ctrlKey, metaKey, originalEvent, foundElement, selectedItems, itemId;
5588
5837
  return regeneratorRuntime.wrap(function _callee$(_context) {
5589
5838
  while (1) {
5590
5839
  switch (_context.prev = _context.next) {
5591
5840
  case 0:
5592
- target = _ref3.target, ctrlKey = _ref3.ctrlKey, metaKey = _ref3.metaKey, event = _ref3.event;
5593
-
5594
- if (!["INPUT", "TEXTAREA"].includes(target.tagName)) {
5595
- _context.next = 3;
5596
- break;
5597
- }
5598
-
5599
- return _context.abrupt("return");
5841
+ ctrlKey = event.ctrlKey, metaKey = event.metaKey, originalEvent = event.event;
5842
+ _context.next = 3;
5843
+ return findElementUnderPointer(event);
5600
5844
 
5601
5845
  case 3:
5602
- foundElement = insideClass(target, "item");
5846
+ foundElement = _context.sent;
5603
5847
 
5604
- if (!(foundElement && !hasClass(foundElement, "locked"))) {
5848
+ if (!foundElement) {
5605
5849
  _context.next = 13;
5606
5850
  break;
5607
5851
  }
5608
5852
 
5609
- event.stopPropagation();
5853
+ originalEvent.stopPropagation();
5610
5854
  _context.next = 8;
5611
5855
  return snapshot.getPromise(SelectedItemsAtom);
5612
5856
 
@@ -5642,21 +5886,21 @@ var ActionPane = function ActionPane(_ref) {
5642
5886
  }));
5643
5887
 
5644
5888
  return function (_x) {
5645
- return _ref4.apply(this, arguments);
5889
+ return _ref3.apply(this, arguments);
5646
5890
  };
5647
5891
  }();
5648
- }, [setSelectedItems]);
5649
- var onDrag = useRecoilCallback(function (_ref5) {
5650
- var snapshot = _ref5.snapshot;
5892
+ }, [findElementUnderPointer, setSelectedItems]);
5893
+ var onDrag = useRecoilCallback(function (_ref4) {
5894
+ var snapshot = _ref4.snapshot;
5651
5895
  return /*#__PURE__*/function () {
5652
- var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref6) {
5896
+ var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(_ref5) {
5653
5897
  var deltaX, deltaY, _yield$snapshot$getPr, scale, moveX, moveY;
5654
5898
 
5655
5899
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
5656
5900
  while (1) {
5657
5901
  switch (_context2.prev = _context2.next) {
5658
5902
  case 0:
5659
- deltaX = _ref6.deltaX, deltaY = _ref6.deltaY;
5903
+ deltaX = _ref5.deltaX, deltaY = _ref5.deltaY;
5660
5904
 
5661
5905
  if (!actionRef.current.moving) {
5662
5906
  _context2.next = 10;
@@ -5690,12 +5934,12 @@ var ActionPane = function ActionPane(_ref) {
5690
5934
  }));
5691
5935
 
5692
5936
  return function (_x2) {
5693
- return _ref7.apply(this, arguments);
5937
+ return _ref6.apply(this, arguments);
5694
5938
  };
5695
5939
  }();
5696
5940
  }, [moveItems, setBoardState]);
5697
- var onDragEnd = useRecoilCallback(function (_ref8) {
5698
- var snapshot = _ref8.snapshot;
5941
+ var onDragEnd = useRecoilCallback(function (_ref7) {
5942
+ var snapshot = _ref7.snapshot;
5699
5943
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
5700
5944
  var _yield$snapshot$getPr2, _yield$snapshot$getPr3, boardGridSize, gridSize;
5701
5945
 
@@ -5738,10 +5982,10 @@ var ActionPane = function ActionPane(_ref) {
5738
5982
  }, _callee3);
5739
5983
  }));
5740
5984
  }, [placeItems, setBoardState]);
5741
- var onKeyDown = useRecoilCallback(function (_ref10) {
5742
- var snapshot = _ref10.snapshot;
5985
+ var onKeyDown = useRecoilCallback(function (_ref9) {
5986
+ var snapshot = _ref9.snapshot;
5743
5987
  return /*#__PURE__*/function () {
5744
- var _ref11 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(e) {
5988
+ var _ref10 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(e) {
5745
5989
  var selectedItems, _yield$snapshot$getPr4, _yield$snapshot$getPr5, boardGridSize, moveX, moveY, gridSize;
5746
5990
 
5747
5991
  return regeneratorRuntime.wrap(function _callee4$(_context4) {
@@ -5834,7 +6078,7 @@ var ActionPane = function ActionPane(_ref) {
5834
6078
  }));
5835
6079
 
5836
6080
  return function (_x3) {
5837
- return _ref11.apply(this, arguments);
6081
+ return _ref10.apply(this, arguments);
5838
6082
  };
5839
6083
  }();
5840
6084
  }, [moveItems, placeItems]);
@@ -5848,9 +6092,7 @@ var ActionPane = function ActionPane(_ref) {
5848
6092
  onDragStart: onDragStart,
5849
6093
  onDrag: onDrag,
5850
6094
  onDragEnd: onDragEnd
5851
- }, /*#__PURE__*/React.createElement("div", {
5852
- ref: wrapperRef
5853
- }, children));
6095
+ }, children);
5854
6096
  };
5855
6097
 
5856
6098
  function t(t, n, r) {
@@ -6049,297 +6291,104 @@ var Cursor = function Cursor(_ref3) {
6049
6291
 
6050
6292
  var MemoizedCursor = /*#__PURE__*/React.memo(Cursor);
6051
6293
 
6052
- var PositionnedCursor = function PositionnedCursor(_ref4) {
6053
- var pos = _ref4.pos,
6054
- rest = _objectWithoutProperties(_ref4, _excluded$1);
6055
-
6056
- return /*#__PURE__*/React.createElement("div", {
6057
- style: {
6058
- transform: "translate(".concat(pos.x - 5, "px, ").concat(pos.y - 3, "px)"),
6059
- top: 0,
6060
- left: 0,
6061
- zIndex: 210,
6062
- position: "fixed",
6063
- pointerEvents: "none"
6064
- }
6065
- }, /*#__PURE__*/React.createElement(MemoizedCursor, rest));
6066
- };
6067
-
6068
- var Cursors = function Cursors(_ref) {
6069
- var users = _ref.users;
6070
-
6071
- var _useWire = useWire("board"),
6072
- wire = _useWire.wire;
6073
-
6074
- var _React$useState = React.useState({}),
6075
- _React$useState2 = _slicedToArray(_React$useState, 2),
6076
- cursors = _React$useState2[0],
6077
- setCursors = _React$useState2[1];
6078
-
6079
- var preventRef = React.useRef(false);
6080
- var usersById = React.useMemo(function () {
6081
- return users.reduce(function (acc, user) {
6082
- acc[user.id] = user;
6083
- return acc;
6084
- }, {});
6085
- }, [users]); // Prevent race condition when removing user
6086
-
6087
- var currentCursor = React.useMemo(function () {
6088
- return users.reduce(function (acc, user) {
6089
- if (cursors[user.id]) {
6090
- acc[user.id] = cursors[user.id];
6091
- }
6092
-
6093
- return acc;
6094
- }, {});
6095
- }, [users, cursors]);
6096
- React.useEffect(function () {
6097
- setCursors(function (prevCursors) {
6098
- return users.reduce(function (acc, user) {
6099
- if (prevCursors[user.id]) {
6100
- acc[user.id] = prevCursors[user.id];
6101
- }
6102
-
6103
- return acc;
6104
- }, {});
6105
- });
6106
- }, [users]);
6107
- React.useEffect(function () {
6108
- var unsub = [];
6109
- unsub.push(wire.subscribe("cursorMove", function (_ref2) {
6110
- var userId = _ref2.userId,
6111
- pos = _ref2.pos;
6112
- // Avoid move after cursor off
6113
- if (preventRef.current) return;
6114
- setCursors(function (prevCursors) {
6115
- return _objectSpread2(_objectSpread2({}, prevCursors), {}, _defineProperty({}, userId, pos));
6116
- });
6117
- }));
6118
- unsub.push(wire.subscribe("cursorOff", function (_ref3) {
6119
- var userId = _ref3.userId;
6120
- setCursors(function (prevCursors) {
6121
- var newCursors = _objectSpread2({}, prevCursors);
6122
-
6123
- delete newCursors[userId];
6124
- return newCursors;
6125
- }); // Prevent next moves
6126
-
6127
- preventRef.current = true;
6128
- setTimeout(function () {
6129
- preventRef.current = false;
6130
- }, 100);
6131
- }));
6132
- return function () {
6133
- unsub.map(function (c) {
6134
- return c();
6135
- });
6136
- };
6137
- }, [wire]);
6138
- return /*#__PURE__*/React.createElement("div", null, Object.entries(currentCursor).map(function (_ref4) {
6139
- var _ref5 = _slicedToArray(_ref4, 2),
6140
- userId = _ref5[0],
6141
- pos = _ref5[1];
6142
-
6143
- return /*#__PURE__*/React.createElement(PositionnedCursor, {
6144
- key: userId,
6145
- pos: pos,
6146
- text: usersById[userId].name,
6147
- color: usersById[userId].color
6148
- });
6149
- }));
6150
- };
6151
-
6152
- var persistUser = function persistUser(user) {
6153
- localStorage.setItem("user", JSON.stringify(user));
6154
- };
6155
- 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"];
6156
-
6157
- var getRandomColor = function getRandomColor() {
6158
- return colors[Math.floor(Math.random() * colors.length)];
6159
- }; // TODO remove user persistence
6160
-
6161
-
6162
- var getUser = function getUser() {
6163
- if (localStorage.user) {
6164
- // Add some mandatory info if missing
6165
- var localUser = _objectSpread2({
6166
- name: "Player",
6167
- color: getRandomColor(),
6168
- uid: nanoid()
6169
- }, JSON.parse(localStorage.user)); // Id is given by server
6170
- // delete localUser.id;
6171
-
6172
-
6173
- persistUser(localUser);
6174
- return localUser;
6175
- }
6176
-
6177
- var newUser = {
6178
- name: "Player",
6179
- color: getRandomColor(),
6180
- uid: nanoid()
6181
- };
6182
- persistUser(newUser);
6183
- return newUser;
6184
- };
6185
- var userAtom = atom({
6186
- key: "user",
6187
- "default": getUser()
6188
- });
6189
- var usersAtom = atom({
6190
- key: "users",
6191
- "default": []
6192
- });
6193
-
6194
- var useUsers = function useUsers() {
6195
- var _useRecoilState = useRecoilState(userAtom),
6196
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
6197
- currentUser = _useRecoilState2[0],
6198
- setCurrentUserState = _useRecoilState2[1];
6199
-
6200
- var users = useRecoilValue(usersAtom);
6201
- var setCurrentUser = React.useCallback(function (callbackOrUser) {
6202
- var callback = callbackOrUser;
6203
-
6204
- if (_typeof(callbackOrUser) === "object") {
6205
- callback = function callback() {
6206
- return callbackOrUser;
6207
- };
6208
- }
6209
-
6210
- setCurrentUserState(function (prevUser) {
6211
- var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
6212
- id: prevUser.id,
6213
- uid: prevUser.uid
6214
- });
6215
-
6216
- persistUser(newUser);
6217
- return newUser;
6218
- });
6219
- }, [setCurrentUserState]);
6220
- var localUsers = React.useMemo(function () {
6221
- // eslint-disable-next-line no-console
6222
- console.debug("Curent user is in space ".concat(currentUser.space));
6223
- return users.filter(function (_ref) {
6224
- var space = _ref.space;
6225
- return space === currentUser.space;
6226
- });
6227
- }, [currentUser.space, users]);
6228
- return {
6229
- currentUser: currentUser,
6230
- setCurrentUser: setCurrentUser,
6231
- users: users,
6232
- localUsers: localUsers
6233
- };
6294
+ var PositionnedCursor = function PositionnedCursor(_ref4) {
6295
+ var pos = _ref4.pos,
6296
+ rest = _objectWithoutProperties(_ref4, _excluded$1);
6297
+
6298
+ return /*#__PURE__*/React.createElement("div", {
6299
+ style: {
6300
+ transform: "translate(".concat(pos.x - 5, "px, ").concat(pos.y - 3, "px)"),
6301
+ top: 0,
6302
+ left: 0,
6303
+ zIndex: 210,
6304
+ position: "fixed",
6305
+ pointerEvents: "none"
6306
+ }
6307
+ }, /*#__PURE__*/React.createElement(MemoizedCursor, rest));
6234
6308
  };
6235
6309
 
6236
- var SubscribeUserEvents = function SubscribeUserEvents() {
6237
- var usersRef = React.useRef([]);
6238
- var setUsers = useSetRecoilState(usersAtom);
6310
+ var Cursors = function Cursors(_ref) {
6311
+ var users = _ref.users;
6239
6312
 
6240
- var _useRecoilState = useRecoilState(userAtom),
6241
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
6242
- currentUser = _useRecoilState2[0],
6243
- setCurrentUserState = _useRecoilState2[1];
6313
+ var _useWire = useWire("board"),
6314
+ wire = _useWire.wire;
6244
6315
 
6245
- var _useWire = useWire("room"),
6246
- wire = _useWire.wire,
6247
- isMaster = _useWire.isMaster,
6248
- roomSpace = _useWire.room;
6316
+ var _React$useState = React.useState({}),
6317
+ _React$useState2 = _slicedToArray(_React$useState, 2),
6318
+ cursors = _React$useState2[0],
6319
+ setCursors = _React$useState2[1];
6249
6320
 
6250
- React.useEffect(function () {
6251
- setCurrentUserState(function (prevUser) {
6252
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
6253
- id: wire.userId,
6254
- space: roomSpace
6255
- });
6256
- });
6257
- return function () {
6258
- setCurrentUserState(function (prevUser) {
6259
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
6260
- id: wire.userId,
6261
- space: null
6262
- });
6263
- });
6264
- };
6265
- }, [wire.userId, roomSpace, setCurrentUserState]);
6266
- React.useEffect(function () {
6267
- if (!isMaster) {
6268
- var onGetUserList = function onGetUserList(userList) {
6269
- usersRef.current = userList;
6270
- setUsers(userList);
6271
- };
6321
+ var preventRef = React.useRef(false);
6322
+ var usersById = React.useMemo(function () {
6323
+ return users.reduce(function (acc, user) {
6324
+ acc[user.id] = user;
6325
+ return acc;
6326
+ }, {});
6327
+ }, [users]); // Prevent race condition when removing user
6272
6328
 
6273
- wire.call("getUserList").then(onGetUserList, function () {
6274
- // retry later
6275
- setTimeout(function () {
6276
- wire.call("getUserList") // eslint-disable-next-line no-console
6277
- .then(onGetUserList, function (error) {
6278
- return console.log(error);
6279
- });
6280
- }, 1000);
6281
- });
6282
- }
6283
- }, [wire, isMaster, setUsers]); // eslint-disable-next-line react-hooks/exhaustive-deps
6329
+ var currentCursor = React.useMemo(function () {
6330
+ return users.reduce(function (acc, user) {
6331
+ if (cursors[user.id]) {
6332
+ acc[user.id] = cursors[user.id];
6333
+ }
6284
6334
 
6285
- var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
6286
- wire.publish("userUpdate", newUser, true);
6287
- }, [wire], 500);
6335
+ return acc;
6336
+ }, {});
6337
+ }, [users, cursors]);
6288
6338
  React.useEffect(function () {
6289
- if (currentUser && currentUser.id) {
6290
- debouncedEmitUpdateUser(currentUser);
6291
- }
6292
- }, [currentUser, debouncedEmitUpdateUser]);
6339
+ setCursors(function (prevCursors) {
6340
+ return users.reduce(function (acc, user) {
6341
+ if (prevCursors[user.id]) {
6342
+ acc[user.id] = prevCursors[user.id];
6343
+ }
6344
+
6345
+ return acc;
6346
+ }, {});
6347
+ });
6348
+ }, [users]);
6293
6349
  React.useEffect(function () {
6294
6350
  var unsub = [];
6295
-
6296
- if (isMaster) {
6297
- wire.register("getUserList", function () {
6298
- return usersRef.current;
6299
- }).then(function (unregister) {
6300
- unsub.push(unregister);
6351
+ unsub.push(wire.subscribe("cursorMove", function (_ref2) {
6352
+ var userId = _ref2.userId,
6353
+ pos = _ref2.pos;
6354
+ // Avoid move after cursor off
6355
+ if (preventRef.current) return;
6356
+ setCursors(function (prevCursors) {
6357
+ return _objectSpread2(_objectSpread2({}, prevCursors), {}, _defineProperty({}, userId, pos));
6301
6358
  });
6302
- unsub.push(wire.subscribe("userUpdate", function (user) {
6303
- if (usersRef.current.find(function (u) {
6304
- return u.id === user.id;
6305
- })) {
6306
- var newUsers = usersRef.current.map(function (u) {
6307
- return u.id === user.id ? user : u;
6308
- });
6309
- usersRef.current = newUsers;
6310
- } else {
6311
- var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
6312
-
6313
- usersRef.current = _newUsers;
6314
- }
6315
-
6316
- setUsers(usersRef.current);
6317
- wire.publish("updateUserList", usersRef.current);
6318
- }));
6319
- }
6359
+ }));
6360
+ unsub.push(wire.subscribe("cursorOff", function (_ref3) {
6361
+ var userId = _ref3.userId;
6362
+ setCursors(function (prevCursors) {
6363
+ var newCursors = _objectSpread2({}, prevCursors);
6320
6364
 
6321
- unsub.push(wire.subscribe("userLeave", function (userId) {
6322
- usersRef.current = usersRef.current.filter(function (_ref) {
6323
- var id = _ref.id;
6324
- return id !== userId;
6325
- });
6326
- setUsers(usersRef.current);
6365
+ delete newCursors[userId];
6366
+ return newCursors;
6367
+ }); // Prevent next moves
6327
6368
 
6328
- if (isMaster) {
6329
- wire.publish("updateUserList", usersRef.current);
6330
- }
6331
- }));
6332
- unsub.push(wire.subscribe("updateUserList", function (newList) {
6333
- usersRef.current = newList;
6334
- setUsers(usersRef.current);
6369
+ preventRef.current = true;
6370
+ setTimeout(function () {
6371
+ preventRef.current = false;
6372
+ }, 100);
6335
6373
  }));
6336
6374
  return function () {
6337
- unsub.forEach(function (u) {
6338
- return u();
6375
+ unsub.map(function (c) {
6376
+ return c();
6339
6377
  });
6340
6378
  };
6341
- }, [wire, isMaster, setUsers]);
6342
- return null;
6379
+ }, [wire]);
6380
+ return /*#__PURE__*/React.createElement("div", null, Object.entries(currentCursor).map(function (_ref4) {
6381
+ var _ref5 = _slicedToArray(_ref4, 2),
6382
+ userId = _ref5[0],
6383
+ pos = _ref5[1];
6384
+
6385
+ return /*#__PURE__*/React.createElement(PositionnedCursor, {
6386
+ key: userId,
6387
+ pos: pos,
6388
+ text: usersById[userId].name,
6389
+ color: usersById[userId].color
6390
+ });
6391
+ }));
6343
6392
  };
6344
6393
 
6345
6394
  var CursorPane = function CursorPane(_ref) {
@@ -6411,8 +6460,8 @@ var CursorPane = function CursorPane(_ref) {
6411
6460
  };
6412
6461
 
6413
6462
  return /*#__PURE__*/React.createElement("div", {
6414
- onMouseMove: onMouseMove,
6415
- onMouseLeave: onLeave
6463
+ onPointerMove: onMouseMove,
6464
+ onPointerLeave: onLeave
6416
6465
  }, children, /*#__PURE__*/React.createElement(Cursors, {
6417
6466
  users: users
6418
6467
  }));
@@ -6941,7 +6990,8 @@ var Board = function Board(_ref) {
6941
6990
  _ref$itemTemplates = _ref.itemTemplates,
6942
6991
  itemTemplates = _ref$itemTemplates === void 0 ? {} : _ref$itemTemplates,
6943
6992
  _ref$boardSize = _ref.boardSize,
6944
- boardSize = _ref$boardSize === void 0 ? DEFAULT_BOARD_MAX_SIZE : _ref$boardSize;
6993
+ boardSize = _ref$boardSize === void 0 ? DEFAULT_BOARD_MAX_SIZE : _ref$boardSize,
6994
+ children = _ref.children;
6945
6995
  var setConfiguration = useSetRecoilState(ConfigurationAtom);
6946
6996
 
6947
6997
  var _useDim = useDim(),
@@ -6979,7 +7029,7 @@ var Board = function Board(_ref) {
6979
7029
  className: "board"
6980
7030
  }, /*#__PURE__*/React.createElement(ItemList, {
6981
7031
  itemTemplates: itemTemplates
6982
- })))))), /*#__PURE__*/React.createElement(Selection, null));
7032
+ }), children))))), /*#__PURE__*/React.createElement(Selection, null));
6983
7033
  };
6984
7034
 
6985
7035
  var TOLERANCE = 100;
@@ -7016,10 +7066,16 @@ var useDim = function useDim() {
7016
7066
  var _useRecoilValue = useRecoilValue(ConfigurationAtom),
7017
7067
  itemExtentGlobal = _useRecoilValue.itemExtent;
7018
7068
 
7019
- var setDimSafe = useRecoilCallback(function (_ref2) {
7069
+ var getDim = useRecoilCallback(function (_ref2) {
7020
7070
  var snapshot = _ref2.snapshot;
7071
+ return function () {
7072
+ return snapshot.getPromise(BoardTransformAtom);
7073
+ };
7074
+ }, []);
7075
+ var setDimSafe = useRecoilCallback(function (_ref3) {
7076
+ var snapshot = _ref3.snapshot;
7021
7077
  return /*#__PURE__*/function () {
7022
- var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(fn) {
7078
+ var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(fn) {
7023
7079
  var _yield$snapshot$getPr, itemExtent, boardWrapperRect, boardSize;
7024
7080
 
7025
7081
  return regeneratorRuntime.wrap(function _callee$(_context) {
@@ -7091,14 +7147,14 @@ var useDim = function useDim() {
7091
7147
  }));
7092
7148
 
7093
7149
  return function (_x) {
7094
- return _ref3.apply(this, arguments);
7150
+ return _ref4.apply(this, arguments);
7095
7151
  };
7096
7152
  }();
7097
7153
  }, [setDim]);
7098
- var zoomTo = useRecoilCallback(function (_ref4) {
7099
- var snapshot = _ref4.snapshot;
7154
+ var zoomTo = useRecoilCallback(function (_ref5) {
7155
+ var snapshot = _ref5.snapshot;
7100
7156
  return /*#__PURE__*/function () {
7101
- var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(factor, zoomCenter) {
7157
+ var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(factor, zoomCenter) {
7102
7158
  var _yield$snapshot$getPr2, itemExtent, boardWrapperRect, boardSize, center;
7103
7159
 
7104
7160
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
@@ -7170,12 +7226,12 @@ var useDim = function useDim() {
7170
7226
  }));
7171
7227
 
7172
7228
  return function (_x2, _x3) {
7173
- return _ref5.apply(this, arguments);
7229
+ return _ref6.apply(this, arguments);
7174
7230
  };
7175
7231
  }();
7176
7232
  }, [setDim]);
7177
- var updateScaleBoundaries = useRecoilCallback(function (_ref6) {
7178
- var snapshot = _ref6.snapshot;
7233
+ var updateScaleBoundaries = useRecoilCallback(function (_ref7) {
7234
+ var snapshot = _ref7.snapshot;
7179
7235
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
7180
7236
  var _yield$snapshot$getPr3, _yield$snapshot$getPr4, width, height, boardWrapperRect, scaleX, scaleY, newScale;
7181
7237
 
@@ -7205,8 +7261,8 @@ var useDim = function useDim() {
7205
7261
  }, _callee3);
7206
7262
  }));
7207
7263
  }, []);
7208
- var getCenterCoordinates = useRecoilCallback(function (_ref8) {
7209
- var snapshot = _ref8.snapshot;
7264
+ var getCenterCoordinates = useRecoilCallback(function (_ref9) {
7265
+ var snapshot = _ref9.snapshot;
7210
7266
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
7211
7267
  var _yield$snapshot$getPr5, boardWrapperRect, boardSize, _yield$snapshot$getPr6, translateX, translateY, scale;
7212
7268
 
@@ -7242,11 +7298,11 @@ var useDim = function useDim() {
7242
7298
  }, _callee4);
7243
7299
  }));
7244
7300
  }, []);
7245
- var updateItemExtent = useRecoilCallback(function (_ref10) {
7246
- var snapshot = _ref10.snapshot,
7247
- set = _ref10.set;
7301
+ var updateItemExtent = useRecoilCallback(function (_ref11) {
7302
+ var snapshot = _ref11.snapshot,
7303
+ set = _ref11.set;
7248
7304
  return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
7249
- var itemIds, _yield$snapshot$getPr7, boardWrapperRect, boardWrapper, boardSize, _yield$snapshot$getPr8, scale, translateX, translateY, _ref12, left, top, width, height, relativeExtent, delta, _delta;
7305
+ var itemIds, _yield$snapshot$getPr7, boardWrapperRect, boardWrapper, boardSize, _yield$snapshot$getPr8, scale, translateX, translateY, _ref13, left, top, width, height, relativeExtent, delta, _delta;
7250
7306
 
7251
7307
  return regeneratorRuntime.wrap(function _callee5$(_context5) {
7252
7308
  while (1) {
@@ -7273,12 +7329,12 @@ var useDim = function useDim() {
7273
7329
  scale = _yield$snapshot$getPr8.scale;
7274
7330
  translateX = _yield$snapshot$getPr8.translateX;
7275
7331
  translateY = _yield$snapshot$getPr8.translateY;
7276
- _ref12 = getItemBoundingBox(itemIds, boardWrapper) || {
7332
+ _ref13 = getItemBoundingBox(itemIds, boardWrapper) || {
7277
7333
  left: boardSize / 2 * scale + boardWrapperRect.left + translateX,
7278
7334
  top: boardSize / 2 * scale + boardWrapperRect.top + translateY,
7279
7335
  width: 0,
7280
7336
  height: 0
7281
- }, left = _ref12.left, top = _ref12.top, width = _ref12.width, height = _ref12.height;
7337
+ }, left = _ref13.left, top = _ref13.top, width = _ref13.width, height = _ref13.height;
7282
7338
  relativeExtent = {
7283
7339
  left: (left - boardWrapperRect.left - translateX) / scale,
7284
7340
  top: (top - boardWrapperRect.top - translateY) / scale,
@@ -7324,6 +7380,7 @@ var useDim = function useDim() {
7324
7380
  }, [updateScaleBoundaries, itemExtentGlobal]);
7325
7381
  return {
7326
7382
  setDim: setDimSafe,
7383
+ getDim: getDim,
7327
7384
  zoomTo: zoomTo,
7328
7385
  getCenter: getCenterCoordinates,
7329
7386
  updateItemExtent: debouncedUpdateItemExtent
@@ -7981,6 +8038,133 @@ var useItemActions = function useItemActions() {
7981
8038
  };
7982
8039
  }();
7983
8040
  }, []);
8041
+ var findElementUnderPointer = useRecoilCallback(function (_ref16) {
8042
+ var snapshot = _ref16.snapshot;
8043
+ return /*#__PURE__*/function () {
8044
+ var _ref18 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8(_ref17) {
8045
+ var target,
8046
+ clientX,
8047
+ clientY,
8048
+ _ref19,
8049
+ _ref19$returnLocked,
8050
+ returnLocked,
8051
+ _ref19$passLocked,
8052
+ passLocked,
8053
+ foundElement,
8054
+ isPassthrough,
8055
+ itemList,
8056
+ _yield$snapshot$getPr2,
8057
+ boardWrapper,
8058
+ elems,
8059
+ i,
8060
+ elem,
8061
+ _args8 = arguments;
8062
+
8063
+ return regeneratorRuntime.wrap(function _callee8$(_context8) {
8064
+ while (1) {
8065
+ switch (_context8.prev = _context8.next) {
8066
+ case 0:
8067
+ target = _ref17.target, clientX = _ref17.clientX, clientY = _ref17.clientY;
8068
+ _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;
8069
+
8070
+ if (!["INPUT", "TEXTAREA"].includes(target.tagName)) {
8071
+ _context8.next = 4;
8072
+ break;
8073
+ }
8074
+
8075
+ return _context8.abrupt("return", null);
8076
+
8077
+ case 4:
8078
+ foundElement = insideClass(target, "item");
8079
+
8080
+ if (!foundElement) {
8081
+ _context8.next = 27;
8082
+ break;
8083
+ }
8084
+
8085
+ if (!(!passLocked && hasClass(foundElement, "locked"))) {
8086
+ _context8.next = 8;
8087
+ break;
8088
+ }
8089
+
8090
+ return _context8.abrupt("return", null);
8091
+
8092
+ case 8:
8093
+ // Is it a passthrough element?
8094
+ isPassthrough = (hasClass(target, "passthrough") || !returnLocked && hasClass(foundElement, "locked")) && !hasClass(foundElement, "selected");
8095
+
8096
+ if (!isPassthrough) {
8097
+ _context8.next = 27;
8098
+ break;
8099
+ }
8100
+
8101
+ _context8.next = 12;
8102
+ return snapshot.getPromise(ItemListAtom);
8103
+
8104
+ case 12:
8105
+ itemList = _context8.sent;
8106
+ _context8.next = 15;
8107
+ return snapshot.getPromise(ConfigurationAtom);
8108
+
8109
+ case 15:
8110
+ _yield$snapshot$getPr2 = _context8.sent;
8111
+ boardWrapper = _yield$snapshot$getPr2.boardWrapper;
8112
+ // Found element under the cursor
8113
+ elems = itemList.reduce(function (prev, itemId) {
8114
+ var elem = getItemElem(boardWrapper, itemId);
8115
+ var itemRect = elem.getBoundingClientRect();
8116
+
8117
+ if (isPointInsideRect({
8118
+ x: clientX,
8119
+ y: clientY
8120
+ }, itemRect)) {
8121
+ prev.unshift(elem);
8122
+ }
8123
+
8124
+ return prev;
8125
+ }, []); // Figure out if one can be returned
8126
+
8127
+ i = 0;
8128
+
8129
+ case 19:
8130
+ if (!(i < elems.length)) {
8131
+ _context8.next = 26;
8132
+ break;
8133
+ }
8134
+
8135
+ elem = elems[i];
8136
+
8137
+ if (!(elem !== foundElement && (returnLocked || !hasClass(elem, "locked")))) {
8138
+ _context8.next = 23;
8139
+ break;
8140
+ }
8141
+
8142
+ return _context8.abrupt("return", elem);
8143
+
8144
+ case 23:
8145
+ i += 1;
8146
+ _context8.next = 19;
8147
+ break;
8148
+
8149
+ case 26:
8150
+ return _context8.abrupt("return", null);
8151
+
8152
+ case 27:
8153
+ return _context8.abrupt("return", foundElement);
8154
+
8155
+ case 28:
8156
+ case "end":
8157
+ return _context8.stop();
8158
+ }
8159
+ }
8160
+ }, _callee8);
8161
+ }));
8162
+
8163
+ return function (_x13) {
8164
+ return _ref18.apply(this, arguments);
8165
+ };
8166
+ }();
8167
+ }, []);
7984
8168
  return {
7985
8169
  putItemsOnTop: putItemsOnTop,
7986
8170
  batchUpdateItems: batchUpdateItems,
@@ -7995,6 +8179,7 @@ var useItemActions = function useItemActions() {
7995
8179
  pushItems: pushItems,
7996
8180
  removeItems: removeItems,
7997
8181
  getItemList: getItemList,
8182
+ findElementUnderPointer: findElementUnderPointer,
7998
8183
  getItems: getItems
7999
8184
  };
8000
8185
  };
@@ -8919,5 +9104,5 @@ var ConnectedSyncRoom = function ConnectedSyncRoom(_ref) {
8919
9104
  }, /*#__PURE__*/React.createElement(SubscribeUserEvents, null), children));
8920
9105
  };
8921
9106
 
8922
- export { Board, ConnectedSyncBoard as BoardWrapper, ConnectedSyncRoom as RoomWrapper, useAvailableActions, useBoardConfig, useBoardState, useItemActions, useItemInteraction, useItemList as useItems, useMessage, useSelectedItems, useSelectionBox, useUsers, useWire };
9107
+ export { Board, ConnectedSyncBoard as BoardWrapper, ConnectedSyncRoom as RoomWrapper, useAvailableActions, useBoardConfig, useDim as useBoardPosition, useBoardState, useItemActions, useItemInteraction, useItemList as useItems, useMessage, useSelectedItems, useSelectionBox, useUsers, useWire };
8923
9108
  //# sourceMappingURL=index.js.map