react-sync-board 0.5.5 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -4318,1196 +4318,1312 @@ function useResizeObserver(target, callback, enabled) {
4318
4318
  }, [target, ro]);
4319
4319
  }
4320
4320
 
4321
- var img = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='UTF-8' standalone='no'%3f%3e%3csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' version='1.1' x='0px' y='0px' viewBox='0 0 75.601318 94.9' xml:space='preserve' id='svg26' sodipodi:docname='lock.svg' width='75.601318' height='94.900002' inkscape:version='0.92.5 (2060ec1f9f%2c 2020-04-08)'%3e%3cmetadata id='metadata32'%3e%3crdf:RDF%3e%3ccc:Work rdf:about=''%3e%3cdc:format%3eimage/svg%2bxml%3c/dc:format%3e%3cdc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage' /%3e%3cdc:title%3e%3c/dc:title%3e%3c/cc:Work%3e%3c/rdf:RDF%3e%3c/metadata%3e%3cdefs id='defs30' /%3e%3csodipodi:namedview pagecolor='black' bordercolor='%23666666' borderopacity='1' objecttolerance='10' gridtolerance='10' guidetolerance='10' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:window-width='1848' inkscape:window-height='1016' id='namedview28' showgrid='false' fit-margin-top='0' fit-margin-left='0' fit-margin-right='0' fit-margin-bottom='0' inkscape:zoom='5.3400704' inkscape:cx='3.2640013' inkscape:cy='45.072152' inkscape:window-x='1512' inkscape:window-y='27' inkscape:window-maximized='1' inkscape:current-layer='g16' /%3e%3cg id='g16' transform='translate(-12.2%2c-2.5)'%3e%3cpath d='M 75.4%2c36.8 H 34.1 V 24.6 c 0%2c-8.8 7.1%2c-15.9 15.9%2c-15.9 8.8%2c0 15.9%2c7.1 15.9%2c15.9 0%2c1.7 1.4%2c3.1 3.1%2c3.1 1.7%2c0 3.1%2c-1.4 3.1%2c-3.1 C 72.1%2c12.4 62.2%2c2.5 50%2c2.5 37.8%2c2.5 27.9%2c12.4 27.9%2c24.6 v 12.2 h -3.3 c -6.9%2c0 -12.4%2c5.6 -12.4%2c12.4 V 85 c 0%2c6.9 5.6%2c12.4 12.4%2c12.4 h 50.8 c 6.9%2c0 12.4%2c-5.6 12.4%2c-12.4 V 49.2 C 87.9%2c42.3 82.3%2c36.8 75.4%2c36.8 Z m 6.2%2c48.3 c 0%2c3.4 -2.8%2c6.2 -6.2%2c6.2 H 24.6 c -3.4%2c0 -6.2%2c-2.8 -6.2%2c-6.2 V 49.2 c 0%2c-3.4 2.8%2c-6.2 6.2%2c-6.2 h 50.8 c 3.4%2c0 6.2%2c2.8 6.2%2c6.2 z' id='path12' inkscape:connector-curvature='0' style='fill:white%3bfill-opacity:1' /%3e%3cpath d='m 59.8%2c57.6 -12.5%2c12.5 -7%2c-7 c -1.2%2c-1.2 -3.2%2c-1.2 -4.4%2c0 -1.2%2c1.2 -1.2%2c3.2 0%2c4.4 l 9.2%2c9.2 c 0.6%2c0.6 1.4%2c0.9 2.2%2c0.9 0.8%2c0 1.6%2c-0.3 2.2%2c-0.9 L 64.2%2c62 c 1.2%2c-1.2 1.2%2c-3.2 0%2c-4.4 -1.2%2c-1.2 -3.2%2c-1.2 -4.4%2c0 z' id='path14' inkscape:connector-curvature='0' style='fill:white%3bfill-opacity:1' /%3e%3c/g%3e%3c/svg%3e";
4322
-
4323
- var _excluded$2 = ["type", "rotation", "id", "locked", "layer"],
4324
- _excluded2 = ["state", "boardSize", "currentUser"],
4325
- _excluded3 = ["x", "y", "layer", "moving"];
4321
+ var isMacOS = function isMacOS() {
4322
+ var userAgent = navigator.userAgent.toLowerCase();
4323
+ return /mac os ?x 10/.test(userAgent);
4324
+ }; // From https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
4326
4325
 
4327
- var _templateObject$2;
4328
- var ItemWrapper = newStyled.div(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteral(["\n display: inline-block;\n transition: transform 150ms;\n user-select: none;\n padding: 2px;\n transform: rotate(", "deg);\n\n & .corner {\n position: absolute;\n width: 0px;\n height: 0px;\n }\n\n & .top-left {\n top: 0;\n left: 0;\n }\n & .top-right {\n top: 0;\n right: 0;\n }\n & .bottom-left {\n bottom: 0;\n left: 0;\n }\n & .bottom-right {\n bottom: 0;\n right: 0;\n }\n\n &.selected {\n border: 2px dashed #db5034;\n padding: 0px;\n cursor: pointer;\n }\n\n &.locked::after {\n content: \"\";\n position: absolute;\n width: 24px;\n height: 30px;\n top: 4px;\n right: 4px;\n opacity: 0.1;\n background-image: url(\"", "\");\n background-size: cover;\n user-select: none;\n }\n\n &.locked:hover::after {\n opacity: 0.3;\n }\n"])), function (_ref) {
4329
- var rotation = _ref.rotation;
4330
- return rotation;
4331
- }, img);
4326
+ var getScrollLineHeight = function getScrollLineHeight() {
4327
+ var iframe = document.createElement("iframe");
4328
+ iframe.src = "#";
4329
+ document.body.appendChild(iframe); // Write content in Iframe
4332
4330
 
4333
- var DefaultErrorComponent = function DefaultErrorComponent(_ref2) {
4334
- var onReload = _ref2.onReload;
4335
- return /*#__PURE__*/React__default['default'].createElement("div", {
4336
- style: {
4337
- width: "100px",
4338
- display: "flex",
4339
- flexDirection: "column",
4340
- justifyContent: "center",
4341
- textAlign: "center",
4342
- color: "red"
4343
- },
4344
- className: "syncboard-error-item"
4345
- }, "Sorry, this item seems broken.", /*#__PURE__*/React__default['default'].createElement("button", {
4346
- onClick: onReload
4347
- }, "Reload it"));
4331
+ var idoc = iframe.contentWindow.document;
4332
+ idoc.open();
4333
+ idoc.write("<!DOCTYPE html><html><head></head><body><span>a</span></body></html>");
4334
+ idoc.close();
4335
+ var scrollLineHeight = idoc.body.firstElementChild.offsetHeight;
4336
+ document.body.removeChild(iframe);
4337
+ return scrollLineHeight;
4348
4338
  };
4349
- /* Error boundary for broken item */
4350
-
4351
-
4352
- var ItemErrorBoundary = /*#__PURE__*/function (_React$Component) {
4353
- _inherits(ItemErrorBoundary, _React$Component);
4354
-
4355
- var _super = _createSuper(ItemErrorBoundary);
4356
-
4357
- function ItemErrorBoundary(props) {
4358
- var _this;
4359
-
4360
- _classCallCheck(this, ItemErrorBoundary);
4361
4339
 
4362
- _this = _super.call(this, props);
4363
- _this.state = {
4364
- hasError: false,
4365
- itemId: props.itemId
4366
- };
4367
- _this.onReload = _this.onReload.bind(_assertThisInitialized(_this));
4368
- return _this;
4369
- }
4340
+ var LINE_HEIGHT = getScrollLineHeight(); // Reasonable default from https://github.com/facebookarchive/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js
4370
4341
 
4371
- _createClass(ItemErrorBoundary, [{
4372
- key: "componentDidCatch",
4373
- value: function componentDidCatch(error) {
4374
- // eslint-disable-next-line no-console
4375
- console.error("Error for item ".concat(this.state.itemId), error, this.props.state);
4376
- }
4377
- }, {
4378
- key: "onReload",
4379
- value: function onReload() {
4380
- this.setState({
4381
- hasError: false
4382
- });
4383
- }
4384
- }, {
4385
- key: "render",
4386
- value: function render() {
4387
- var ErrorComponent = this.props.ErrorComponent;
4342
+ var PAGE_HEIGHT = 800;
4388
4343
 
4389
- if (this.state.hasError) {
4390
- return /*#__PURE__*/React__default['default'].createElement(ErrorComponent, {
4391
- onReload: this.onReload
4392
- });
4393
- }
4344
+ var otherPointer = function otherPointer(pointers, currentPointer) {
4345
+ var p2 = Object.keys(pointers).map(function (p) {
4346
+ return Number(p);
4347
+ }).find(function (pointer) {
4348
+ return pointer !== currentPointer;
4349
+ });
4350
+ return pointers[p2];
4351
+ };
4394
4352
 
4395
- return this.props.children;
4396
- }
4397
- }], [{
4398
- key: "getDerivedStateFromError",
4399
- value: function getDerivedStateFromError() {
4400
- return {
4401
- hasError: true
4402
- };
4403
- }
4404
- }]);
4353
+ var computeDistance = function computeDistance(_ref, _ref2) {
4354
+ var _ref3 = _slicedToArray(_ref, 2),
4355
+ x1 = _ref3[0],
4356
+ y1 = _ref3[1];
4405
4357
 
4406
- return ItemErrorBoundary;
4407
- }(React__default['default'].Component);
4358
+ var _ref4 = _slicedToArray(_ref2, 2),
4359
+ x2 = _ref4[0],
4360
+ y2 = _ref4[1];
4408
4361
 
4409
- var removeClass = function removeClass(e) {
4410
- e.target.className = "";
4362
+ var distanceX = Math.abs(x1 - x2);
4363
+ var distanceY = Math.abs(y1 - y2);
4364
+ return Math.hypot(distanceX, distanceY);
4411
4365
  };
4412
4366
 
4413
- var Item = function Item(_ref3) {
4414
- var _itemMap$error;
4415
-
4416
- var setState = _ref3.setState,
4417
- _ref3$state = _ref3.state;
4418
- _ref3$state = _ref3$state === void 0 ? {} : _ref3$state;
4419
-
4420
- var type = _ref3$state.type,
4421
- _ref3$state$rotation = _ref3$state.rotation,
4422
- rotation = _ref3$state$rotation === void 0 ? 0 : _ref3$state$rotation,
4423
- id = _ref3$state.id,
4424
- locked = _ref3$state.locked,
4425
- layer = _ref3$state.layer,
4426
- rest = _objectWithoutProperties(_ref3$state, _excluded$2),
4427
- _ref3$animate = _ref3.animate,
4428
- animate = _ref3$animate === void 0 ? "hvr-pop" : _ref3$animate,
4429
- isSelected = _ref3.isSelected,
4430
- itemMap = _ref3.itemMap,
4431
- unlocked = _ref3.unlocked;
4432
-
4433
- var animateRef = React__default['default'].useRef(null);
4434
-
4435
- var Component = itemMap[type].component || function () {
4436
- return null;
4437
- };
4367
+ var empty = function empty() {};
4438
4368
 
4439
- var updateState = React__default['default'].useCallback(function (callbackOrItem) {
4440
- var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
4441
- return setState(id, callbackOrItem, sync);
4442
- }, [setState, id]);
4443
- React__default['default'].useEffect(function () {
4444
- animateRef.current.className = animate;
4445
- }, [animate]);
4446
- var className = "item ".concat(id);
4369
+ var protect = function protect(fn) {
4370
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
4371
+ var _args = arguments;
4372
+ return regeneratorRuntime.wrap(function _callee$(_context) {
4373
+ while (1) {
4374
+ switch (_context.prev = _context.next) {
4375
+ case 0:
4376
+ _context.prev = 0;
4377
+ _context.next = 3;
4378
+ return fn.apply(void 0, _args);
4447
4379
 
4448
- if (locked) {
4449
- className += " locked";
4450
- }
4380
+ case 3:
4381
+ _context.next = 8;
4382
+ break;
4451
4383
 
4452
- if (isSelected) {
4453
- className += " selected";
4454
- }
4384
+ case 5:
4385
+ _context.prev = 5;
4386
+ _context.t0 = _context["catch"](0);
4387
+ // eslint-disable-next-line no-console
4388
+ console.error(_context.t0);
4455
4389
 
4456
- return /*#__PURE__*/React__default['default'].createElement(ItemWrapper, {
4457
- rotation: rotation,
4458
- locked: locked && !unlocked,
4459
- selected: isSelected,
4460
- layer: layer,
4461
- "data-id": id,
4462
- className: className
4463
- }, /*#__PURE__*/React__default['default'].createElement("div", {
4464
- style: {
4465
- display: "flex"
4466
- },
4467
- ref: animateRef,
4468
- onAnimationEnd: removeClass,
4469
- onKeyDown: function onKeyDown(e) {
4470
- return e.stopPropagation();
4471
- },
4472
- onKeyUp: function onKeyUp(e) {
4473
- return e.stopPropagation();
4474
- }
4475
- }, /*#__PURE__*/React__default['default'].createElement(ItemErrorBoundary, {
4476
- itemId: id,
4477
- state: rest,
4478
- setState: updateState,
4479
- ErrorComponent: (itemMap === null || itemMap === void 0 ? void 0 : (_itemMap$error = itemMap.error) === null || _itemMap$error === void 0 ? void 0 : _itemMap$error.component) || DefaultErrorComponent
4480
- }, /*#__PURE__*/React__default['default'].createElement(Component, _extends$1({}, rest, {
4481
- id: id,
4482
- setState: updateState
4483
- }))), /*#__PURE__*/React__default['default'].createElement("div", {
4484
- className: "corner top-left"
4485
- }), /*#__PURE__*/React__default['default'].createElement("div", {
4486
- className: "corner top-right"
4487
- }), /*#__PURE__*/React__default['default'].createElement("div", {
4488
- className: "corner bottom-left"
4489
- }), /*#__PURE__*/React__default['default'].createElement("div", {
4490
- className: "corner bottom-right"
4491
- })));
4390
+ case 8:
4391
+ case "end":
4392
+ return _context.stop();
4393
+ }
4394
+ }
4395
+ }, _callee, null, [[0, 5]]);
4396
+ }));
4492
4397
  };
