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