react-sync-board 0.4.5 → 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) {
@@ -6047,311 +6289,106 @@ var Cursor = function Cursor(_ref3) {
6047
6289
  }, text));
6048
6290
  };
6049
6291
 
6050
- var MemoizedCursor = /*#__PURE__*/React.memo(Cursor);
6051
-
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
- var localUsersAtom = selector({
6194
- key: "localUsersAtom",
6195
- get: function get(_ref) {
6196
- var _get = _ref.get;
6197
-
6198
- var currentUser = _get(userAtom);
6199
-
6200
- var users = _get(usersAtom);
6201
-
6202
- return users.filter(function (_ref2) {
6203
- var space = _ref2.space;
6204
- return space === currentUser.space;
6205
- });
6206
- }
6207
- });
6208
-
6209
- var useUsers = function useUsers() {
6210
- var _useRecoilState = useRecoilState(userAtom),
6211
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
6212
- currentUser = _useRecoilState2[0],
6213
- setCurrentUserState = _useRecoilState2[1];
6214
-
6215
- var users = useRecoilValue(usersAtom);
6216
- var localUsers = useRecoilValue(localUsersAtom);
6217
- var setCurrentUser = React.useCallback(function (callbackOrUser) {
6218
- var callback = callbackOrUser;
6219
-
6220
- if (_typeof(callbackOrUser) === "object") {
6221
- callback = function callback() {
6222
- return callbackOrUser;
6223
- };
6224
- }
6292
+ var MemoizedCursor = /*#__PURE__*/React.memo(Cursor);
6225
6293
 
6226
- setCurrentUserState(function (prevUser) {
6227
- var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
6228
- id: prevUser.id,
6229
- uid: prevUser.uid
6230
- });
6294
+ var PositionnedCursor = function PositionnedCursor(_ref4) {
6295
+ var pos = _ref4.pos,
6296
+ rest = _objectWithoutProperties(_ref4, _excluded$1);
6231
6297
 
6232
- persistUser(newUser);
6233
- return newUser;
6234
- });
6235
- }, [setCurrentUserState]);
6236
- React.useEffect(function () {
6237
- // eslint-disable-next-line no-console
6238
- console.debug("Curent user is in space ".concat(currentUser.space));
6239
- }, [currentUser.space]);
6240
- return {
6241
- currentUser: currentUser,
6242
- setCurrentUser: setCurrentUser,
6243
- users: users,
6244
- localUsers: localUsers
6245
- };
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));
6246
6308
  };
6247
6309
 