4493
4398
 
4494
- var MemoizedItem = /*#__PURE__*/React.memo(Item, function (_ref4, _ref5) {
4495
- var prevState = _ref4.state,
4496
- prevSetState = _ref4.setState,
4497
- prevIsSelected = _ref4.isSelected,
4498
- prevUnlocked = _ref4.unlocked;
4499
- var nextState = _ref5.state,
4500
- nextSetState = _ref5.setState,
4501
- nextIsSelected = _ref5.isSelected,
4502
- nextUnlocked = _ref5.unlocked;
4503
- return prevIsSelected === nextIsSelected && prevUnlocked === nextUnlocked && prevSetState === nextSetState && JSON.stringify(prevState) === JSON.stringify(nextState);
4504
- }); // Exclude positioning from memoization
4399
+ var Gesture = function Gesture(_ref6) {
4400
+ var children = _ref6.children,
4401
+ _ref6$onDrag = _ref6.onDrag,
4402
+ onDrag = _ref6$onDrag === void 0 ? empty : _ref6$onDrag,
4403
+ _ref6$onDragStart = _ref6.onDragStart,
4404
+ onDragStart = _ref6$onDragStart === void 0 ? empty : _ref6$onDragStart,
4405
+ _ref6$onDragEnd = _ref6.onDragEnd,
4406
+ onDragEnd = _ref6$onDragEnd === void 0 ? empty : _ref6$onDragEnd,
4407
+ _ref6$onPan = _ref6.onPan,
4408
+ onPan = _ref6$onPan === void 0 ? empty : _ref6$onPan,
4409
+ _ref6$onTap = _ref6.onTap,
4410
+ onTap = _ref6$onTap === void 0 ? empty : _ref6$onTap,
4411
+ _ref6$onLongTap = _ref6.onLongTap,
4412
+ onLongTap = _ref6$onLongTap === void 0 ? empty : _ref6$onLongTap,
4413
+ _ref6$onDoubleTap = _ref6.onDoubleTap,
4414
+ onDoubleTap = _ref6$onDoubleTap === void 0 ? empty : _ref6$onDoubleTap,
4415
+ onZoom = _ref6.onZoom;
4416
+ var wrapperRef = React__default['default'].useRef(null);
4417
+ var stateRef = React__default['default'].useRef({
4418
+ moving: false,
4419
+ pointers: {},
4420
+ mainPointer: undefined
4421
+ });
4422
+ var queueRef = React__default['default'].useRef([]); // Queue event to avoid async mess
4505
4423
 
4506
- var PositionedItem = function PositionedItem(_ref6) {
4507
- var _rest$itemMap$state$t;
4424
+ var queue = React__default['default'].useCallback(function (callback, args) {
4425
+ queueRef.current.push( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
4426
+ return regeneratorRuntime.wrap(function _callee2$(_context2) {
4427
+ while (1) {
4428
+ switch (_context2.prev = _context2.next) {
4429
+ case 0:
4430
+ _context2.next = 2;
4431
+ return protect(callback)(args);
4508
4432
 
4509
- var _ref6$state = _ref6.state,
4510
- state = _ref6$state === void 0 ? {} : _ref6$state,
4511
- boardSize = _ref6.boardSize,
4512
- currentUser = _ref6.currentUser,
4513
- rest = _objectWithoutProperties(_ref6, _excluded2);
4433
+ case 2:
4434
+ queueRef.current.shift();
4514
4435
 
4515
- var stateTrans = ((_rest$itemMap$state$t = rest.itemMap[state.type]) === null || _rest$itemMap$state$t === void 0 ? void 0 : _rest$itemMap$state$t.stateHook) || function (st) {
4516
- return st;
4517
- };
4436
+ if (!(queueRef.current.length !== 0)) {
4437
+ _context2.next = 6;
4438
+ break;
4439
+ }
4518
4440
 
4519
- var _stateTrans = stateTrans(state, {
4520
- currentUser: currentUser
4521
- }),
4522
- _stateTrans$x = _stateTrans.x,
4523
- x = _stateTrans$x === void 0 ? 0 : _stateTrans$x,
4524
- _stateTrans$y = _stateTrans.y,
4525
- y = _stateTrans$y === void 0 ? 0 : _stateTrans$y,
4526
- _stateTrans$layer = _stateTrans.layer,
4527
- layer = _stateTrans$layer === void 0 ? 0 : _stateTrans$layer,
4528
- moving = _stateTrans.moving,
4529
- stateRest = _objectWithoutProperties(_stateTrans, _excluded3);
4441
+ _context2.next = 6;
4442
+ return protect(queueRef.current[0])();
4530
4443
 
4531
- return /*#__PURE__*/React__default['default'].createElement("div", {
4532
- style: {
4533
- position: "absolute",
4534
- top: "".concat(boardSize / 2, "px"),
4535
- left: "".concat(boardSize / 2, "px"),
4536
- display: "inline-block",
4537
- transform: "translate(".concat(x, "px, ").concat(y, "px)"),
4538
- zIndex: (layer + 4) * 10 + 100 + (moving ? 5 : 0) // Items z-index between 100 and 200
4444
+ case 6:
4445
+ case "end":
4446
+ return _context2.stop();
4447
+ }
4448
+ }
4449
+ }, _callee2);
4450
+ })));
4539
4451
 
4452
+ if (queueRef.current.length === 1) {
4453
+ protect(queueRef.current[0])();
4540
4454
  }
4541
- }, /*#__PURE__*/React__default['default'].createElement(MemoizedItem, _extends$1({}, rest, {
4542
- state: stateRest
4543
- })));
4544
- };
4455
+ }, []);
4456
+ var onWheel = React__default['default'].useCallback(function (e) {
4457
+ var deltaX = e.deltaX,
4458
+ deltaY = e.deltaY,
4459
+ clientX = e.clientX,
4460
+ clientY = e.clientY,
4461
+ deltaMode = e.deltaMode,
4462
+ ctrlKey = e.ctrlKey,
4463
+ altKey = e.altKey,
4464
+ metaKey = e.metaKey,
4465
+ target = e.target; // On a MacOs trackpad, the pinch gesture sets the ctrlKey to true.
4466
+ // In that situation, we want to use the custom scaling, not the browser default zoom.
4467
+ // Hence in this situation we avoid to return immediately.
4545
4468
 
4546
- var MemoizedPositionedItem = /*#__PURE__*/React.memo(PositionedItem);
4469
+ if (altKey || ctrlKey && !isMacOS()) {
4470
+ return;
4471
+ } // On a trackpad, the pinch and pan events are differentiated by the crtlKey value.
4472
+ // On a pinch gesture, the ctrlKey is set to true, so we want to have a scaling effect.
4473
+ // If we are only moving the fingers in the same direction, a pan is needed.
4474
+ // Ref: https://medium.com/@auchenberg/detecting-multi-touch-trackpad-gestures-in-javascript-a2505babb10e
4547
4475
 
4548
- var persistUser = function persistUser(user) {
4549
- localStorage.setItem("user", JSON.stringify(user));
4550
- };
4551
- var colors = ["#037758", "#99092a", "#067070", "#c6650f", "#008726", "#3d7004", "#348402", "#057f58", "#b58612", "#c44c01", "#0a7704", "#0e910e", "#027377", "#c99e02", "#054160", "#157a01", "#b10de2", "#0d6289", "#bc5d03", "#ba0cd1", "#d39f10", "#0c4c7a", "#460782", "#a51f10", "#cecb10", "#9b0943", "#607f0c", "#007a4b", "#bf0daa", "#af0ad8"];
4552
4476
 
4553
- var getRandomColor = function getRandomColor() {
4554
- return colors[Math.floor(Math.random() * colors.length)];
4555
- }; // TODO remove user persistence
4477
+ if (isMacOS() && !ctrlKey) {
4478
+ queue(onPan, {
4479
+ deltaX: -2 * deltaX,
4480
+ deltaY: -2 * deltaY,
4481
+ button: 1,
4482
+ ctrlKey: ctrlKey,
4483
+ metaKey: metaKey,
4484
+ target: target,
4485
+ event: e
4486
+ });
4487
+ } else {
4488
+ // Quit if onZoom is not set
4489
+ if (onZoom === undefined || !deltaY) return;
4490
+ var scale = deltaY;
4556
4491
 
4492
+ switch (deltaMode) {
4493
+ case 1:
4494
+ // Pixel
4495
+ scale *= LINE_HEIGHT;
4496
+ break;
4557
4497
 
4558
- var getUser = function getUser() {
4559
- if (localStorage.user) {
4560
- // Add some mandatory info if missing
4561
- var localUser = _objectSpread2({
4562
- name: "Player",
4563
- color: getRandomColor(),
4564
- uid: nanoid()
4565
- }, JSON.parse(localStorage.user)); // Id is given by server
4566
- // delete localUser.id;
4498
+ case 2:
4499
+ scale *= PAGE_HEIGHT;
4500
+ break;
4501
+ }
4567
4502
 
4503
+ if (isMacOS()) {
4504
+ scale *= 2;
4505
+ }
4568
4506
 
4569
- persistUser(localUser);
4570
- return localUser;
4571
- }
4507
+ queue(onZoom, {
4508
+ scale: scale,
4509
+ clientX: clientX,
4510
+ clientY: clientY,
4511
+ event: e
4512
+ });
4513
+ }
4514
+ }, [onPan, onZoom, queue]);
4515
+ var onPointerDown = React__default['default'].useCallback(function (_ref8) {
4516
+ var target = _ref8.target,
4517
+ button = _ref8.button,
4518
+ clientX = _ref8.clientX,
4519
+ clientY = _ref8.clientY,
4520
+ pointerId = _ref8.pointerId,
4521
+ altKey = _ref8.altKey,
4522
+ ctrlKey = _ref8.ctrlKey,
4523
+ metaKey = _ref8.metaKey,
4524
+ isPrimary = _ref8.isPrimary;
4525
+ // Add pointer to map
4526
+ stateRef.current.pointers[pointerId] = {
4527
+ clientX: clientX,
4528
+ clientY: clientY
4529
+ };
4572
4530
 
4573
- var newUser = {
4574
- name: "Player",
4575
- color: getRandomColor(),
4576
- uid: nanoid()
4577
- };
4578
- persistUser(newUser);
4579
- return newUser;
4580
- };
4581
- var userAtom = recoil.atom({
4582
- key: "user",
4583
- "default": getUser()
4584
- });
4585
- var usersAtom = recoil.atom({
4586
- key: "users",
4587
- "default": []
4588
- });
4589
- var localUsersAtom = recoil.selector({
4590
- key: "localUsersAtom",
4591
- get: function get(_ref) {
4592
- var _get = _ref.get;
4531
+ if (isPrimary) {
4532
+ // Clean mainPoint on primary pointer
4533
+ stateRef.current.mainPointer = undefined;
4534
+ }
4593
4535
 
4594
- var currentUser = _get(userAtom);
4536
+ if (stateRef.current.mainPointer !== undefined) {
4537
+ if (stateRef.current.mainPointer !== pointerId) {
4538
+ // This is not the main pointer
4539
+ try {
4540
+ var _otherPointer = otherPointer(stateRef.current.pointers, pointerId),
4541
+ clientX2 = _otherPointer.clientX,
4542
+ clientY2 = _otherPointer.clientY;
4595
4543
 
4596
- var users = _get(usersAtom);
4544
+ var newClientX = (clientX2 + clientX) / 2;
4545
+ var newClientY = (clientY2 + clientY) / 2;
4546
+ var distance = computeDistance([clientX2, clientY2], [clientX, clientY]); // We update previous position as the new position is the center beetween both finger
4597
4547
 
4598
- return users.filter(function (_ref2) {
4599
- var space = _ref2.space;
4600
- return space === currentUser.space;
4601
- });
4602
- }
4603
- });
4548
+ Object.assign(stateRef.current, {
4549
+ pressed: true,
4550
+ moving: false,
4551
+ gestureStart: false,
4552
+ startX: clientX,
4553
+ startY: clientY,
4554
+ prevX: newClientX,
4555
+ prevY: newClientY,
4556
+ startDistance: distance,
4557
+ prevDistance: distance
4558
+ });
4559
+ } catch (e) {
4560
+ // eslint-disable-next-line no-console
4561
+ console.log("Error while getting other pointer. Ignoring", e); // eslint-disable-next-line no-unused-expressions
4604
4562
 
4605
- var useUsers = function useUsers() {
4606
- var _useRecoilState = recoil.useRecoilState(userAtom),
4607
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
4608
- currentUser = _useRecoilState2[0],
4609
- setCurrentUserState = _useRecoilState2[1];
4563
+ stateRef.current.mainPointer === undefined;
4564
+ }
4565
+ }
4610
4566
 
4611
- var users = recoil.useRecoilValue(usersAtom);
4612
- var localUsers = recoil.useRecoilValue(localUsersAtom);
4613
- var setCurrentUser = React__default['default'].useCallback(function (callbackOrUser) {
4614
- var callback = callbackOrUser;
4567
+ return;
4568
+ } // We set the mainpointer
4615
4569
 
4616
- if (_typeof(callbackOrUser) === "object") {
4617
- callback = function callback() {
4618
- return callbackOrUser;
4619
- };
4620
- }
4621
4570
 
4622
- setCurrentUserState(function (prevUser) {
4623
- var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
4624
- id: prevUser.id,
4625
- uid: prevUser.uid
4626
- });
4571
+ stateRef.current.mainPointer = pointerId; // And prepare move
4627
4572
 
4628
- persistUser(newUser);
4629
- return newUser;
4573
+ Object.assign(stateRef.current, {
4574
+ pressed: true,
4575
+ moving: false,
4576
+ gestureStart: false,
4577
+ startX: clientX,
4578
+ startY: clientY,
4579
+ prevX: clientX,
4580
+ prevY: clientY,
4581
+ currentButton: button,
4582
+ target: target,
4583
+ timeStart: Date.now(),
4584
+ longTapTimeout: setTimeout( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
4585
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
4586
+ while (1) {
4587
+ switch (_context3.prev = _context3.next) {
4588
+ case 0:
4589
+ stateRef.current.noTap = true;
4590
+ queue(onLongTap, {
4591
+ clientX: clientX,
4592
+ clientY: clientY,
4593
+ altKey: altKey,
4594
+ ctrlKey: ctrlKey,
4595
+ metaKey: metaKey,
4596
+ target: target
4597
+ });
4598
+
4599
+ case 2:
4600
+ case "end":
4601
+ return _context3.stop();
4602
+ }
4603
+ }
4604
+ }, _callee3);
4605
+ })), 750)
4630
4606
  });
4631
- }, [setCurrentUserState]);
4632
- React__default['default'].useEffect(function () {
4633
- // eslint-disable-next-line no-console
4634
- console.debug("Curent user is in space ".concat(currentUser.space));
4635
- }, [currentUser.space]);
4636
- return {
4637
- currentUser: currentUser,
4638
- setCurrentUser: setCurrentUser,
4639
- users: users,
4640
- localUsers: localUsers
4641
- };
4642
- };
4643
4607
 
4644
- var SubscribeUserEvents = function SubscribeUserEvents() {
4645
- var usersRef = React__default['default'].useRef([]);
4646
- var setUsers = recoil.useSetRecoilState(usersAtom);
4608
+ try {
4609
+ target.setPointerCapture(pointerId);
4610
+ } catch (e) {
4611
+ // eslint-disable-next-line no-console
4612
+ console.log("Fail to capture pointer", e);
4613
+ }
4614
+ }, [onLongTap, queue]);
4615
+ var onPointerMove = React__default['default'].useCallback(function (e) {
4616
+ if (stateRef.current.pressed) {
4617
+ var pointerId = e.pointerId,
4618
+ eventClientX = e.clientX,
4619
+ eventClientY = e.clientY,
4620
+ altKey = e.altKey,
4621
+ ctrlKey = e.ctrlKey,
4622
+ metaKey = e.metaKey,
4623
+ pointerType = e.pointerType;
4647
4624
 
4648
- var _useRecoilState = recoil.useRecoilState(userAtom),
4649
- _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
4650
- currentUser = _useRecoilState2[0],
4651
- setCurrentUserState = _useRecoilState2[1];
4625
+ if (stateRef.current.mainPointer !== pointerId) {
4626
+ // Event from other pointer
4627
+ stateRef.current.pointers[pointerId] = {
4628
+ clientX: eventClientX,
4629
+ clientY: eventClientY
4630
+ };
4631
+ return;
4632
+ }
4652
4633
 
4653
- var _useWire = useWire("room"),
4654
- wire = _useWire.wire,
4655
- isMaster = _useWire.isMaster,
4656
- roomSpace = _useWire.room;
4634
+ stateRef.current.moving = true; // Do we have two fingers ?
4657
4635
 
4658
- React__default['default'].useEffect(function () {
4659
- setCurrentUserState(function (prevUser) {
4660
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
4661
- id: wire.userId,
4662
- space: roomSpace
4663
- });
4664
- });
4665
- return function () {
4666
- setCurrentUserState(function (prevUser) {
4667
- return _objectSpread2(_objectSpread2({}, prevUser), {}, {
4668
- id: wire.userId,
4669
- space: null
4670
- });
4671
- });
4672
- };
4673
- }, [wire.userId, roomSpace, setCurrentUserState]);
4674
- React__default['default'].useEffect(function () {
4675
- if (!isMaster) {
4676
- var onGetUserList = function onGetUserList(userList) {
4677
- usersRef.current = userList;
4678
- setUsers(userList);
4679
- };
4636
+ var twoFingers = Object.keys(stateRef.current.pointers).length === 2;
4637
+ var clientX;
4638
+ var clientY;
4639
+ var distance;
4680
4640
 
4681
- wire.call("getUserList").then(onGetUserList, function () {
4682
- // retry later
4683
- setTimeout(function () {
4684
- wire.call("getUserList") // eslint-disable-next-line no-console
4685
- .then(onGetUserList, function (error) {
4686
- return console.log(error);
4687
- });
4688
- }, 1000);
4689
- });
4690
- }
4691
- }, [wire, isMaster, setUsers]); // eslint-disable-next-line react-hooks/exhaustive-deps
4641
+ if (twoFingers) {
4642
+ // Find other pointerId
4643
+ var _otherPointer2 = otherPointer(stateRef.current.pointers, pointerId),
4644
+ clientX2 = _otherPointer2.clientX,
4645
+ clientY2 = _otherPointer2.clientY; // Update client X with the center of each touch
4692
4646
 
4693
- var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
4694
- wire.publish("userUpdate", newUser, true);
4695
- }, [wire], 500);
4696
- React__default['default'].useEffect(function () {
4697
- if (currentUser && currentUser.id) {
4698
- debouncedEmitUpdateUser(currentUser);
4699
- }
4700
- }, [currentUser, debouncedEmitUpdateUser]);
4701
- React__default['default'].useEffect(function () {
4702
- var unsub = [];
4703
4647
 
4704
- if (isMaster) {
4705
- wire.register("getUserList", function () {
4706
- return usersRef.current;
4707
- }).then(function (unregister) {
4708
- unsub.push(unregister);
4709
- });
4710
- unsub.push(wire.subscribe("userUpdate", function (user) {
4711
- if (usersRef.current.find(function (u) {
4712
- return u.id === user.id;
4713
- })) {
4714
- var newUsers = usersRef.current.map(function (u) {
4715
- return u.id === user.id ? user : u;
4716
- });
4717
- usersRef.current = newUsers;
4718
- } else {
4719
- var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
4648
+ clientX = (clientX2 + eventClientX) / 2;
4649
+ clientY = (clientY2 + eventClientY) / 2;
4650
+ distance = computeDistance([clientX2, clientY2], [eventClientX, eventClientY]);
4651
+ } else {
4652
+ clientX = eventClientX;
4653
+ clientY = eventClientY;
4654
+ } // We drag if
4655
+ // On non touch device
4656
+ // - Button is 0
4657
+ // - Alt key is no pressed
4658
+ // or on touch devices
4659
+ // - We use only one finger
4720
4660
 
4721
- usersRef.current = _newUsers;
4722
- }
4723
4661
 
4724
- setUsers(usersRef.current);
4725
- wire.publish("updateUserList", usersRef.current);
4726
- }));
4727
- }
4662
+ var shouldDrag = pointerType !== "touch" ? stateRef.current.currentButton === 0 && !altKey : !twoFingers;
4728
4663
 
4729
- unsub.push(wire.subscribe("userLeave", function (userId) {
4730
- usersRef.current = usersRef.current.filter(function (_ref) {
4731
- var id = _ref.id;
4732
- return id !== userId;
4733
- });
4734
- setUsers(usersRef.current);
4664
+ if (shouldDrag) {
4665
+ // Send drag start on first move
4666
+ if (!stateRef.current.gestureStart) {
4667
+ wrapperRef.current.style.cursor = "move";
4668
+ stateRef.current.gestureStart = true; // Clear tap timeout
4735
4669
 
4736
- if (isMaster) {
4737
- wire.publish("updateUserList", usersRef.current);
4738
- }
4739
- }));
4740
- unsub.push(wire.subscribe("updateUserList", function (newList) {
4741
- usersRef.current = newList;
4742
- setUsers(usersRef.current);
4743
- }));
4744
- return function () {
4745
- unsub.forEach(function (u) {
4746
- return u();
4747
- });
4748
- };
4749
- }, [wire, isMaster, setUsers]);
4750
- return null;
4751
- };
4670
+ clearTimeout(stateRef.current.longTapTimeout);
4671
+ queue(onDragStart, {
4672
+ deltaX: 0,
4673
+ deltaY: 0,
4674
+ startX: stateRef.current.startX,
4675
+ startY: stateRef.current.startY,
4676
+ clientX: stateRef.current.startX,
4677
+ clientY: stateRef.current.startY,
4678
+ distanceX: 0,
4679
+ distanceY: 0,
4680
+ button: stateRef.current.currentButton,
4681
+ altKey: altKey,
4682
+ ctrlKey: ctrlKey,
4683
+ metaKey: metaKey,
4684
+ target: stateRef.current.target,
4685
+ event: e
4686
+ });
4687
+ } // Create closure
4752
4688
 
4753
- /** Allow to operate on locked items while u or l key is pressed */
4754
4689
 
4755
- var useUnlock = function useUnlock() {
4756
- var _React$useState = React__default['default'].useState(false),
4757
- _React$useState2 = _slicedToArray(_React$useState, 2),
4758
- unlock = _React$useState2[0],
4759
- setUnlock = _React$useState2[1];
4690
+ var deltaX = clientX - stateRef.current.prevX;
4691
+ var deltaY = clientY - stateRef.current.prevY;
4692
+ var distanceX = clientX - stateRef.current.startX;
4693
+ var distanceY = clientY - stateRef.current.startY; // Drag event
4760
4694
 
4761
- React__default['default'].useEffect(function () {
4762
- var onKeyDown = function onKeyDown(e) {
4763
- if (e.key === "u" || e.key === "l") {
4764
- setUnlock(true);
4765
- }
4766
- };
4695
+ queue(onDrag, {
4696
+ deltaX: deltaX,
4697
+ deltaY: deltaY,
4698
+ startX: stateRef.current.startX,
4699
+ startY: stateRef.current.startY,
4700
+ clientX: clientX,
4701
+ clientY: clientY,
4702
+ distanceX: distanceX,
4703
+ distanceY: distanceY,
4704
+ button: stateRef.current.currentButton,
4705
+ altKey: altKey,
4706
+ ctrlKey: ctrlKey,
4707
+ metaKey: metaKey,
4708
+ target: stateRef.current.target,
4709
+ event: e
4710
+ });
4711
+ } else {
4712
+ if (!stateRef.current.gestureStart) {
4713
+ wrapperRef.current.style.cursor = "move";
4714
+ stateRef.current.gestureStart = true; // Clear tap timeout on first move
4767
4715
 
4768
- var onKeyUp = function onKeyUp(e) {
4769
- if (e.key === "u" || e.key === "l") {
4770
- setUnlock(false);
4771
- }
4772
- };
4716
+ clearTimeout(stateRef.current.longTapTimeout);
4717
+ } // Create closure
4773
4718
 
4774
- document.addEventListener("keydown", onKeyDown);
4775
- document.addEventListener("keyup", onKeyUp);
4776
- return function () {
4777
- document.removeEventListener("keydown", onKeyDown);
4778
- document.removeEventListener("keyup", onKeyUp);
4779
- };
4780
- }, []);
4781
- return unlock;
4782
- };
4783
4719
 
4784
- var ItemList = function ItemList(_ref) {
4785
- var itemTemplates = _ref.itemTemplates;
4720
+ var _deltaX = clientX - stateRef.current.prevX;
4786
4721
 
4787
- var _useItemActions = useItemActions(),
4788
- updateItem = _useItemActions.updateItem;
4722
+ var _deltaY = clientY - stateRef.current.prevY;
4789
4723
 
4790
- var itemList = recoil.useRecoilValue(ItemListAtom);
4791
- var itemMap = recoil.useRecoilValue(ItemMapAtom);
4792
- var selectedItems = recoil.useRecoilValue(SelectedItemsAtom);
4724
+ var target = stateRef.current.target; // Pan event
4793
4725
 
4794
- var _useRecoilValue = recoil.useRecoilValue(ConfigurationAtom),
4795
- boardSize = _useRecoilValue.boardSize;
4726
+ queue(onPan, {
4727
+ deltaX: _deltaX,
4728
+ deltaY: _deltaY,
4729
+ button: stateRef.current.currentButton,
4730
+ altKey: altKey,
4731
+ ctrlKey: ctrlKey,
4732
+ metaKey: metaKey,
4733
+ target: target,
4734
+ event: e
4735
+ });
4796
4736
 
4797
- var _useUsers = useUsers(),
4798
- currentUser = _useUsers.currentUser;
4737
+ if (twoFingers && distance !== stateRef.current.prevDistance && onZoom) {
4738
+ var scale = stateRef.current.prevDistance - distance;
4799
4739
 
4800
- var unlocked = useUnlock();
4801
- return itemList.map(function (itemId) {
4802
- return /*#__PURE__*/React__default['default'].createElement(MemoizedPositionedItem, {
4803
- key: itemId,
4804
- state: itemMap[itemId],
4805
- setState: updateItem,
4806
- isSelected: selectedItems.includes(itemId),
4807
- unlocked: unlocked,
4808
- itemMap: itemTemplates,
4809
- boardSize: boardSize,
4810
- currentUser: currentUser
4811
- });
4812
- });
4813
- };
4740
+ if (Math.abs(scale) > 0) {
4741
+ queue(onZoom, {
4742
+ scale: scale,
4743
+ clientX: clientX,
4744
+ clientY: clientY,
4745
+ event: e
4746
+ });
4747
+ stateRef.current.prevDistance = distance;
4748
+ }
4749
+ }
4750
+ }
4814
4751
 