6248
- var SubscribeUserEvents = function SubscribeUserEvents() {
6249
- var usersRef = React.useRef([]);
6250
- var setUsers = useSetRecoilState(usersAtom);
6310
+ var Cursors = function Cursors(_ref) {
6311
+ var users = _ref.users;
6251
6312
 
6252
- var _useRecoilState = useRecoilState(userAtom),
6253
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
6254
- currentUser = _useRecoilState2[0],
6255
- setCurrentUserState = _useRecoilState2[1];
6313
+ var _useWire = useWire("board"),
6314
+ wire = _useWire.wire;
6256
6315
 
6257
- var _useWire = useWire("room"),
6258
- wire = _useWire.wire,
6259
- isMaster = _useWire.isMaster,
6260
- 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];
6261
6320
 
6262
- React.useEffect(function () {
6263
- setCurrentUserState(function (prevUser) {
6264
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
6265
- id: wire.userId,
6266
- space: roomSpace
6267
- });
6268
- });
6269
- return function () {
6270
- setCurrentUserState(function (prevUser) {
6271
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
6272
- id: wire.userId,
6273
- space: null
6274
- });
6275
- });
6276
- };
6277
- }, [wire.userId, roomSpace, setCurrentUserState]);
6278
- React.useEffect(function () {
6279
- if (!isMaster) {
6280
- var onGetUserList = function onGetUserList(userList) {
6281
- usersRef.current = userList;
6282
- setUsers(userList);
6283
- };
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
6284
6328
 
6285
- wire.call("getUserList").then(onGetUserList, function () {
6286
- // retry later
6287
- setTimeout(function () {
6288
- wire.call("getUserList") // eslint-disable-next-line no-console
6289
- .then(onGetUserList, function (error) {
6290
- return console.log(error);
6291
- });
6292
- }, 1000);
6293
- });
6294
- }
6295
- }, [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
+ }
6296
6334
 
6297
- var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
6298
- wire.publish("userUpdate", newUser, true);
6299
- }, [wire], 500);
6335
+ return acc;
6336
+ }, {});
6337
+ }, [users, cursors]);
6300
6338
  React.useEffect(function () {
6301
- if (currentUser && currentUser.id) {
6302
- debouncedEmitUpdateUser(currentUser);
6303
- }
6304
- }, [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]);
6305
6349
  React.useEffect(function () {
6306
6350
  var unsub = [];
6307
-
6308
- if (isMaster) {
6309
- wire.register("getUserList", function () {
6310
- return usersRef.current;
6311
- }).then(function (unregister) {
6312
- 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));
6313
6358
  });
6314
- unsub.push(wire.subscribe("userUpdate", function (user) {
6315
- if (usersRef.current.find(function (u) {
6316
- return u.id === user.id;
6317
- })) {
6318
- var newUsers = usersRef.current.map(function (u) {
6319
- return u.id === user.id ? user : u;
6320
- });
6321
- usersRef.current = newUsers;
6322
- } else {
6323
- var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
6324
-
6325
- usersRef.current = _newUsers;
6326
- }
6327
-
6328
- setUsers(usersRef.current);
6329
- wire.publish("updateUserList", usersRef.current);
6330
- }));
6331
- }
6359
+ }));
6360
+ unsub.push(wire.subscribe("cursorOff", function (_ref3) {
6361
+ var userId = _ref3.userId;
6362
+ setCursors(function (prevCursors) {
6363
+ var newCursors = _objectSpread2({}, prevCursors);
6332
6364
 
6333
- unsub.push(wire.subscribe("userLeave", function (userId) {
6334
- usersRef.current = usersRef.current.filter(function (_ref) {
6335
- var id = _ref.id;
6336
- return id !== userId;
6337
- });
6338
- setUsers(usersRef.current);
6365
+ delete newCursors[userId];
6366
+ return newCursors;
6367
+ }); // Prevent next moves
6339
6368
 
6340
- if (isMaster) {
6341
- wire.publish("updateUserList", usersRef.current);
6342
- }
6343
- }));
6344
- unsub.push(wire.subscribe("updateUserList", function (newList) {
6345
- usersRef.current = newList;
6346
- setUsers(usersRef.current);
6369
+ preventRef.current = true;
6370
+ setTimeout(function () {
6371
+ preventRef.current = false;
6372
+ }, 100);
6347
6373
  }));
6348
6374
  return function () {
6349
- unsub.forEach(function (u) {
6350
- return u();
6375
+ unsub.map(function (c) {
6376
+ return c();
6351
6377
  });
6352
6378
  };
6353
- }, [wire, isMaster, setUsers]);
6354
- 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
+ }));
6355
6392
  };
6356
6393
 
6357
6394
  var CursorPane = function CursorPane(_ref) {
@@ -6423,8 +6460,8 @@ var CursorPane = function CursorPane(_ref) {
6423
6460
  };
6424
6461
 
6425
6462
  return /*#__PURE__*/React.createElement("div", {
6426
- onMouseMove: onMouseMove,
6427
- onMouseLeave: onLeave
6463
+ onPointerMove: onMouseMove,
6464
+ onPointerLeave: onLeave
6428
6465
  }, children, /*#__PURE__*/React.createElement(Cursors, {
6429
6466
  users: users
6430
6467
  }));
@@ -6953,7 +6990,8 @@ var Board = function Board(_ref) {
6953
6990
  _ref$itemTemplates = _ref.itemTemplates,
6954
6991
  itemTemplates = _ref$itemTemplates === void 0 ? {} : _ref$itemTemplates,
6955
6992
  _ref$boardSize = _ref.boardSize,
6956
- 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;
6957
6995
  var setConfiguration = useSetRecoilState(ConfigurationAtom);
6958
6996
 
6959
6997
  var _useDim = useDim(),
@@ -6991,7 +7029,7 @@ var Board = function Board(_ref) {
6991
7029
  className: "board"
6992
7030
  }, /*#__PURE__*/React.createElement(ItemList, {
6993
7031
  itemTemplates: itemTemplates
6994
- })))))), /*#__PURE__*/React.createElement(Selection, null));
7032
+ }), children))))), /*#__PURE__*/React.createElement(Selection, null));
6995
7033
  };
6996
7034
 
6997
7035
  var TOLERANCE = 100;
@@ -8000,6 +8038,133 @@ var useItemActions = function useItemActions() {
8000
8038
  };
8001
8039
  }();
8002
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
+ }, []);
8003
8168
  return {
8004
8169
  putItemsOnTop: putItemsOnTop,
8005
8170
  batchUpdateItems: batchUpdateItems,
@@ -8014,6 +8179,7 @@ var useItemActions = function useItemActions() {
8014
8179
  pushItems: pushItems,
8015
8180
  removeItems: removeItems,
8016
8181
  getItemList: getItemList,
8182
+ findElementUnderPointer: findElementUnderPointer,
8017
8183
  getItems: getItems
8018
8184
  };
8019
8185
  };