4815
- var SubcribeItemEvents = function SubcribeItemEvents() {
4816
- var _useWire = useWire("board"),
4817
- wire = _useWire.wire;
4752
+ stateRef.current.prevX = clientX;
4753
+ stateRef.current.prevY = clientY;
4754
+ }
4755
+ }, [onDrag, onDragStart, onPan, onZoom, queue]);
4756
+ var onPointerUp = React__default['default'].useCallback(function (e) {
4757
+ var clientX = e.clientX,
4758
+ clientY = e.clientY,
4759
+ altKey = e.altKey,
4760
+ ctrlKey = e.ctrlKey,
4761
+ metaKey = e.metaKey,
4762
+ target = e.target,
4763
+ pointerId = e.pointerId;
4818
4764
 
4819
- var setItemMap = recoil.useSetRecoilState(ItemMapAtom);
4765
+ if (!stateRef.current.pointers[pointerId]) {
4766
+ // Pointer already gone previously with another event
4767
+ // ignoring it
4768
+ return;
4769
+ } // Remove pointer from map
4820
4770
 
4821
- var _useItemActions = useItemActions(),
4822
- updateItemOrder = _useItemActions.updateItemOrder,
4823
- moveItems = _useItemActions.moveItems,
4824
- removeItems = _useItemActions.removeItems,
4825
- pushItem = _useItemActions.pushItem;
4826
4771
 
4827
- var batchUpdate = React__default['default'].useCallback(function (updatedItems) {
4828
- setItemMap(function (prevItemMap) {
4829
- return _objectSpread2(_objectSpread2({}, prevItemMap), updatedItems);
4830
- });
4831
- }, [setItemMap]);
4832
- React__default['default'].useEffect(function () {
4833
- var unsub = wire.subscribe("batchItemsUpdate", function (updatedItems) {
4834
- batchUpdate(updatedItems);
4835
- });
4836
- return unsub;
4837
- }, [wire, batchUpdate]);
4838
- React__default['default'].useEffect(function () {
4839
- var unsub = wire.subscribe("selectedItemsMove", function (_ref) {
4840
- var itemIds = _ref.itemIds,
4841
- posDelta = _ref.posDelta;
4842
- moveItems(itemIds, posDelta, false);
4843
- });
4844
- return unsub;
4845
- }, [wire, moveItems]);
4846
- React__default['default'].useEffect(function () {
4847
- var unsub = wire.subscribe("updateItemListOrder", function (itemIds) {
4848
- updateItemOrder(itemIds, false);
4849
- });
4850
- return unsub;
4851
- }, [wire, updateItemOrder]);
4852
- React__default['default'].useEffect(function () {
4853
- var unsub = wire.subscribe("pushItem", function (newItem) {
4854
- pushItem(newItem, null, false);
4855
- });
4856
- return unsub;
4857
- }, [wire, pushItem]);
4858
- React__default['default'].useEffect(function () {
4859
- var unsub = wire.subscribe("insertItemBefore", function (_ref2) {
4860
- var _ref3 = _slicedToArray(_ref2, 2),
4861
- newItem = _ref3[0],
4862
- beforeId = _ref3[1];
4772
+ delete stateRef.current.pointers[pointerId];
4863
4773
 
4864
- pushItem(newItem, beforeId, false);
4865
- });
4866
- return unsub;
4867
- }, [wire, pushItem]);
4868
- React__default['default'].useEffect(function () {
4869
- var unsub = wire.subscribe("removeItems", function (itemIds) {
4870
- removeItems(itemIds, false);
4871
- });
4872
- return unsub;
4873
- }, [wire, removeItems]);
4874
- return null;
4875
- };
4774
+ if (stateRef.current.mainPointer !== pointerId) {
4775
+ // If this is not the main pointer we quit here
4776
+ return;
4777
+ }
4876
4778
 
4877
- /**
4878
- * Check if element or parent has className.
4879
- * @param {DOMElement} element
4880
- * @param {string} className
4881
- */
4882
- var hasClass = function hasClass(element, className) {
4883
- return element.classList && element.classList.contains(className);
4884
- };
4885
- var insideClass = function insideClass(element, className) {
4886
- if (hasClass(element, className)) {
4887
- return element;
4888
- }
4779
+ while (Object.keys(stateRef.current.pointers).length > 0) {
4780
+ // If was main pointer but we have another one, this one become main
4781
+ stateRef.current.mainPointer = Number(Object.keys(stateRef.current.pointers)[0]);
4889
4782
 
4890
- if (!element.parentNode) {
4891
- return false;
4892
- }
4783
+ try {
4784
+ stateRef.current.target.setPointerCapture(stateRef.current.mainPointer);
4785
+ return;
4786
+ } catch (error) {
4787
+ // eslint-disable-next-line no-console
4788
+ console.log("Fails to set pointer capture", error);
4789
+ stateRef.current.mainPointer = undefined;
4790
+ delete stateRef.current.pointers[Object.keys(stateRef.current.pointers)[0]];
4791
+ }
4792
+ }
4893
4793
 
4894
- return insideClass(element.parentNode, className);
4895
- };
4896
- var isPointInsideRect = function isPointInsideRect(point, rect) {
4897
- return point.x > rect.left && point.x < rect.left + rect.width && point.y > rect.top && point.y < rect.top + rect.height;
4898
- };
4899
- var isItemInsideElement = function isItemInsideElement(itemElement, otherElem) {
4900
- var rect = otherElem.getBoundingClientRect();
4901
- var fourElem = Array.from(itemElement.querySelectorAll(".corner"));
4902
- return fourElem.every(function (corner) {
4903
- var _corner$getBoundingCl = corner.getBoundingClientRect(),
4904
- y = _corner$getBoundingCl.top,
4905
- x = _corner$getBoundingCl.left;
4794
+ stateRef.current.mainPointer = undefined;
4795
+ stateRef.current.pressed = false; // Clear longTap
4906
4796
 
4907
- return isPointInsideRect({
4908
- x: x,
4909
- y: y
4910
- }, rect);
4911
- });
4912
- };
4913
- var getItemElem = function getItemElem(wrapper, itemId) {
4914
- var elems = wrapper.getElementsByClassName("item ".concat(itemId));
4915
- var elem = elems[0];
4797
+ clearTimeout(stateRef.current.longTapTimeout);
4916
4798
 
4917
- if (!elem) {
4918
- // eslint-disable-next-line no-console
4919
- console.error("Missing item ".concat(itemId));
4920
- }
4799
+ if (stateRef.current.moving) {
4800
+ // If we were moving, send drag end event
4801
+ stateRef.current.moving = false;
4802
+ queue(onDragEnd, {
4803
+ deltaX: clientX - stateRef.current.prevX,
4804
+ deltaY: clientY - stateRef.current.prevY,
4805
+ startX: stateRef.current.startX,
4806
+ startY: stateRef.current.startY,
4807
+ clientX: clientX,
4808
+ clientY: clientY,
4809
+ distanceX: clientX - stateRef.current.startX,
4810
+ distanceY: clientY - stateRef.current.startY,
4811
+ button: stateRef.current.currentButton,
4812
+ altKey: altKey,
4813
+ ctrlKey: ctrlKey,
4814
+ metaKey: metaKey,
4815
+ event: e
4816
+ });
4817
+ wrapperRef.current.style.cursor = "auto";
4818
+ } else {
4819
+ var now = Date.now();
4921
4820
 
4922
- return elem;
4821
+ if (stateRef.current.noTap) {
4822
+ stateRef.current.noTap = false;
4823
+ } // Send tap event only if time less than 300ms
4824
+ else if (stateRef.current.timeStart - now < 300) {
4825
+ queue(onTap, {
4826
+ clientX: clientX,
4827
+ clientY: clientY,
4828
+ altKey: altKey,
4829
+ ctrlKey: ctrlKey,
4830
+ metaKey: metaKey,
4831
+ target: target
4832
+ });
4833
+ }
4834
+ }
4835
+ }, [onDragEnd, onTap, queue]);
4836
+ var onDoubleTapHandler = React__default['default'].useCallback(function (event) {
4837
+ queue(onDoubleTap, event);
4838
+ }, [onDoubleTap, queue]);
4839
+ return /*#__PURE__*/React__default['default'].createElement("div", {
4840
+ onWheel: onWheel,
4841
+ onPointerDown: onPointerDown,
4842
+ onPointerMove: onPointerMove,
4843
+ onPointerUp: onPointerUp,
4844
+ onPointerOut: onPointerUp,
4845
+ onPointerLeave: onPointerUp,
4846
+ onPointerCancel: onPointerUp,
4847
+ onDoubleClick: onDoubleTapHandler,
4848
+ style: {
4849
+ touchAction: "none"
4850
+ },
4851
+ ref: wrapperRef
4852
+ }, children);
4923
4853
  };
4924
- var getIdFromElem = function getIdFromElem(elem) {
4925
- var _elem$dataset;
4926
4854
 
4927
- var value = elem === null || elem === void 0 ? void 0 : (_elem$dataset = elem.dataset) === null || _elem$dataset === void 0 ? void 0 : _elem$dataset.id;
4855
+ var _excluded$3 = ["onResize"];
4928
4856
 
4929
- if (!value) {
4930
- var _elem$dataset2;
4857
+ var ResizeHandler = function ResizeHandler(_ref) {
4858
+ var onResize = _ref.onResize,
4859
+ rest = _objectWithoutProperties(_ref, _excluded$3);
4931
4860
 
4932
- // eslint-disable-next-line no-console
4933
- console.error("getIdFromElem call fails", elem, JSON.stringify(elem === null || elem === void 0 ? void 0 : elem.dataset), elem === null || elem === void 0 ? void 0 : (_elem$dataset2 = elem.dataset) === null || _elem$dataset2 === void 0 ? void 0 : _elem$dataset2.id);
4934
- }
4861
+ var onDrag = recoil.useRecoilCallback(function (_ref2) {
4862
+ var snapshot = _ref2.snapshot;
4863
+ return /*#__PURE__*/function () {
4864
+ var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref3) {
4865
+ var deltaX, deltaY, event, _yield$snapshot$getPr, scale;
4935
4866
 
4936
- return value;
4937
- };
4938
- var getItemBoundingBox = function getItemBoundingBox(items) {
4939
- var wrapper = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
4940
- var result = items.reduce(function (prev, itemId) {
4941
- var elem = getItemElem(wrapper, itemId);
4942
- if (!elem) return null;
4867
+ return regeneratorRuntime.wrap(function _callee$(_context) {
4868
+ while (1) {
4869
+ switch (_context.prev = _context.next) {
4870
+ case 0:
4871
+ deltaX = _ref3.deltaX, deltaY = _ref3.deltaY, event = _ref3.event;
4872
+ event.stopPropagation();
4873
+ _context.next = 4;
4874
+ return snapshot.getPromise(BoardTransformAtom);
4943
4875
 
4944
- var _elem$getBoundingClie = elem.getBoundingClientRect(),
4945
- left = _elem$getBoundingClie.left,
4946
- right = _elem$getBoundingClie.right,
4947
- top = _elem$getBoundingClie.top,
4948
- bottom = _elem$getBoundingClie.bottom;
4876
+ case 4:
4877
+ _yield$snapshot$getPr = _context.sent;
4878
+ scale = _yield$snapshot$getPr.scale;
4879
+ onResize({
4880
+ width: deltaX / scale,
4881
+ height: deltaY / scale
4882
+ });
4949
4883
 
4950
- var boundingBox;
4884
+ case 7:
4885
+ case "end":
4886
+ return _context.stop();
4887
+ }
4888
+ }
4889
+ }, _callee);
4890
+ }));
4951
4891
 
4952
- if (!prev) {
4953
- boundingBox = {
4954
- left: left,
4955
- top: top,
4956
- right: right,
4957
- bottom: bottom
4892
+ return function (_x) {
4893
+ return _ref4.apply(this, arguments);
4958
4894
  };
4959
- } else {
4960
- boundingBox = prev;
4961
- }
4962
-
4963
- boundingBox.left = Math.min(left, boundingBox.left);
4964
- boundingBox.top = Math.min(top, boundingBox.top);
4965
- boundingBox.right = Math.max(right, boundingBox.right);
4966
- boundingBox.bottom = Math.max(bottom, boundingBox.bottom);
4967
- return boundingBox;
4968
- }, null);
4895
+ }();
4896
+ }, [onResize]);
4897
+ return /*#__PURE__*/React__default['default'].createElement(Gesture, {
4898
+ onDrag: onDrag
4899
+ }, /*#__PURE__*/React__default['default'].createElement("div", rest));
4900
+ };
4969
4901
 
4970
- if (!result) {
4971
- return result;
4972
- }
4902
+ 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";
4973
4903
 
4974
- result.width = result.right - result.left;
4975
- result.height = result.bottom - result.top;
4976
- return result;
4977
- };
4904
+ var _excluded$2 = ["type", "rotation", "id", "locked", "layer"],
4905
+ _excluded2 = ["state", "boardSize", "currentUser"],
4906
+ _excluded3 = ["x", "y", "layer", "moving"];
4978
4907
 
4979
- var isMacOS = function isMacOS() {
4980
- var userAgent = navigator.userAgent.toLowerCase();
4981
- return /mac os ?x 10/.test(userAgent);
4982
- }; // From https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
4908
+ var _templateObject$2;
4909
+ var ItemWrapper = newStyled.div(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteral(["\n display: inline-block;\n transition: transform 150ms;\n user-select: none;\n padding: 2px;\n box-sizing: border-box;\n transform: rotate(", "deg);\n\n & .corner {\n position: absolute;\n width: 0px;\n height: 0px;\n }\n\n & .top-left {\n top: 0;\n left: 0;\n }\n & .top-right {\n top: 0;\n right: 0;\n }\n & .bottom-left {\n bottom: 0;\n left: 0;\n }\n & .bottom-right {\n bottom: 0;\n right: 0;\n }\n\n &.selected {\n border: 2px dashed #db5034;\n padding: 0px;\n cursor: pointer;\n }\n\n &.locked::after {\n content: \"\";\n position: absolute;\n width: 24px;\n height: 30px;\n top: 4px;\n right: 4px;\n opacity: 0.1;\n background-image: url(\"", "\");\n background-size: cover;\n user-select: none;\n }\n\n &.locked:hover::after {\n opacity: 0.3;\n }\n\n & .resize {\n position: absolute;\n\n width: 10px;\n height: 10px;\n border: 2px solid #db5034;\n background-color: #db5034;\n cursor: move;\n\n &.resize-width {\n cursor: ew-resize;\n right: -6px;\n top: calc(50% - 5px);\n }\n &.resize-height {\n cursor: ns-resize;\n bottom: -6px;\n left: calc(50% - 5px);\n }\n &.resize-ratio {\n cursor: nwse-resize;\n bottom: -6px;\n right: -6px;\n }\n }\n"])), function (_ref) {
4910
+ var rotation = _ref.rotation;
4911
+ return rotation;
4912
+ }, img);
4983
4913
 
4984
- var getScrollLineHeight = function getScrollLineHeight() {
4985
- var iframe = document.createElement("iframe");
4986
- iframe.src = "#";
4987
- document.body.appendChild(iframe); // Write content in Iframe
4914
+ var identity = function identity(x) {
4915
+ return x;
4916
+ };
4988
4917
 
4989
- var idoc = iframe.contentWindow.document;
4990
- idoc.open();
4991
- idoc.write("<!DOCTYPE html><html><head></head><body><span>a</span></body></html>");
4992
- idoc.close();
4993
- var scrollLineHeight = idoc.body.firstElementChild.offsetHeight;
4994
- document.body.removeChild(iframe);
4995
- return scrollLineHeight;
4918
+ var DefaultErrorComponent = function DefaultErrorComponent(_ref2) {
4919
+ var onReload = _ref2.onReload;
4920
+ return /*#__PURE__*/React__default['default'].createElement("div", {
4921
+ style: {
4922
+ width: "100px",
4923
+ display: "flex",
4924
+ flexDirection: "column",
4925
+ justifyContent: "center",
4926
+ textAlign: "center",
4927
+ color: "red"
4928
+ },
4929
+ className: "syncboard-error-item"
4930
+ }, "Sorry, this item seems broken.", /*#__PURE__*/React__default['default'].createElement("button", {
4931
+ onClick: onReload
4932
+ }, "Reload it"));
4996
4933
  };
4934
+ /* Error boundary for broken item */
4997
4935
 
4998
- var LINE_HEIGHT = getScrollLineHeight(); // Reasonable default from https://github.com/facebookarchive/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js
4999
4936
 
5000
- var PAGE_HEIGHT = 800;
4937
+ var ItemErrorBoundary = /*#__PURE__*/function (_React$Component) {
4938
+ _inherits(ItemErrorBoundary, _React$Component);
5001
4939
 
5002
- var otherPointer = function otherPointer(pointers, currentPointer) {
5003
- var p2 = Object.keys(pointers).map(function (p) {
5004
- return Number(p);
5005
- }).find(function (pointer) {
5006
- return pointer !== currentPointer;
5007
- });
5008
- return pointers[p2];
5009
- };
4940
+ var _super = _createSuper(ItemErrorBoundary);
5010
4941
 
5011
- var computeDistance = function computeDistance(_ref, _ref2) {
5012
- var _ref3 = _slicedToArray(_ref, 2),
5013
- x1 = _ref3[0],
5014
- y1 = _ref3[1];
4942
+ function ItemErrorBoundary(props) {
4943
+ var _this;
5015
4944
 
5016
- var _ref4 = _slicedToArray(_ref2, 2),
5017
- x2 = _ref4[0],
5018
- y2 = _ref4[1];
4945
+ _classCallCheck(this, ItemErrorBoundary);
5019
4946
 
5020
- var distanceX = Math.abs(x1 - x2);
5021
- var distanceY = Math.abs(y1 - y2);
5022
- return Math.hypot(distanceX, distanceY);
5023
- };
4947
+ _this = _super.call(this, props);
4948
+ _this.state = {
4949
+ hasError: false,
4950
+ itemId: props.itemId
4951
+ };
4952
+ _this.onReload = _this.onReload.bind(_assertThisInitialized(_this));
4953
+ return _this;
4954
+ }
5024
4955
 
5025
- var empty = function empty() {};
4956
+ _createClass(ItemErrorBoundary, [{
4957
+ key: "componentDidCatch",
4958
+ value: function componentDidCatch(error) {
4959
+ // eslint-disable-next-line no-console
4960
+ console.error("Error for item ".concat(this.state.itemId), error, this.props.state);
4961
+ }
4962
+ }, {
4963
+ key: "onReload",
4964
+ value: function onReload() {
4965
+ this.setState({
4966
+ hasError: false
4967
+ });
4968
+ }
4969
+ }, {
4970
+ key: "render",
4971
+ value: function render() {
4972
+ var ErrorComponent = this.props.ErrorComponent;
5026
4973
 
5027
- var protect = function protect(fn) {
5028
- return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
5029
- var _args = arguments;
5030
- return regeneratorRuntime.wrap(function _callee$(_context) {
5031
- while (1) {
5032
- switch (_context.prev = _context.next) {
5033
- case 0:
5034
- _context.prev = 0;
5035
- _context.next = 3;
5036
- return fn.apply(void 0, _args);
4974
+ if (this.state.hasError) {
4975
+ return /*#__PURE__*/React__default['default'].createElement(ErrorComponent, {
4976
+ onReload: this.onReload
4977
+ });
4978
+ }
5037
4979
 
5038
- case 3:
5039
- _context.next = 8;
5040
- break;
4980
+ return this.props.children;
4981
+ }
4982
+ }], [{
4983
+ key: "getDerivedStateFromError",
4984
+ value: function getDerivedStateFromError() {
4985
+ return {
4986
+ hasError: true
4987
+ };
4988
+ }
4989
+ }]);
5041
4990
 
5042
- case 5:
5043
- _context.prev = 5;
5044
- _context.t0 = _context["catch"](0);
5045
- // eslint-disable-next-line no-console
5046
- console.error(_context.t0);
4991
+ return ItemErrorBoundary;
4992
+ }(React__default['default'].Component);
5047
4993
 
5048
- case 8:
5049
- case "end":
5050
- return _context.stop();
5051
- }
5052
- }
5053
- }, _callee, null, [[0, 5]]);
5054
- }));
4994
+ var removeClass = function removeClass(e) {
4995
+ e.target.className = "";
5055
4996
  };
5056
4997
 
5057
- var Gesture = function Gesture(_ref6) {
5058
- var children = _ref6.children,
5059
- _ref6$onDrag = _ref6.onDrag,
5060
- onDrag = _ref6$onDrag === void 0 ? empty : _ref6$onDrag,
5061
- _ref6$onDragStart = _ref6.onDragStart,
5062
- onDragStart = _ref6$onDragStart === void 0 ? empty : _ref6$onDragStart,
5063
- _ref6$onDragEnd = _ref6.onDragEnd,
5064
- onDragEnd = _ref6$onDragEnd === void 0 ? empty : _ref6$onDragEnd,
5065
- _ref6$onPan = _ref6.onPan,
5066
- onPan = _ref6$onPan === void 0 ? empty : _ref6$onPan,
5067
- _ref6$onTap = _ref6.onTap,
5068
- onTap = _ref6$onTap === void 0 ? empty : _ref6$onTap,
5069
- _ref6$onLongTap = _ref6.onLongTap,
5070
- onLongTap = _ref6$onLongTap === void 0 ? empty : _ref6$onLongTap,
5071
- _ref6$onDoubleTap = _ref6.onDoubleTap,
5072
- onDoubleTap = _ref6$onDoubleTap === void 0 ? empty : _ref6$onDoubleTap,
5073
- onZoom = _ref6.onZoom;
5074
- var wrapperRef = React__default['default'].useRef(null);
5075
- var stateRef = React__default['default'].useRef({
5076
- moving: false,
5077
- pointers: {},
5078
- mainPointer: undefined
5079
- });
5080
- var queueRef = React__default['default'].useRef([]); // Queue event to avoid async mess
4998
+ var defaultResize = function defaultResize(_ref3) {
4999
+ var width = _ref3.width,
5000
+ height = _ref3.height,
5001
+ actualWidth = _ref3.actualWidth,
5002
+ actualHeight = _ref3.actualHeight,
5003
+ prevState = _ref3.prevState,
5004
+ keepRatio = _ref3.keepRatio;
5005
+ var currentWidth = prevState.width,
5006
+ currentHeight = prevState.height; // Parse text values if any
5007
+
5008
+ var _ref4 = [parseFloat(currentWidth), parseFloat(currentHeight)];
5009
+ currentWidth = _ref4[0];
5010
+ currentHeight = _ref4[1];
5011
+
5012
+ if (!currentWidth || Number.isNaN(Number(currentWidth))) {
5013
+ currentWidth = actualWidth;
5014
+ }
5081
5015
 
5082
- var queue = React__default['default'].useCallback(function (callback, args) {
5083
- queueRef.current.push( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
5084
- return regeneratorRuntime.wrap(function _callee2$(_context2) {
5085
- while (1) {
5086
- switch (_context2.prev = _context2.next) {
5087
- case 0:
5088
- _context2.next = 2;
5089
- return protect(callback)(args);
5016
+ if (!currentHeight || Number.isNaN(Number(currentHeight))) {
5017
+ currentHeight = actualHeight;
5018
+ }
5090
5019
 
5091
- case 2:
5092
- queueRef.current.shift();
5020
+ if (keepRatio) {
5021
+ var ratio = currentWidth / currentHeight;
5022
+ return _objectSpread2(_objectSpread2({}, prevState), {}, {
5023
+ width: (currentWidth + width).toFixed(1),
5024
+ height: (currentHeight + height / ratio).toFixed(1)
5025
+ });
5026
+ }
5093
5027
 
5094
- if (!(queueRef.current.length !== 0)) {
5095
- _context2.next = 6;
5096
- break;
5097
- }
5028
+ return _objectSpread2(_objectSpread2({}, prevState), {}, {
5029
+ width: (currentWidth + width).toFixed(1),
5030
+ height: (currentHeight + height).toFixed(1)
5031
+ });
5032
+ };
5098
5033
 
5099
- _context2.next = 6;
5100
- return protect(queueRef.current[0])();
5034
+ var defaultResizeDirection = {
5035
+ w: true,
5036
+ h: true,
5037
+ b: true
5038
+ };
5101
5039
 
5102
- case 6:
5103
- case "end":
5104
- return _context2.stop();
5105
- }
5106
- }
5107
- }, _callee2);
5108
- })));
5040
+ var Item = function Item(_ref5) {
5041
+ var _itemMap$error;
5109
5042
 
5110
- if (queueRef.current.length === 1) {
5111
- protect(queueRef.current[0])();
5112
- }
5113
- }, []);
5114
- var onWheel = React__default['default'].useCallback(function (e) {
5115
- var deltaX = e.deltaX,
5116
- deltaY = e.deltaY,
5117
- clientX = e.clientX,
5118
- clientY = e.clientY,
5119
- deltaMode = e.deltaMode,
5120
- ctrlKey = e.ctrlKey,
5121
- altKey = e.altKey,
5122
- metaKey = e.metaKey,
5123
- target = e.target; // On a MacOs trackpad, the pinch gesture sets the ctrlKey to true.
5124
- // In that situation, we want to use the custom scaling, not the browser default zoom.
5125
- // Hence in this situation we avoid to return immediately.
5043
+ var setState = _ref5.setState,
5044
+ _ref5$state = _ref5.state;
5045
+ _ref5$state = _ref5$state === void 0 ? {} : _ref5$state;
5046
+
5047
+ var type = _ref5$state.type,
5048
+ _ref5$state$rotation = _ref5$state.rotation,
5049
+ rotation = _ref5$state$rotation === void 0 ? 0 : _ref5$state$rotation,
5050
+ id = _ref5$state.id,
5051
+ locked = _ref5$state.locked,
5052
+ layer = _ref5$state.layer,
5053
+ rest = _objectWithoutProperties(_ref5$state, _excluded$2),
5054
+ _ref5$animate = _ref5.animate,
5055
+ animate = _ref5$animate === void 0 ? "hvr-pop" : _ref5$animate,
5056
+ isSelected = _ref5.isSelected,
5057
+ itemMap = _ref5.itemMap,
5058
+ _ref5$showResizeHandl = _ref5.showResizeHandle,
5059
+ showResizeHandle = _ref5$showResizeHandl === void 0 ? false : _ref5$showResizeHandl;
5060
+
5061
+ var itemWrapperRef = React__default['default'].useRef(null);
5062
+ var _itemMap$type = itemMap[type],
5063
+ _itemMap$type$compone = _itemMap$type.component,
5064
+ Component = _itemMap$type$compone === void 0 ? function () {
5065
+ return null;
5066
+ } : _itemMap$type$compone,
5067
+ _itemMap$type$resizeD = _itemMap$type.resizeDirections,
5068
+ resizeDirections = _itemMap$type$resizeD === void 0 ? defaultResizeDirection : _itemMap$type$resizeD,
5069
+ _itemMap$type$resize = _itemMap$type.resize,
5070
+ resize = _itemMap$type$resize === void 0 ? defaultResize : _itemMap$type$resize;
5071
+ var updateState = React__default['default'].useCallback(function (callbackOrItem) {
5072
+ var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
5073
+ return setState(id, callbackOrItem, sync);
5074
+ }, [setState, id]);
5075
+ React__default['default'].useEffect(function () {
5076
+ itemWrapperRef.current.className = animate;
5077
+ }, [animate]);
5078
+ var className = "item ".concat(id);
5126
5079
 
5127
- if (altKey || ctrlKey && !isMacOS()) {
5128
- return;
5129
- } // On a trackpad, the pinch and pan events are differentiated by the crtlKey value.
5130
- // On a pinch gesture, the ctrlKey is set to true, so we want to have a scaling effect.
5131
- // If we are only moving the fingers in the same direction, a pan is needed.
5132
- // Ref: https://medium.com/@auchenberg/detecting-multi-touch-trackpad-gestures-in-javascript-a2505babb10e
5080
+ if (locked) {
5081
+ className += " locked";
5082
+ }
5133
5083
 
5084
+ if (isSelected) {
5085
+ className += " selected";
5086
+ }
5134
5087
 
5135
- if (isMacOS() && !ctrlKey) {
5136
- queue(onPan, {
5137
- deltaX: -2 * deltaX,
5138
- deltaY: -2 * deltaY,
5139
- button: 1,
5140
- ctrlKey: ctrlKey,
5141
- metaKey: metaKey,
5142
- target: target,
5143
- event: e
5088
+ var onResize = React__default['default'].useCallback(function (_ref6) {
5089
+ var _ref6$width = _ref6.width,
5090
+ width = _ref6$width === void 0 ? 0 : _ref6$width,
5091
+ _ref6$height = _ref6.height,
5092
+ height = _ref6$height === void 0 ? 0 : _ref6$height,
5093
+ keepRatio = _ref6.keepRatio;
5094
+ updateState(function (prev) {
5095
+ var _itemWrapperRef$curre = itemWrapperRef.current,
5096
+ offsetWidth = _itemWrapperRef$curre.offsetWidth,
5097
+ offsetHeight = _itemWrapperRef$curre.offsetHeight;
5098
+ return resize({
5099
+ prevState: prev,
5100
+ width: width,
5101
+ height: height,
5102
+ actualHeight: offsetHeight,
5103
+ actualWidth: offsetWidth,
5104
+ keepRatio: keepRatio
5144
5105
  });
5145
- } else {
5146
- // Quit if onZoom is not set
5147
- if (onZoom === undefined || !deltaY) return;
5148
- var scale = deltaY;
5106
+ });
5107
+ }, [resize, updateState]);
5108
+ var onResizeWidth = React__default['default'].useCallback(function (_ref7) {
5109
+ var width = _ref7.width;
5110
+ onResize({
5111
+ width: width
5112
+ });
5113
+ }, [onResize]);
5114
+ var onResizeHeight = React__default['default'].useCallback(function (_ref8) {
5115
+ var height = _ref8.height;
5116
+ onResize({
5117
+ height: height
5118
+ });
5119
+ }, [onResize]);
5120
+ var onResizeRatio = React__default['default'].useCallback(function (_ref9) {
5121
+ var width = _ref9.width;
5122
+ onResize({
5123
+ height: width,
5124
+ width: width,
5125
+ keepRatio: true
5126
+ });
5127
+ }, [onResize]);
5128
+ return /*#__PURE__*/React__default['default'].createElement(ItemWrapper, {
5129
+ rotation: rotation,
5130
+ locked: locked,
5131
+ selected: isSelected,
5132
+ layer: layer,
5133
+ "data-id": id,
5134
+ className: className
5135
+ }, /*#__PURE__*/React__default['default'].createElement("div", {
5136
+ style: {
5137
+ display: "flex"
5138
+ },
5139
+ ref: itemWrapperRef,
5140
+ onAnimationEnd: removeClass,
5141
+ onKeyDown: function onKeyDown(e) {
5142
+ return e.stopPropagation();
5143
+ },
5144
+ onKeyUp: function onKeyUp(e) {
5145
+ return e.stopPropagation();
5146
+ }
5147
+ }, /*#__PURE__*/React__default['default'].createElement(ItemErrorBoundary, {
5148
+ itemId: id,
5149
+ state: rest,
5150
+ setState: updateState,
5151
+ ErrorComponent: (itemMap === null || itemMap === void 0 ? void 0 : (_itemMap$error = itemMap.error) === null || _itemMap$error === void 0 ? void 0 : _itemMap$error.component) || DefaultErrorComponent
5152
+ }, /*#__PURE__*/React__default['default'].createElement(Component, _extends$1({}, rest, {
5153
+ id: id,
5154
+ setState: updateState
5155
+ }))), /*#__PURE__*/React__default['default'].createElement("div", {
5156
+ className: "corner top-left"
5157
+ }), /*#__PURE__*/React__default['default'].createElement("div", {
5158
+ className: "corner top-right"
5159
+ }), /*#__PURE__*/React__default['default'].createElement("div", {
5160
+ className: "corner bottom-left"
5161
+ }), /*#__PURE__*/React__default['default'].createElement("div", {
5162
+ className: "corner bottom-right"
5163
+ }), isSelected && showResizeHandle && /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, resizeDirections.b && /*#__PURE__*/React__default['default'].createElement(ResizeHandler, {
5164
+ className: "resize resize-ratio",
5165
+ onResize: onResizeRatio
5166
+ }), resizeDirections.h && /*#__PURE__*/React__default['default'].createElement(ResizeHandler, {
5167
+ className: "resize resize-height",
5168
+ onResize: onResizeHeight
5169
+ }), resizeDirections.w && /*#__PURE__*/React__default['default'].createElement(ResizeHandler, {
5170
+ className: "resize resize-width",
5171
+ onResize: onResizeWidth
5172
+ }))));
5173
+ };
5149
5174
 
5150
- switch (deltaMode) {
5151
- case 1:
5152
- // Pixel
5153
- scale *= LINE_HEIGHT;
5154
- break;
5175
+ var MemoizedItem = /*#__PURE__*/React.memo(Item, function (_ref10, _ref11) {
5176
+ var prevState = _ref10.state,
5177
+ prevSetState = _ref10.setState,
5178
+ prevIsSelected = _ref10.isSelected,
5179
+ prevShowResizeHandle = _ref10.showResizeHandle;
5180
+ var nextState = _ref11.state,
5181
+ nextSetState = _ref11.setState,
5182
+ nextIsSelected = _ref11.isSelected,
5183
+ nextShowResizeHandle = _ref11.showResizeHandle;
5184
+ return prevIsSelected === nextIsSelected && prevShowResizeHandle === nextShowResizeHandle && prevSetState === nextSetState && JSON.stringify(prevState) === JSON.stringify(nextState);
5185
+ }); // Exclude positioning from memoization
5155
5186
 
5156
- case 2:
5157
- scale *= PAGE_HEIGHT;
5158
- break;
5159
- }
5187
+ var PositionedItem = function PositionedItem(_ref12) {
5188
+ var _ref12$state = _ref12.state,
5189
+ state = _ref12$state === void 0 ? {} : _ref12$state,
5190
+ boardSize = _ref12.boardSize,
5191
+ currentUser = _ref12.currentUser,
5192
+ rest = _objectWithoutProperties(_ref12, _excluded2);
5160
5193
 
5161
- if (isMacOS()) {
5162
- scale *= 2;
5163
- }
5194
+ if (!rest.itemMap[state.type]) {
5195
+ // eslint-disable-next-line no-console
5196
+ console.warn("Item type ".concat(state.type, " not recognized!"));
5197
+ return null;
5198
+ }
5164
5199
 
5165
- queue(onZoom, {
5166
- scale: scale,
5167
- clientX: clientX,
5168
- clientY: clientY,
5169
- event: e
5170
- });
5171
- }
5172
- }, [onPan, onZoom, queue]);
5173
- var onPointerDown = React__default['default'].useCallback(function (_ref8) {
5174
- var target = _ref8.target,
5175
- button = _ref8.button,
5176
- clientX = _ref8.clientX,
5177
- clientY = _ref8.clientY,
5178
- pointerId = _ref8.pointerId,
5179
- altKey = _ref8.altKey,
5180
- ctrlKey = _ref8.ctrlKey,
5181
- metaKey = _ref8.metaKey,
5182
- isPrimary = _ref8.isPrimary;
5183
- // Add pointer to map
5184
- stateRef.current.pointers[pointerId] = {
5185
- clientX: clientX,
5186
- clientY: clientY
5187
- };
5200
+ var _rest$itemMap$state$t = rest.itemMap[state.type].stateHook,
5201
+ stateHook = _rest$itemMap$state$t === void 0 ? identity : _rest$itemMap$state$t;
5202
+
5203
+ var _stateHook = stateHook(state, {
5204
+ currentUser: currentUser
5205
+ }),
5206
+ _stateHook$x = _stateHook.x,
5207
+ x = _stateHook$x === void 0 ? 0 : _stateHook$x,
5208
+ _stateHook$y = _stateHook.y,
5209
+ y = _stateHook$y === void 0 ? 0 : _stateHook$y,
5210
+ _stateHook$layer = _stateHook.layer,
5211
+ layer = _stateHook$layer === void 0 ? 0 : _stateHook$layer,
5212
+ moving = _stateHook.moving,
5213
+ stateRest = _objectWithoutProperties(_stateHook, _excluded3);
5214
+
5215
+ return /*#__PURE__*/React__default['default'].createElement("div", {
5216
+ style: {
5217
+ position: "absolute",
5218
+ top: "".concat(boardSize / 2, "px"),
5219
+ left: "".concat(boardSize / 2, "px"),
5220
+ display: "inline-block",
5221
+ transform: "translate(".concat(x, "px, ").concat(y, "px)"),
5222
+ zIndex: (layer + 4) * 10 + 100 + (moving ? 5 : 0) // Items z-index between 100 and 200
5188
5223
 
5189
- if (isPrimary) {
5190
- // Clean mainPoint on primary pointer
5191
- stateRef.current.mainPointer = undefined;
5192
5224
  }
5225
+ }, /*#__PURE__*/React__default['default'].createElement(MemoizedItem, _extends$1({}, rest, {
5226
+ // Helps to prevent render
5227
+ showResizeHandle: rest.isSelected && rest.showResizeHandle,
5228
+ state: stateRest
5229
+ })));
5230
+ };
5193
5231
 
5194
- if (stateRef.current.mainPointer !== undefined) {
5195
- if (stateRef.current.mainPointer !== pointerId) {
5196
- // This is not the main pointer
5197
- try {
5198
- var _otherPointer = otherPointer(stateRef.current.pointers, pointerId),
5199
- clientX2 = _otherPointer.clientX,
5200
- clientY2 = _otherPointer.clientY;
5232
+ var MemoizedPositionedItem = /*#__PURE__*/React.memo(PositionedItem);
5201
5233
 
5202
- var newClientX = (clientX2 + clientX) / 2;
5203
- var newClientY = (clientY2 + clientY) / 2;
5204
- var distance = computeDistance([clientX2, clientY2], [clientX, clientY]); // We update previous position as the new position is the center beetween both finger
5234
+ var persistUser = function persistUser(user) {
5235
+ localStorage.setItem("user", JSON.stringify(user));
5236
+ };
5237
+ 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"];
5205
5238
 
5206
- Object.assign(stateRef.current, {
5207
- pressed: true,
5208
- moving: false,
5209
- gestureStart: false,
5210
- startX: clientX,
5211
- startY: clientY,
5212
- prevX: newClientX,
5213
- prevY: newClientY,
5214
- startDistance: distance,
5215
- prevDistance: distance
5216
- });
5217
- } catch (e) {
5218
- // eslint-disable-next-line no-console
5219
- console.log("Error while getting other pointer. Ignoring", e); // eslint-disable-next-line no-unused-expressions
5239
+ var getRandomColor = function getRandomColor() {
5240
+ return colors[Math.floor(Math.random() * colors.length)];
5241
+ }; // TODO remove user persistence
5220
5242
 
5221
- stateRef.current.mainPointer === undefined;
5222
- }
5223
- }
5224
5243
 
5225
- return;
5226
- } // We set the mainpointer
5244
+ var getUser = function getUser() {
5245
+ if (localStorage.user) {
5246
+ // Add some mandatory info if missing
5247
+ var localUser = _objectSpread2({
5248
+ name: "Player",
5249
+ color: getRandomColor(),
5250
+ uid: nanoid()
5251
+ }, JSON.parse(localStorage.user)); // Id is given by server
5252
+ // delete localUser.id;
5227
5253
 
5228
5254
 
5229
- stateRef.current.mainPointer = pointerId; // And prepare move
5255
+ persistUser(localUser);
5256
+ return localUser;
5257
+ }
5230
5258
 
5231
- Object.assign(stateRef.current, {
5232
- pressed: true,
5233
- moving: false,
5234
- gestureStart: false,
5235
- startX: clientX,
5236
- startY: clientY,
5237
- prevX: clientX,
5238
- prevY: clientY,
5239
- currentButton: button,
5240
- target: target,
5241
- timeStart: Date.now(),
5242
- longTapTimeout: setTimeout( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
5243
- return regeneratorRuntime.wrap(function _callee3$(_context3) {
5244
- while (1) {
5245
- switch (_context3.prev = _context3.next) {
5246
- case 0:
5247
- stateRef.current.noTap = true;
5248
- queue(onLongTap, {
5249
- clientX: clientX,
5250
- clientY: clientY,
5251
- altKey: altKey,
5252
- ctrlKey: ctrlKey,
5253
- metaKey: metaKey,
5254
- target: target
5255
- });
5259
+ var newUser = {
5260
+ name: "Player",
5261
+ color: getRandomColor(),
5262
+ uid: nanoid()
5263
+ };
5264
+ persistUser(newUser);
5265
+ return newUser;
5266
+ };
5267
+ var userAtom = recoil.atom({
5268
+ key: "user",
5269
+ "default": getUser()
5270
+ });
5271
+ var usersAtom = recoil.atom({
5272
+ key: "users",
5273
+ "default": []
5274
+ });
5275
+ var localUsersAtom = recoil.selector({
5276
+ key: "localUsersAtom",
5277
+ get: function get(_ref) {
5278
+ var _get = _ref.get;
5256
5279
 
5257
- case 2:
5258
- case "end":
5259
- return _context3.stop();
5260
- }
5261
- }
5262
- }, _callee3);
5263
- })), 750)
5280
+ var currentUser = _get(userAtom);
5281
+
5282
+ var users = _get(usersAtom);
5283
+
5284
+ return users.filter(function (_ref2) {
5285
+ var space = _ref2.space;
5286
+ return space === currentUser.space;
5264
5287
  });
5288
+ }
5289
+ });
5265
5290
 
5266
- try {
5267
- target.setPointerCapture(pointerId);
5268
- } catch (e) {
5269
- // eslint-disable-next-line no-console
5270
- console.log("Fail to capture pointer", e);
5271
- }
5272
- }, [onLongTap, queue]);
5273
- var onPointerMove = React__default['default'].useCallback(function (e) {
5274
- if (stateRef.current.pressed) {
5275
- var pointerId = e.pointerId,
5276
- eventClientX = e.clientX,
5277
- eventClientY = e.clientY,
5278
- altKey = e.altKey,
5279
- ctrlKey = e.ctrlKey,
5280
- metaKey = e.metaKey,
5281
- pointerType = e.pointerType;
5291
+ var useUsers = function useUsers() {
5292
+ var _useRecoilState = recoil.useRecoilState(userAtom),
5293
+ _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
5294
+ currentUser = _useRecoilState2[0],
5295
+ setCurrentUserState = _useRecoilState2[1];
5282
5296
 
5283
- if (stateRef.current.mainPointer !== pointerId) {
5284
- // Event from other pointer
5285
- stateRef.current.pointers[pointerId] = {
5286
- clientX: eventClientX,
5287
- clientY: eventClientY
5288
- };
5289
- return;
5290
- }
5297
+ var users = recoil.useRecoilValue(usersAtom);
5298
+ var localUsers = recoil.useRecoilValue(localUsersAtom);
5299
+ var setCurrentUser = React__default['default'].useCallback(function (callbackOrUser) {
5300
+ var callback = callbackOrUser;
5291
5301
 
5292
- stateRef.current.moving = true; // Do we have two fingers ?
5302
+ if (_typeof(callbackOrUser) === "object") {
5303
+ callback = function callback() {
5304
+ return callbackOrUser;
5305
+ };
5306
+ }
5293
5307
 
5294
- var twoFingers = Object.keys(stateRef.current.pointers).length === 2;
5295
- var clientX;
5296
- var clientY;
5297
- var distance;
5308
+ setCurrentUserState(function (prevUser) {
5309
+ var newUser = _objectSpread2(_objectSpread2({}, callback(prevUser)), {}, {
5310
+ id: prevUser.id,
5311
+ uid: prevUser.uid
5312
+ });
5298
5313
 
5299
- if (twoFingers) {
5300
- // Find other pointerId
5301
- var _otherPointer2 = otherPointer(stateRef.current.pointers, pointerId),
5302
- clientX2 = _otherPointer2.clientX,
5303
- clientY2 = _otherPointer2.clientY; // Update client X with the center of each touch
5314
+ persistUser(newUser);
5315
+ return newUser;
5316
+ });
5317
+ }, [setCurrentUserState]);
5318
+ return {
5319
+ currentUser: currentUser,
5320
+ setCurrentUser: setCurrentUser,
5321
+ users: users,
5322
+ localUsers: localUsers
5323
+ };
5324
+ };
5304
5325
 
5326
+ var SubscribeUserEvents = function SubscribeUserEvents() {
5327
+ var usersRef = React__default['default'].useRef([]);
5328
+ var setUsers = recoil.useSetRecoilState(usersAtom);
5305
5329
 
5306
- clientX = (clientX2 + eventClientX) / 2;
5307
- clientY = (clientY2 + eventClientY) / 2;
5308
- distance = computeDistance([clientX2, clientY2], [eventClientX, eventClientY]);
5309
- } else {
5310
- clientX = eventClientX;
5311
- clientY = eventClientY;
5312
- } // We drag if
5313
- // On non touch device
5314
- // - Button is 0
5315
- // - Alt key is no pressed
5316
- // or on touch devices
5317
- // - We use only one finger
5330
+ var _useRecoilState = recoil.useRecoilState(userAtom),
5331
+ _useRecoilState2 = _slicedToArray(_useRecoilState, 2),
5332
+ currentUser = _useRecoilState2[0],
5333
+ setCurrentUserState = _useRecoilState2[1];
5318
5334
 
5335
+ var _useWire = useWire("room"),
5336
+ wire = _useWire.wire,
5337
+ isMaster = _useWire.isMaster,
5338
+ roomSpace = _useWire.room;
5319
5339
 
5320
- var shouldDrag = pointerType !== "touch" ? stateRef.current.currentButton === 0 && !altKey : !twoFingers;
5340
+ React__default['default'].useEffect(function () {
5341
+ setCurrentUserState(function (prevUser) {
5342
+ return _objectSpread2(_objectSpread2({}, prevUser), {}, {
5343
+ id: wire.userId,
5344
+ space: roomSpace
5345
+ });
5346
+ });
5347
+ return function () {
5348
+ setCurrentUserState(function (prevUser) {
5349
+ return _objectSpread2(_objectSpread2({}, prevUser), {}, {
5350
+ id: wire.userId,
5351
+ space: null
5352
+ });
5353
+ });
5354
+ };
5355
+ }, [wire.userId, roomSpace, setCurrentUserState]);
5356
+ React__default['default'].useEffect(function () {
5357
+ if (!isMaster) {
5358
+ var onGetUserList = function onGetUserList(userList) {
5359
+ usersRef.current = userList;
5360
+ setUsers(userList);
5361
+ };
5321
5362
 
5322
- if (shouldDrag) {
5323
- // Send drag start on first move
5324
- if (!stateRef.current.gestureStart) {
5325
- wrapperRef.current.style.cursor = "move";
5326
- stateRef.current.gestureStart = true; // Clear tap timeout
5363
+ wire.call("getUserList").then(onGetUserList, function () {
5364
+ // retry later
5365
+ setTimeout(function () {
5366
+ wire.call("getUserList") // eslint-disable-next-line no-console
5367
+ .then(onGetUserList, function (error) {
5368
+ return console.log(error);
5369
+ });
5370
+ }, 1000);
5371
+ });
5372
+ }
5373
+ }, [wire, isMaster, setUsers]); // eslint-disable-next-line react-hooks/exhaustive-deps
5327
5374
 
5328
- clearTimeout(stateRef.current.longTapTimeout);
5329
- queue(onDragStart, {
5330
- deltaX: 0,
5331
- deltaY: 0,
5332
- startX: stateRef.current.startX,
5333
- startY: stateRef.current.startY,
5334
- clientX: stateRef.current.startX,
5335
- clientY: stateRef.current.startY,
5336
- distanceX: 0,
5337
- distanceY: 0,
5338
- button: stateRef.current.currentButton,
5339
- altKey: altKey,
5340
- ctrlKey: ctrlKey,
5341
- metaKey: metaKey,
5342
- target: stateRef.current.target,
5343
- event: e
5375
+ var debouncedEmitUpdateUser = useDebouncedCallback(function (newUser) {
5376
+ wire.publish("userUpdate", newUser, true);
5377
+ }, [wire], 500);
5378
+ React__default['default'].useEffect(function () {
5379
+ if (currentUser && currentUser.id) {
5380
+ debouncedEmitUpdateUser(currentUser);
5381
+ }
5382
+ }, [currentUser, debouncedEmitUpdateUser]);
5383
+ React__default['default'].useEffect(function () {
5384
+ var unsub = [];
5385
+
5386
+ if (isMaster) {
5387
+ wire.register("getUserList", function () {
5388
+ return usersRef.current;
5389
+ }).then(function (unregister) {
5390
+ unsub.push(unregister);
5391
+ });
5392
+ unsub.push(wire.subscribe("userUpdate", function (user) {
5393
+ if (usersRef.current.find(function (u) {
5394
+ return u.id === user.id;
5395
+ })) {
5396
+ var newUsers = usersRef.current.map(function (u) {
5397
+ return u.id === user.id ? user : u;
5344
5398
  });
5345
- } // Create closure
5399
+ usersRef.current = newUsers;
5400
+ } else {
5401
+ var _newUsers = [].concat(_toConsumableArray(usersRef.current), [user]);
5346
5402
 
5403
+ usersRef.current = _newUsers;
5404
+ }
5347
5405
 
5348
- var deltaX = clientX - stateRef.current.prevX;
5349
- var deltaY = clientY - stateRef.current.prevY;
5350
- var distanceX = clientX - stateRef.current.startX;
5351
- var distanceY = clientY - stateRef.current.startY; // Drag event
5406
+ setUsers(usersRef.current);
5407
+ wire.publish("updateUserList", usersRef.current);
5408
+ }));
5409
+ }
5352
5410
 
5353
- queue(onDrag, {
5354
- deltaX: deltaX,
5355
- deltaY: deltaY,
5356
- startX: stateRef.current.startX,
5357
- startY: stateRef.current.startY,
5358
- clientX: clientX,
5359
- clientY: clientY,
5360
- distanceX: distanceX,
5361
- distanceY: distanceY,
5362
- button: stateRef.current.currentButton,
5363
- altKey: altKey,
5364
- ctrlKey: ctrlKey,
5365
- metaKey: metaKey,
5366
- target: stateRef.current.target,
5367
- event: e
5368
- });
5369
- } else {
5370
- if (!stateRef.current.gestureStart) {
5371
- wrapperRef.current.style.cursor = "move";
5372
- stateRef.current.gestureStart = true; // Clear tap timeout on first move
5411
+ unsub.push(wire.subscribe("userLeave", function (userId) {
5412
+ usersRef.current = usersRef.current.filter(function (_ref) {
5413
+ var id = _ref.id;
5414
+ return id !== userId;
5415
+ });
5416
+ setUsers(usersRef.current);
5417
+
5418
+ if (isMaster) {
5419
+ wire.publish("updateUserList", usersRef.current);
5420
+ }
5421
+ }));
5422
+ unsub.push(wire.subscribe("updateUserList", function (newList) {
5423
+ usersRef.current = newList;
5424
+ setUsers(usersRef.current);
5425
+ }));
5426
+ return function () {
5427
+ unsub.forEach(function (u) {
5428
+ return u();
5429
+ });
5430
+ };
5431
+ }, [wire, isMaster, setUsers]);
5432
+ return null;
5433
+ };
5434
+
5435
+ var ItemList = function ItemList() {
5436
+ var _useItemActions = useItemActions(),
5437
+ updateItem = _useItemActions.updateItem;
5438
+
5439
+ var itemList = recoil.useRecoilValue(ItemListAtom);
5440
+ var itemMap = recoil.useRecoilValue(ItemMapAtom);
5441
+ var selectedItems = recoil.useRecoilValue(SelectedItemsAtom);
5442
+
5443
+ var _useRecoilValue = recoil.useRecoilValue(ConfigurationAtom),
5444
+ boardSize = _useRecoilValue.boardSize,
5445
+ showResizeHandle = _useRecoilValue.showResizeHandle,
5446
+ itemTemplates = _useRecoilValue.itemTemplates;
5447
+
5448
+ var _useUsers = useUsers(),
5449
+ currentUser = _useUsers.currentUser;
5450
+
5451
+ return itemList.map(function (itemId) {
5452
+ return /*#__PURE__*/React__default['default'].createElement(MemoizedPositionedItem, {
5453
+ key: itemId,
5454
+ state: itemMap[itemId],
5455
+ setState: updateItem,
5456
+ isSelected: selectedItems.includes(itemId),
5457
+ itemMap: itemTemplates,
5458
+ boardSize: boardSize,
5459
+ currentUser: currentUser,
5460
+ showResizeHandle: showResizeHandle
5461
+ });
5462
+ });
5463
+ };
5464
+
5465
+ var SubcribeItemEvents = function SubcribeItemEvents() {
5466
+ var _useWire = useWire("board"),
5467
+ wire = _useWire.wire;
5468
+
5469
+ var setItemMap = recoil.useSetRecoilState(ItemMapAtom);
5470
+
5471
+ var _useItemActions = useItemActions(),
5472
+ updateItemOrder = _useItemActions.updateItemOrder,
5473
+ moveItems = _useItemActions.moveItems,
5474
+ removeItems = _useItemActions.removeItems,
5475
+ pushItem = _useItemActions.pushItem;
5373
5476
 
5374
- clearTimeout(stateRef.current.longTapTimeout);
5375
- } // Create closure
5477
+ var batchUpdate = React__default['default'].useCallback(function (updatedItems) {
5478
+ setItemMap(function (prevItemMap) {
5479
+ return _objectSpread2(_objectSpread2({}, prevItemMap), updatedItems);
5480
+ });
5481
+ }, [setItemMap]);
5482
+ React__default['default'].useEffect(function () {
5483
+ var unsub = wire.subscribe("batchItemsUpdate", function (updatedItems) {
5484
+ batchUpdate(updatedItems);
5485
+ });
5486
+ return unsub;
5487
+ }, [wire, batchUpdate]);
5488
+ React__default['default'].useEffect(function () {
5489
+ var unsub = wire.subscribe("selectedItemsMove", function (_ref) {
5490
+ var itemIds = _ref.itemIds,
5491
+ posDelta = _ref.posDelta;
5492
+ moveItems(itemIds, posDelta, false);
5493
+ });
5494
+ return unsub;
5495
+ }, [wire, moveItems]);
5496
+ React__default['default'].useEffect(function () {
5497
+ var unsub = wire.subscribe("updateItemListOrder", function (itemIds) {
5498
+ updateItemOrder(itemIds, false);
5499
+ });
5500
+ return unsub;
5501
+ }, [wire, updateItemOrder]);
5502
+ React__default['default'].useEffect(function () {
5503
+ var unsub = wire.subscribe("pushItem", function (newItem) {
5504
+ pushItem(newItem, null, false);
5505
+ });
5506
+ return unsub;
5507
+ }, [wire, pushItem]);
5508
+ React__default['default'].useEffect(function () {
5509
+ var unsub = wire.subscribe("insertItemBefore", function (_ref2) {
5510
+ var _ref3 = _slicedToArray(_ref2, 2),
5511
+ newItem = _ref3[0],
5512
+ beforeId = _ref3[1];
5376
5513
 
5514
+ pushItem(newItem, beforeId, false);
5515
+ });
5516
+ return unsub;
5517
+ }, [wire, pushItem]);
5518
+ React__default['default'].useEffect(function () {
5519
+ var unsub = wire.subscribe("removeItems", function (itemIds) {
5520
+ removeItems(itemIds, false);
5521
+ });
5522
+ return unsub;
5523
+ }, [wire, removeItems]);
5524
+ return null;
5525
+ };
5377
5526
 
5378
- var _deltaX = clientX - stateRef.current.prevX;
5527
+ /**
5528
+ * Check if element or parent has className.
5529
+ * @param {DOMElement} element
5530
+ * @param {string} className
5531
+ */
5532
+ var hasClass = function hasClass(element, className) {
5533
+ return element.classList && element.classList.contains(className);
5534
+ };
5535
+ var insideClass = function insideClass(element, className) {
5536
+ if (hasClass(element, className)) {
5537
+ return element;
5538
+ }
5379
5539
 
5380
- var _deltaY = clientY - stateRef.current.prevY;
5540
+ if (!element.parentNode) {
5541
+ return false;
5542
+ }
5381
5543
 
5382
- var target = stateRef.current.target; // Pan event
5544
+ return insideClass(element.parentNode, className);
5545
+ };
5546
+ var isPointInsideRect = function isPointInsideRect(point, rect) {
5547
+ return point.x > rect.left && point.x < rect.left + rect.width && point.y > rect.top && point.y < rect.top + rect.height;
5548
+ };
5549
+ var isItemInsideElement = function isItemInsideElement(itemElement, otherElem) {
5550
+ var rect = otherElem.getBoundingClientRect();
5551
+ var fourElem = Array.from(itemElement.querySelectorAll(".corner"));
5552
+ return fourElem.every(function (corner) {
5553
+ var _corner$getBoundingCl = corner.getBoundingClientRect(),
5554
+ y = _corner$getBoundingCl.top,
5555
+ x = _corner$getBoundingCl.left;
5383
5556
 
5384
- queue(onPan, {
5385
- deltaX: _deltaX,
5386
- deltaY: _deltaY,
5387
- button: stateRef.current.currentButton,
5388
- altKey: altKey,
5389
- ctrlKey: ctrlKey,
5390
- metaKey: metaKey,
5391
- target: target,
5392
- event: e
5393
- });
5557
+ return isPointInsideRect({
5558
+ x: x,
5559
+ y: y
5560
+ }, rect);
5561
+ });
5562
+ };
5563
+ var getItemElem = function getItemElem(wrapper, itemId) {
5564
+ var elems = wrapper.getElementsByClassName("item ".concat(itemId));
5565
+ var elem = elems[0];
5394
5566
 
5395
- if (twoFingers && distance !== stateRef.current.prevDistance && onZoom) {
5396
- var scale = stateRef.current.prevDistance - distance;
5567
+ if (!elem) {
5568
+ // eslint-disable-next-line no-console
5569
+ console.error("Missing item ".concat(itemId));
5570
+ }
5397
5571
 
5398
- if (Math.abs(scale) > 0) {
5399
- queue(onZoom, {
5400
- scale: scale,
5401
- clientX: clientX,
5402
- clientY: clientY,
5403
- event: e
5404
- });
5405
- stateRef.current.prevDistance = distance;
5406
- }
5407
- }
5408
- }
5572
+ return elem;
5573
+ };
5574
+ var getIdFromElem = function getIdFromElem(elem) {
5575
+ var _elem$dataset;
5409
5576
 
5410
- stateRef.current.prevX = clientX;
5411
- stateRef.current.prevY = clientY;
5412
- }
5413
- }, [onDrag, onDragStart, onPan, onZoom, queue]);
5414
- var onPointerUp = React__default['default'].useCallback(function (e) {
5415
- var clientX = e.clientX,
5416
- clientY = e.clientY,
5417
- altKey = e.altKey,
5418
- ctrlKey = e.ctrlKey,
5419
- metaKey = e.metaKey,
5420
- target = e.target,
5421
- pointerId = e.pointerId;
5577
+ var value = elem === null || elem === void 0 ? void 0 : (_elem$dataset = elem.dataset) === null || _elem$dataset === void 0 ? void 0 : _elem$dataset.id;
5422
5578
 
5423
- if (!stateRef.current.pointers[pointerId]) {
5424
- // Pointer already gone previously with another event
5425
- // ignoring it
5426
- return;
5427
- } // Remove pointer from map
5579
+ if (!value) {
5580
+ var _elem$dataset2;
5428
5581
 
5582
+ // eslint-disable-next-line no-console
5583
+ console.error("getIdFromElem call fails", elem, JSON.stringify(elem === null || elem === void 0 ? void 0 : elem.dataset), elem === null || elem === void 0 ? void 0 : (_elem$dataset2 = elem.dataset) === null || _elem$dataset2 === void 0 ? void 0 : _elem$dataset2.id);
5584
+ }
5429
5585
 
5430
- delete stateRef.current.pointers[pointerId];
5586
+ return value;
5587
+ };
5588
+ var getItemBoundingBox = function getItemBoundingBox(items) {
5589
+ var wrapper = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
5590
+ var result = items.reduce(function (prev, itemId) {
5591
+ var elem = getItemElem(wrapper, itemId);
5592
+ if (!elem) return null;
5431
5593
 
5432
- if (stateRef.current.mainPointer !== pointerId) {
5433
- // If this is not the main pointer we quit here
5434
- return;
5435
- }
5594
+ var _elem$getBoundingClie = elem.getBoundingClientRect(),
5595
+ left = _elem$getBoundingClie.left,
5596
+ right = _elem$getBoundingClie.right,
5597
+ top = _elem$getBoundingClie.top,
5598
+ bottom = _elem$getBoundingClie.bottom;
5436
5599
 
5437
- while (Object.keys(stateRef.current.pointers).length > 0) {
5438
- // If was main pointer but we have another one, this one become main
5439
- stateRef.current.mainPointer = Number(Object.keys(stateRef.current.pointers)[0]);
5600
+ var boundingBox;
5440
5601
 
5441
- try {
5442
- stateRef.current.target.setPointerCapture(stateRef.current.mainPointer);
5443
- return;
5444
- } catch (error) {
5445
- // eslint-disable-next-line no-console
5446
- console.log("Fails to set pointer capture", error);
5447
- stateRef.current.mainPointer = undefined;
5448
- delete stateRef.current.pointers[Object.keys(stateRef.current.pointers)[0]];
5449
- }
5602
+ if (!prev) {
5603
+ boundingBox = {
5604
+ left: left,
5605
+ top: top,
5606
+ right: right,
5607
+ bottom: bottom
5608
+ };
5609
+ } else {
5610
+ boundingBox = prev;
5450
5611
  }
5451
5612
 
5452
- stateRef.current.mainPointer = undefined;
5453
- stateRef.current.pressed = false; // Clear longTap
5454
-
5455
- clearTimeout(stateRef.current.longTapTimeout);
5613
+ boundingBox.left = Math.min(left, boundingBox.left);
5614
+ boundingBox.top = Math.min(top, boundingBox.top);
5615
+ boundingBox.right = Math.max(right, boundingBox.right);
5616
+ boundingBox.bottom = Math.max(bottom, boundingBox.bottom);
5617
+ return boundingBox;
5618
+ }, null);
5456
5619
 
5457
- if (stateRef.current.moving) {
5458
- // If we were moving, send drag end event
5459
- stateRef.current.moving = false;
5460
- queue(onDragEnd, {
5461
- deltaX: clientX - stateRef.current.prevX,
5462
- deltaY: clientY - stateRef.current.prevY,
5463
- startX: stateRef.current.startX,
5464
- startY: stateRef.current.startY,
5465
- clientX: clientX,
5466
- clientY: clientY,
5467
- distanceX: clientX - stateRef.current.startX,
5468
- distanceY: clientY - stateRef.current.startY,
5469
- button: stateRef.current.currentButton,
5470
- altKey: altKey,
5471
- ctrlKey: ctrlKey,
5472
- metaKey: metaKey,
5473
- event: e
5474
- });
5475
- wrapperRef.current.style.cursor = "auto";
5476
- } else {
5477
- var now = Date.now();
5620
+ if (!result) {
5621
+ return result;
5622
+ }
5478
5623
 
5479
- if (stateRef.current.noTap) {
5480
- stateRef.current.noTap = false;
5481
- } // Send tap event only if time less than 300ms
5482
- else if (stateRef.current.timeStart - now < 300) {
5483
- queue(onTap, {
5484
- clientX: clientX,
5485
- clientY: clientY,
5486
- altKey: altKey,
5487
- ctrlKey: ctrlKey,
5488
- metaKey: metaKey,
5489
- target: target
5490
- });
5491
- }
5492
- }
5493
- }, [onDragEnd, onTap, queue]);
5494
- var onDoubleTapHandler = React__default['default'].useCallback(function (event) {
5495
- queue(onDoubleTap, event);
5496
- }, [onDoubleTap, queue]);
5497
- return /*#__PURE__*/React__default['default'].createElement("div", {
5498
- onWheel: onWheel,
5499
- onPointerDown: onPointerDown,
5500
- onPointerMove: onPointerMove,
5501
- onPointerUp: onPointerUp,
5502
- onPointerOut: onPointerUp,
5503
- onPointerLeave: onPointerUp,
5504
- onPointerCancel: onPointerUp,
5505
- onDoubleClick: onDoubleTapHandler,
5506
- style: {
5507
- touchAction: "none"
5508
- },
5509
- ref: wrapperRef
5510
- }, children);
5624
+ result.width = result.right - result.left;
5625
+ result.height = result.bottom - result.top;
5626
+ return result;
5511
5627
  };
5512
5628
 
5513
5629
  var defaultSelectorStyle = {
@@ -6974,8 +7090,8 @@ var BoundingBox = function BoundingBox() {
6974
7090
  return /*#__PURE__*/React__default['default'].createElement("div", {
6975
7091
  style: _objectSpread2(_objectSpread2({}, defaultZoneStyle), {}, {
6976
7092
  transform: "translate(".concat(boundingBoxLast.left, "px, ").concat(boundingBoxLast.top, "px)"),
6977
- height: "".concat(boundingBoxLast.height - 2, "px"),
6978
- width: "".concat(boundingBoxLast.width - 2, "px")
7093
+ height: "".concat(boundingBoxLast.height, "px"),
7094
+ width: "".concat(boundingBoxLast.width, "px")
6979
7095
  }),
6980
7096
  className: "selection"
6981
7097
  });
@@ -6999,7 +7115,9 @@ var Board = function Board(_ref) {
6999
7115
  itemTemplates = _ref$itemTemplates === void 0 ? {} : _ref$itemTemplates,
7000
7116
  _ref$boardSize = _ref.boardSize,
7001
7117
  boardSize = _ref$boardSize === void 0 ? DEFAULT_BOARD_MAX_SIZE : _ref$boardSize,
7002
- children = _ref.children;
7118
+ children = _ref.children,
7119
+ _ref$showResizeHandle = _ref.showResizeHandle,
7120
+ showResizeHandle = _ref$showResizeHandle === void 0 ? false : _ref$showResizeHandle;
7003
7121
  var setConfiguration = recoil.useSetRecoilState(ConfigurationAtom);
7004
7122
 
7005
7123
  var _useDim = useDim(),
@@ -7017,10 +7135,11 @@ var Board = function Board(_ref) {
7017
7135
  setConfiguration(function (prev) {
7018
7136
  return _objectSpread2(_objectSpread2({}, prev), {}, {
7019
7137
  itemTemplates: itemTemplates,
7020
- boardSize: boardSize
7138
+ boardSize: boardSize,
7139
+ showResizeHandle: showResizeHandle
7021
7140
  });
7022
7141
  });
7023
- }, [itemTemplates, setConfiguration, boardSize]);
7142
+ }, [itemTemplates, setConfiguration, boardSize, showResizeHandle]);
7024
7143
  React__default['default'].useEffect(function () {
7025
7144
  updateItemExtent();
7026
7145
  setTimeout(updateItemExtent, 2000);
@@ -7035,9 +7154,7 @@ var Board = function Board(_ref) {
7035
7154
  },
7036
7155
  style: boardStyle,
7037
7156
  className: "board"
7038
- }, /*#__PURE__*/React__default['default'].createElement(ItemList, {
7039
- itemTemplates: itemTemplates
7040
- }), children))))), /*#__PURE__*/React__default['default'].createElement(Selection, null));
7157
+ }, /*#__PURE__*/React__default['default'].createElement(ItemList, null), children))))), /*#__PURE__*/React__default['default'].createElement(Selection, null));
7041
7158
  };
7042
7159
 
7043
7160
  var TOLERANCE = 100;