@aics/vole-app 3.4.4 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/es/aics-image-viewer/components/App/index.js +15 -5
  2. package/es/aics-image-viewer/components/ChannelsWidget.js +3 -1
  3. package/es/aics-image-viewer/components/ChannelsWidgetRow.js +29 -16
  4. package/es/aics-image-viewer/components/ColorPicker/index.js +9 -1
  5. package/es/aics-image-viewer/components/ControlPanel/CopySettingsButton.js +445 -0
  6. package/es/aics-image-viewer/components/ControlPanel/index.js +16 -5
  7. package/es/aics-image-viewer/components/ControlPanel/styles.css +29 -2
  8. package/es/aics-image-viewer/components/StyleProvider/index.js +17 -2
  9. package/es/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.js +1 -1
  10. package/es/aics-image-viewer/components/Toolbar/index.js +1 -1
  11. package/es/aics-image-viewer/components/Toolbar/styles.css +0 -10
  12. package/es/aics-image-viewer/components/{CellViewerCanvasWrapper → ViewerCanvasWrapper}/index.js +3 -2
  13. package/es/aics-image-viewer/components/dimension_sliders/AxisClipSliders.js +21 -8
  14. package/es/aics-image-viewer/components/dimension_sliders/RotationSliders.js +6 -8
  15. package/es/aics-image-viewer/components/dimension_sliders/SliderRows.js +8 -6
  16. package/es/aics-image-viewer/components/shared/ContextualAlert.js +101 -0
  17. package/es/aics-image-viewer/components/shared/ControlPanelRow/index.js +4 -2
  18. package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +4 -3
  19. package/es/aics-image-viewer/components/useVolume.js +59 -25
  20. package/es/aics-image-viewer/shared/constants.js +25 -1
  21. package/es/aics-image-viewer/shared/types.js +1 -1
  22. package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +4 -0
  23. package/es/aics-image-viewer/shared/utils/parseSnapshot.js +205 -0
  24. package/es/aics-image-viewer/shared/utils/{urlParsing.js → parseUrl.js} +55 -191
  25. package/es/aics-image-viewer/shared/utils/permissions.js +46 -0
  26. package/es/aics-image-viewer/shared/utils/test/camera.test.js +1 -2
  27. package/es/aics-image-viewer/shared/utils/test/{urlParsing.test.js → parseUrl.test.js} +28 -25
  28. package/es/aics-image-viewer/shared/utils/test/storage.test.js +2 -2
  29. package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +1 -1
  30. package/es/aics-image-viewer/state/deserialize.js +443 -331
  31. package/es/aics-image-viewer/state/reset.js +1 -1
  32. package/es/aics-image-viewer/state/serialize.js +168 -78
  33. package/es/aics-image-viewer/state/subscribers.js +1 -1
  34. package/es/aics-image-viewer/state/test/deserialize.test.js +63 -77
  35. package/es/aics-image-viewer/state/test/reset.test.js +2 -2
  36. package/es/aics-image-viewer/state/test/serialize.test.js +42 -43
  37. package/es/aics-image-viewer/state/test/test_data.js +119 -1
  38. package/es/aics-image-viewer/state/types.js +157 -245
  39. package/es/aics-image-viewer/state/util.js +39 -1
  40. package/es/index.js +4 -2
  41. package/package.json +26 -44
  42. package/type-declarations/aics-image-viewer/components/App/types.d.ts +3 -3
  43. package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +3 -0
  44. package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow.d.ts +3 -0
  45. package/type-declarations/aics-image-viewer/components/ControlPanel/CopySettingsButton.d.ts +11 -0
  46. package/type-declarations/aics-image-viewer/components/Toolbar/ViewModeRadioButtons.d.ts +1 -1
  47. package/type-declarations/aics-image-viewer/components/{CellViewerCanvasWrapper → ViewerCanvasWrapper}/index.d.ts +4 -3
  48. package/type-declarations/aics-image-viewer/components/dimension_sliders/AxisClipSliders.d.ts +7 -6
  49. package/type-declarations/aics-image-viewer/components/dimension_sliders/SliderRows.d.ts +1 -2
  50. package/type-declarations/aics-image-viewer/components/shared/ContextualAlert.d.ts +29 -0
  51. package/type-declarations/aics-image-viewer/components/shared/ControlPanelRow/index.d.ts +1 -0
  52. package/type-declarations/aics-image-viewer/components/useVolume.d.ts +3 -0
  53. package/type-declarations/aics-image-viewer/shared/constants.d.ts +2 -2
  54. package/type-declarations/aics-image-viewer/shared/types.d.ts +2 -2
  55. package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +1 -1
  56. package/type-declarations/aics-image-viewer/shared/utils/parseSnapshot.d.ts +49 -0
  57. package/type-declarations/aics-image-viewer/shared/utils/{urlParsing.d.ts → parseUrl.d.ts} +3 -24
  58. package/type-declarations/aics-image-viewer/shared/utils/permissions.d.ts +7 -0
  59. package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +1 -1
  60. package/type-declarations/aics-image-viewer/state/deserialize.d.ts +70 -35
  61. package/type-declarations/aics-image-viewer/state/reset.d.ts +1 -1
  62. package/type-declarations/aics-image-viewer/state/serialize.d.ts +44 -10
  63. package/type-declarations/aics-image-viewer/state/types.d.ts +265 -159
  64. package/type-declarations/aics-image-viewer/state/util.d.ts +3 -1
  65. package/type-declarations/index.d.ts +5 -3
  66. package/es/Globals.d.js +0 -0
  67. package/es/aics-image-viewer/shared/enums.js +0 -18
  68. package/es/aics-image-viewer/shared/utils/firebase/index.js +0 -109
  69. package/type-declarations/aics-image-viewer/shared/enums.d.ts +0 -15
  70. package/type-declarations/aics-image-viewer/shared/utils/firebase/index.d.ts +0 -69
  71. package/type-declarations/aics-image-viewer/shared/utils/math.d.ts +0 -1
  72. /package/es/aics-image-viewer/components/{CellViewerCanvasWrapper → ViewerCanvasWrapper}/styles.css +0 -0
@@ -29,11 +29,10 @@ function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Can
29
29
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
30
30
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
31
31
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
32
- import { deserializeViewerChannelSetting, deserializeViewerState, parseKeyValueList } from "../../state/deserialize";
33
- import { objectToKeyValueList, serializeViewerChannelSetting, serializeViewerState } from "../../state/serialize";
34
- import { ViewerStateParams } from "../../state/types";
32
+ import { parseKeyValueList, stringSnapshotToViewerChannelSetting, stringSnapshotToViewerState } from "../../state/deserialize";
33
+ import { channelStateToStringSnapshot, objectToKeyValueList, viewerStateToStringSnapshot } from "../../state/serialize";
34
+ import { ViewerStateSnapshotKeys } from "../../state/types";
35
35
  import { removeUndefinedProperties } from "./datatypes";
36
- import FirebaseRequest from "./firebase";
37
36
  import { readStoredMetadata, readStoredScenes } from "./storage";
38
37
  var CHANNEL_STATE_KEY_REGEX = /^c[0-9]+$/;
39
38
 
@@ -65,10 +64,6 @@ var DataParams = /*#__PURE__*/_createClass(function DataParams() {
65
64
  * See `ManifestJson` for the type definition.
66
65
  */
67
66
  _defineProperty(this, "manifest", undefined);
68
- /** The name of a dataset in the Cell Feature Explorer database. Used with `id`. */
69
- _defineProperty(this, "dataset", undefined);
70
- /** The ID of a cell within the loaded dataset. Used with `dataset`. */
71
- _defineProperty(this, "id", undefined);
72
67
  /** The key of a collection of scenes stored in local storage. Overrides `url`. */
73
68
  _defineProperty(this, "collectionid", undefined);
74
69
  /**
@@ -93,11 +88,7 @@ var DeprecatedParams = /*#__PURE__*/_createClass(function DeprecatedParams() {
93
88
  /** Deprecated query parameter for channel colors. */
94
89
  _defineProperty(this, "colors", undefined);
95
90
  });
96
- /**
97
- * A message sent from an external application after this app was opened,
98
- * containing data that was too large to pack into the URL.
99
- */
100
- var allowedParamKeys = [].concat(_toConsumableArray(Object.keys(new ViewerStateParams())), _toConsumableArray(Object.keys(new DataParams())), _toConsumableArray(Object.keys(new DeprecatedParams())));
91
+ var allowedParamKeys = [].concat(_toConsumableArray(Object.values(ViewerStateSnapshotKeys)), _toConsumableArray(Object.keys(new DataParams())), _toConsumableArray(Object.keys(new DeprecatedParams())));
101
92
  var isParamKey = function isParamKey(key) {
102
93
  return allowedParamKeys.indexOf(key) !== -1;
103
94
  };
@@ -248,7 +239,7 @@ function parseChannelSettings(params) {
248
239
  var channelIndex = Number.parseInt(key.slice(1), 10);
249
240
  try {
250
241
  var channelData = parseKeyValueList(params[key]);
251
- var channelSetting = deserializeViewerChannelSetting(channelIndex, channelData);
242
+ var channelSetting = stringSnapshotToViewerChannelSetting(channelIndex, channelData);
252
243
  channelIndexToSettings.set(channelIndex, channelSetting);
253
244
  } catch (e) {
254
245
  console.warn("url_utils.getArgsFromParams: Failed to parse channel settings for channel ".concat(channelIndex, " from URL parameters."), e);
@@ -268,86 +259,7 @@ function parseChannelSettings(params) {
268
259
  }
269
260
 
270
261
  //// FULL URL PARSING //////////////////////
271
- function loadDataset(_x, _x2, _x3) {
272
- return _loadDataset.apply(this, arguments);
273
- }
274
- function _loadDataset() {
275
- _loadDataset = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(firestore, dataset, id) {
276
- var db, args, datasets, datasetMeta, _iterator2, _step2, d, innerDatasets, names, matchingName, datasetData, baseUrl, fileInfo;
277
- return _regeneratorRuntime().wrap(function _callee$(_context) {
278
- while (1) switch (_context.prev = _context.next) {
279
- case 0:
280
- db = new FirebaseRequest(firestore);
281
- args = {};
282
- _context.next = 4;
283
- return db.getAvailableDatasets();
284
- case 4:
285
- datasets = _context.sent;
286
- datasetMeta = undefined;
287
- _iterator2 = _createForOfIteratorHelper(datasets);
288
- _context.prev = 7;
289
- _iterator2.s();
290
- case 9:
291
- if ((_step2 = _iterator2.n()).done) {
292
- _context.next = 19;
293
- break;
294
- }
295
- d = _step2.value;
296
- innerDatasets = d.datasets;
297
- names = Object.keys(innerDatasets);
298
- matchingName = names.find(function (name) {
299
- return name === dataset;
300
- });
301
- if (!matchingName) {
302
- _context.next = 17;
303
- break;
304
- }
305
- datasetMeta = innerDatasets[matchingName];
306
- return _context.abrupt("break", 19);
307
- case 17:
308
- _context.next = 9;
309
- break;
310
- case 19:
311
- _context.next = 24;
312
- break;
313
- case 21:
314
- _context.prev = 21;
315
- _context.t0 = _context["catch"](7);
316
- _iterator2.e(_context.t0);
317
- case 24:
318
- _context.prev = 24;
319
- _iterator2.f();
320
- return _context.finish(24);
321
- case 27:
322
- if (!(datasetMeta === undefined)) {
323
- _context.next = 30;
324
- break;
325
- }
326
- console.error("No matching dataset: ".concat(dataset));
327
- return _context.abrupt("return", {});
328
- case 30:
329
- _context.next = 32;
330
- return db.selectDataset(datasetMeta.manifest);
331
- case 32:
332
- datasetData = _context.sent;
333
- baseUrl = datasetData.volumeViewerDataRoot + "/";
334
- args.imageDownloadHref = datasetData.downloadRoot + "/" + id;
335
- // args.fovDownloadHref = datasetData.downloadRoot + "/" + id;
336
- _context.next = 37;
337
- return db.getFileInfoByCellId(id);
338
- case 37:
339
- fileInfo = _context.sent;
340
- args.imageUrl = baseUrl + fileInfo.volumeviewerPath;
341
- args.parentImageUrl = baseUrl + fileInfo.fovVolumeviewerPath;
342
- return _context.abrupt("return", args);
343
- case 41:
344
- case "end":
345
- return _context.stop();
346
- }
347
- }, _callee, null, [[7, 21, 24, 27]]);
348
- }));
349
- return _loadDataset.apply(this, arguments);
350
- }
262
+
351
263
  function isStringArray(arr) {
352
264
  return Array.isArray(arr) && arr.every(function (item) {
353
265
  return typeof item === "string";
@@ -358,15 +270,13 @@ function isValidScenesArray(arr) {
358
270
  return typeof item === "string" || isStringArray(item);
359
271
  });
360
272
  }
361
- export function loadFromManifest(_x4) {
273
+ export function loadFromManifest(_x) {
362
274
  return _loadFromManifest.apply(this, arguments);
363
275
  }
364
276
 
365
277
  /**
366
278
  * Parses a set of URL search parameters into props for the viewer.
367
279
  * @param search The query string to parse, which must be valid in the `URLSearchParams constructor
368
- * @param firestore Optional Firestore instance. If provided, the function can load data from a
369
- * Firestore dataset if the `dataset` and `id` parameters are provided.
370
280
  * @returns An object containing:
371
281
  * - `args`: Partial AppProps object.
372
282
  * - `viewerSettings`: Partial ViewerState object.
@@ -374,46 +284,46 @@ export function loadFromManifest(_x4) {
374
284
  * `args` can be passed as props to the `ImageViewerApp`, and `viewerSettings` can be passed to `ViewerStateProvider`.
375
285
  */
376
286
  function _loadFromManifest() {
377
- _loadFromManifest = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(manifestUrl) {
287
+ _loadFromManifest = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(manifestUrl) {
378
288
  var response, manifestJson, scenes, metadata;
379
- return _regeneratorRuntime().wrap(function _callee2$(_context2) {
380
- while (1) switch (_context2.prev = _context2.next) {
289
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
290
+ while (1) switch (_context.prev = _context.next) {
381
291
  case 0:
382
- _context2.prev = 0;
383
- _context2.next = 3;
292
+ _context.prev = 0;
293
+ _context.next = 3;
384
294
  return fetch(manifestUrl);
385
295
  case 3:
386
- response = _context2.sent;
387
- _context2.next = 10;
296
+ response = _context.sent;
297
+ _context.next = 10;
388
298
  break;
389
299
  case 6:
390
- _context2.prev = 6;
391
- _context2.t0 = _context2["catch"](0);
392
- console.error(_context2.t0);
393
- throw new Error("JSON manifest could not be fetched from URL '".concat(manifestUrl, "': ").concat(_context2.t0));
300
+ _context.prev = 6;
301
+ _context.t0 = _context["catch"](0);
302
+ console.error(_context.t0);
303
+ throw new Error("JSON manifest could not be fetched from URL '".concat(manifestUrl, "': ").concat(_context.t0));
394
304
  case 10:
395
305
  if (response.ok) {
396
- _context2.next = 12;
306
+ _context.next = 12;
397
307
  break;
398
308
  }
399
309
  throw new Error("JSON manifest could not be fetched from URL '".concat(manifestUrl, "': Received ").concat(response.status, " ").concat(response.statusText));
400
310
  case 12:
401
- _context2.prev = 12;
402
- _context2.next = 15;
311
+ _context.prev = 12;
312
+ _context.next = 15;
403
313
  return response.json();
404
314
  case 15:
405
- manifestJson = _context2.sent;
406
- _context2.next = 21;
315
+ manifestJson = _context.sent;
316
+ _context.next = 21;
407
317
  break;
408
318
  case 18:
409
- _context2.prev = 18;
410
- _context2.t1 = _context2["catch"](12);
411
- throw new Error("Could not parse JSON manifest from URL '".concat(manifestUrl, "': ").concat(_context2.t1));
319
+ _context.prev = 18;
320
+ _context.t1 = _context["catch"](12);
321
+ throw new Error("Could not parse JSON manifest from URL '".concat(manifestUrl, "': ").concat(_context.t1));
412
322
  case 21:
413
323
  // Parse scenes
414
324
  scenes = manifestJson.scenes;
415
325
  if (!(scenes === undefined)) {
416
- _context2.next = 24;
326
+ _context.next = 24;
417
327
  break;
418
328
  }
419
329
  throw new Error("No 'scenes' property was found in JSON manifest from URL '".concat(manifestUrl, "'"));
@@ -422,7 +332,7 @@ function _loadFromManifest() {
422
332
  scenes = [scenes];
423
333
  }
424
334
  if (!(!Array.isArray(scenes) || scenes.length === 0 || !isValidScenesArray(scenes))) {
425
- _context2.next = 27;
335
+ _context.next = 27;
426
336
  break;
427
337
  }
428
338
  throw new Error("Invalid 'scenes' property found in JSON manifest from URL '".concat(manifestUrl, "'. 'scenes' must be a non-empty array of strings or string arrays."));
@@ -432,33 +342,38 @@ function _loadFromManifest() {
432
342
  if (manifestJson.meta !== undefined && Array.isArray(manifestJson.meta)) {
433
343
  metadata = manifestJson.meta;
434
344
  }
435
- return _context2.abrupt("return", {
345
+ return _context.abrupt("return", {
436
346
  scenes: scenes,
437
347
  metadata: metadata
438
348
  });
439
349
  case 30:
440
350
  case "end":
441
- return _context2.stop();
351
+ return _context.stop();
442
352
  }
443
- }, _callee2, null, [[0, 6], [12, 18]]);
353
+ }, _callee, null, [[0, 6], [12, 18]]);
444
354
  }));
445
355
  return _loadFromManifest.apply(this, arguments);
446
356
  }
447
- export function parseViewerUrlParams(_x5, _x6) {
357
+ export function parseViewerUrlParams(_x2) {
448
358
  return _parseViewerUrlParams.apply(this, arguments);
449
359
  }
450
360
 
451
- /** Adds the data in a newly-arrived `ViewerMessage` to an existing stored `AppProps` instance. */
361
+ /**
362
+ * Serializes the ViewerState and ChannelState of a ViewerStateContext into a URLSearchParams object.
363
+ * @param state ViewerStateContext to serialize.
364
+ * @param removeDefaults If true, shortens parameters by removing any properties that match the default state.
365
+ * This includes the output of GET_DEFAULT_VIEWER_STATE and GET_DEFAULT_CHANNEL_STATE.
366
+ */
452
367
  function _parseViewerUrlParams() {
453
- _parseViewerUrlParams = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(search, firestore) {
454
- var searchParams, params, args, viewerSettings, deprecatedChannelSettings, channelSettings, scenes, _yield$loadFromManife, manifestScenes, manifestMetadata, collectionid, msgorigin, getFromStorage, urlParamFromStorage, urlParam, firstScene, firstUrl, imageUrls, datasetArgs;
455
- return _regeneratorRuntime().wrap(function _callee3$(_context3) {
456
- while (1) switch (_context3.prev = _context3.next) {
368
+ _parseViewerUrlParams = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(search) {
369
+ var searchParams, params, args, viewerSettings, deprecatedChannelSettings, channelSettings, scenes, _yield$loadFromManife, manifestScenes, manifestMetadata, collectionid, msgorigin, getFromStorage, urlParamFromStorage, urlParam, firstScene, firstUrl, imageUrls;
370
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
371
+ while (1) switch (_context2.prev = _context2.next) {
457
372
  case 0:
458
373
  searchParams = new URLSearchParams(search);
459
374
  params = getAllowedParams(searchParams);
460
375
  args = {}; // Parse viewer state
461
- viewerSettings = deserializeViewerState(params); // Parse channel settings. If per-channel settings are provided, they will override
376
+ viewerSettings = stringSnapshotToViewerState(params); // Parse channel settings. If per-channel settings are provided, they will override
462
377
  // the old `ch` query parameter.
463
378
  deprecatedChannelSettings = parseDeprecatedChannelSettings(params);
464
379
  channelSettings = parseChannelSettings(params);
@@ -466,22 +381,22 @@ function _parseViewerUrlParams() {
466
381
 
467
382
  // Parse data sources (URL or dataset/id pair)
468
383
  if (!(params.manifest !== undefined || params.url !== undefined || params.collectionid !== undefined)) {
469
- _context3.next = 35;
384
+ _context2.next = 33;
470
385
  break;
471
386
  }
472
387
  if (!params.manifest) {
473
- _context3.next = 18;
388
+ _context2.next = 18;
474
389
  break;
475
390
  }
476
- _context3.next = 11;
391
+ _context2.next = 11;
477
392
  return loadFromManifest(params.manifest);
478
393
  case 11:
479
- _yield$loadFromManife = _context3.sent;
394
+ _yield$loadFromManife = _context2.sent;
480
395
  manifestScenes = _yield$loadFromManife.scenes;
481
396
  manifestMetadata = _yield$loadFromManife.metadata;
482
397
  scenes = manifestScenes;
483
398
  args.metadata = manifestMetadata !== null && manifestMetadata !== void 0 ? manifestMetadata : undefined;
484
- _context3.next = 24;
399
+ _context2.next = 24;
485
400
  break;
486
401
  case 18:
487
402
  // Load from URL or storage
@@ -522,76 +437,25 @@ function _parseViewerUrlParams() {
522
437
  }]
523
438
  };
524
439
  }
525
- _context3.next = 40;
526
- break;
527
- case 35:
528
- if (!(params.dataset && params.id && firestore)) {
529
- _context3.next = 40;
530
- break;
531
- }
532
- _context3.next = 38;
533
- return loadDataset(firestore, params.dataset, params.id);
534
- case 38:
535
- datasetArgs = _context3.sent;
536
- args = _objectSpread(_objectSpread({}, args), datasetArgs);
537
- case 40:
538
- return _context3.abrupt("return", {
440
+ case 33:
441
+ return _context2.abrupt("return", {
539
442
  args: removeUndefinedProperties(args),
540
443
  viewerSettings: removeUndefinedProperties(viewerSettings)
541
444
  });
542
- case 41:
445
+ case 34:
543
446
  case "end":
544
- return _context3.stop();
447
+ return _context2.stop();
545
448
  }
546
- }, _callee3);
449
+ }, _callee2);
547
450
  }));
548
451
  return _parseViewerUrlParams.apply(this, arguments);
549
452
  }
550
- export function addViewerParamsFromMessage(args, message) {
551
- var _message$scenes;
552
- // get scenes
553
- var imageUrl = args.imageUrl;
554
- var scenes = (_message$scenes = message.scenes) !== null && _message$scenes !== void 0 ? _message$scenes : typeof imageUrl === "string" ? [imageUrl] : imageUrl.scenes;
555
- var firstScene = scenes[0];
556
- var newImageUrl = scenes.length === 1 && typeof firstScene === "string" ? firstScene : {
557
- scenes: scenes
558
- };
559
-
560
- // get metadata
561
- var meta = message.meta;
562
- var messageMeta = meta && scenes.map(function (scene) {
563
- if (Array.isArray(scene)) {
564
- // can't handle multi-source scenes (yet)
565
- return undefined;
566
- }
567
- return meta[scene];
568
- });
569
- var newMetadata = messageMeta !== null && messageMeta !== void 0 ? messageMeta : args.metadata;
570
- if (newMetadata === undefined) {
571
- return _objectSpread(_objectSpread({}, args), {}, {
572
- imageUrl: newImageUrl
573
- });
574
- } else {
575
- return _objectSpread(_objectSpread({}, args), {}, {
576
- imageUrl: newImageUrl,
577
- metadata: newMetadata
578
- });
579
- }
580
- }
581
-
582
- /**
583
- * Serializes the ViewerState and ChannelState of a ViewerStateContext into a URLSearchParams object.
584
- * @param state ViewerStateContext to serialize.
585
- * @param removeDefaults If true, shortens parameters by removing any properties that match the default state.
586
- * This includes the output of GET_DEFAULT_VIEWER_STATE and GET_DEFAULT_CHANNEL_STATE.
587
- */
588
453
  export function serializeViewerUrlParams(state) {
589
454
  var _state$channelSetting;
590
455
  var removeDefaults = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
591
- var params = serializeViewerState(state, removeDefaults);
456
+ var params = viewerStateToStringSnapshot(state, removeDefaults);
592
457
  var channelParams = (_state$channelSetting = state.channelSettings) === null || _state$channelSetting === void 0 ? void 0 : _state$channelSetting.reduce(function (acc, channelSetting, index) {
593
- var key = "c".concat(index);
594
- acc[key] = objectToKeyValueList(serializeViewerChannelSetting(channelSetting, removeDefaults));
458
+ acc["c".concat(index)] = objectToKeyValueList(channelStateToStringSnapshot(channelSetting, removeDefaults));
595
459
  return acc;
596
460
  }, {});
597
461
  return _objectSpread(_objectSpread({}, params), channelParams);
@@ -0,0 +1,46 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _regeneratorRuntime() { "use strict"; var r = _regenerator(), e = r.m(_regeneratorRuntime), t = (Object.getPrototypeOf ? Object.getPrototypeOf(e) : e.__proto__).constructor; function n(r) { var e = "function" == typeof r && r.constructor; return !!e && (e === t || "GeneratorFunction" === (e.displayName || e.name)); } var o = { "throw": 1, "return": 2, "break": 3, "continue": 3 }; function a(r) { var e, t; return function (n) { e || (e = { stop: function stop() { return t(n.a, 2); }, "catch": function _catch() { return n.v; }, abrupt: function abrupt(r, e) { return t(n.a, o[r], e); }, delegateYield: function delegateYield(r, o, a) { return e.resultName = o, t(n.d, _regeneratorValues(r), a); }, finish: function finish(r) { return t(n.f, r); } }, t = function t(r, _t, o) { n.p = e.prev, n.n = e.next; try { return r(_t, o); } finally { e.next = n.n; } }), e.resultName && (e[e.resultName] = n.v, e.resultName = void 0), e.sent = n.v, e.next = n.n; try { return r.call(this, e); } finally { n.p = e.prev, n.n = e.next; } }; } return (_regeneratorRuntime = function _regeneratorRuntime() { return { wrap: function wrap(e, t, n, o) { return r.w(a(e), t, n, o && o.reverse()); }, isGeneratorFunction: n, mark: r.m, awrap: function awrap(r, e) { return new _OverloadYield(r, e); }, AsyncIterator: _regeneratorAsyncIterator, async: function async(r, e, t, o, u) { return (n(e) ? _regeneratorAsyncGen : _regeneratorAsync)(a(r), e, t, o, u); }, keys: _regeneratorKeys, values: _regeneratorValues }; })(); }
3
+ function _regeneratorValues(e) { if (null != e) { var t = e["function" == typeof Symbol && Symbol.iterator || "@@iterator"], r = 0; if (t) return t.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) return { next: function next() { return e && r >= e.length && (e = void 0), { value: e && e[r++], done: !e }; } }; } throw new TypeError(_typeof(e) + " is not iterable"); }
4
+ function _regeneratorKeys(e) { var n = Object(e), r = []; for (var t in n) r.unshift(t); return function e() { for (; r.length;) if ((t = r.pop()) in n) return e.value = t, e.done = !1, e; return e.done = !0, e; }; }
5
+ function _regeneratorAsync(n, e, r, t, o) { var a = _regeneratorAsyncGen(n, e, r, t, o); return a.next().then(function (n) { return n.done ? n.value : a.next(); }); }
6
+ function _regeneratorAsyncGen(r, e, t, o, n) { return new _regeneratorAsyncIterator(_regenerator().w(r, e, t, o), n || Promise); }
7
+ function _regeneratorAsyncIterator(t, e) { function n(r, o, i, f) { try { var c = t[r](o), u = c.value; return u instanceof _OverloadYield ? e.resolve(u.v).then(function (t) { n("next", t, i, f); }, function (t) { n("throw", t, i, f); }) : e.resolve(u).then(function (t) { c.value = t, i(c); }, function (t) { return n("throw", t, i, f); }); } catch (t) { f(t); } } var r; this.next || (_regeneratorDefine2(_regeneratorAsyncIterator.prototype), _regeneratorDefine2(_regeneratorAsyncIterator.prototype, "function" == typeof Symbol && Symbol.asyncIterator || "@asyncIterator", function () { return this; })), _regeneratorDefine2(this, "_invoke", function (t, o, i) { function f() { return new e(function (e, r) { n(t, i, e, r); }); } return r = r ? r.then(f, f) : f(); }, !0); }
8
+ function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
9
+ function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
10
+ function _OverloadYield(e, d) { this.v = e, this.k = d; }
11
+ function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
12
+ function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
13
+ /**
14
+ * Try to determine whether attempting to access the clipboard will immediately fail.
15
+ *
16
+ * When this function returns `false`, accessing the clipboard *may* be successful, though some browsers require users
17
+ * to confirm every paste. When it returns `true`, access to the clipboard is definitely blocked.
18
+ */
19
+ export var queryPasteDenied = /*#__PURE__*/function () {
20
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
21
+ var permission;
22
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
23
+ while (1) switch (_context.prev = _context.next) {
24
+ case 0:
25
+ _context.prev = 0;
26
+ _context.next = 3;
27
+ return navigator.permissions.query({
28
+ name: "clipboard-read"
29
+ });
30
+ case 3:
31
+ permission = _context.sent;
32
+ return _context.abrupt("return", permission.state === "denied");
33
+ case 7:
34
+ _context.prev = 7;
35
+ _context.t0 = _context["catch"](0);
36
+ return _context.abrupt("return", false);
37
+ case 10:
38
+ case "end":
39
+ return _context.stop();
40
+ }
41
+ }, _callee, null, [[0, 7]]);
42
+ }));
43
+ return function queryPasteDenied() {
44
+ return _ref.apply(this, arguments);
45
+ };
46
+ }();
@@ -4,11 +4,10 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
4
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
5
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
6
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
- import { describe, expect, it } from "@jest/globals";
8
7
  import { mat3 } from "gl-matrix";
8
+ import { describe, expect, it } from "vitest";
9
9
  import { applyMatrix, defaultOrientedCamera, getRotationAngles, rotationMatrix } from "../camera";
10
10
  var expectCameraStateToBe = function expectCameraStateToBe(actual, expected, precision) {
11
- console.log(actual.up, expected.up);
12
11
  var _actual$position = _slicedToArray(actual.position, 3),
13
12
  apx = _actual$position[0],
14
13
  apy = _actual$position[1],
@@ -22,12 +22,12 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
22
22
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
23
23
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
24
24
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
25
- import { describe, expect, it } from "@jest/globals";
25
+ import { describe, expect, it } from "vitest";
26
26
  import { parseKeyValueList } from "../../../state/deserialize";
27
27
  import { DEFAULT_TEST_VIEWER_CHANNEL_SETTING } from "../../../state/test/test_data";
28
+ import { ViewMode } from "../../../state/types";
28
29
  import { getDefaultChannelState, getDefaultViewerState } from "../../constants";
29
- import { ViewMode } from "../../enums";
30
- import { parseViewerUrlParams, serializeViewerUrlParams } from "../urlParsing";
30
+ import { parseViewerUrlParams, serializeViewerUrlParams } from "../parseUrl";
31
31
  //// URL parsing /////////////////////////////////
32
32
 
33
33
  describe("parseViewerUrlParams", function () {
@@ -399,46 +399,46 @@ describe("parseViewerUrlParams", function () {
399
399
  }
400
400
  }, _callee9, null, [[4, 17, 20, 23]]);
401
401
  })));
402
- it("parses viewer settings", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee10() {
403
- var queryString, _yield$parseViewerUrl10, viewerSettings;
404
- return _regeneratorRuntime().wrap(function _callee10$(_context10) {
405
- while (1) switch (_context10.prev = _context10.next) {
402
+ it("parses viewer settings", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee0() {
403
+ var queryString, _yield$parseViewerUrl0, viewerSettings;
404
+ return _regeneratorRuntime().wrap(function _callee0$(_context0) {
405
+ while (1) switch (_context0.prev = _context0.next) {
406
406
  case 0:
407
407
  queryString = "mask=30&view=X";
408
- _context10.next = 3;
408
+ _context0.next = 3;
409
409
  return parseViewerUrlParams(queryString);
410
410
  case 3:
411
- _yield$parseViewerUrl10 = _context10.sent;
412
- viewerSettings = _yield$parseViewerUrl10.viewerSettings;
411
+ _yield$parseViewerUrl0 = _context0.sent;
412
+ viewerSettings = _yield$parseViewerUrl0.viewerSettings;
413
413
  expect(viewerSettings.viewMode).toEqual(ViewMode.yz);
414
414
  expect(viewerSettings.maskAlpha).toEqual(30);
415
415
  case 7:
416
416
  case "end":
417
- return _context10.stop();
417
+ return _context0.stop();
418
418
  }
419
- }, _callee10);
419
+ }, _callee0);
420
420
  })));
421
- it("returns an empty object when no params are passed in", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee11() {
422
- var queryString, _yield$parseViewerUrl11, args, viewerSettings;
423
- return _regeneratorRuntime().wrap(function _callee11$(_context11) {
424
- while (1) switch (_context11.prev = _context11.next) {
421
+ it("returns an empty object when no params are passed in", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee1() {
422
+ var queryString, _yield$parseViewerUrl1, args, viewerSettings;
423
+ return _regeneratorRuntime().wrap(function _callee1$(_context1) {
424
+ while (1) switch (_context1.prev = _context1.next) {
425
425
  case 0:
426
426
  queryString = "";
427
- _context11.next = 3;
427
+ _context1.next = 3;
428
428
  return parseViewerUrlParams(queryString);
429
429
  case 3:
430
- _yield$parseViewerUrl11 = _context11.sent;
431
- args = _yield$parseViewerUrl11.args;
432
- viewerSettings = _yield$parseViewerUrl11.viewerSettings;
430
+ _yield$parseViewerUrl1 = _context1.sent;
431
+ args = _yield$parseViewerUrl1.args;
432
+ viewerSettings = _yield$parseViewerUrl1.viewerSettings;
433
433
  expect(Object.keys(args).length === 0);
434
434
  expect(args).toEqual({});
435
435
  expect(Object.keys(viewerSettings).length === 0);
436
436
  expect(viewerSettings).toEqual({});
437
437
  case 10:
438
438
  case "end":
439
- return _context11.stop();
439
+ return _context1.stop();
440
440
  }
441
- }, _callee11);
441
+ }, _callee1);
442
442
  })));
443
443
  });
444
444
  describe("serializeViewerUrlParams", function () {
@@ -556,9 +556,12 @@ describe("serializeViewerUrlParams", function () {
556
556
  };
557
557
  var serializedParams = serializeViewerUrlParams(_objectSpread(_objectSpread({}, defaultViewerSettings), customViewerState), true);
558
558
  var urlParams = new URLSearchParams(serializedParams);
559
- // Pos is 1.2:3.4:5.6 but escaped
560
- var expectedCameraPosition = encodeURIComponent("pos:1.2:3.4:5.6");
561
- expect(urlParams.toString()).toEqual("dens=100&t=40&cam=".concat(expectedCameraPosition, "&view=Z"));
559
+ expect(Object.fromEntries(urlParams.entries())).toEqual({
560
+ view: "Z",
561
+ dens: "100",
562
+ t: "40",
563
+ cam: "pos:1.2:3.4:5.6"
564
+ });
562
565
  });
563
566
  it("can remove channel state fields that matches the default", function () {
564
567
  // Note that this unit test will break if the
@@ -1,6 +1,6 @@
1
- import { describe, expect, it } from "@jest/globals";
1
+ import { describe, expect, it } from "vitest";
2
2
  import { readStoredMetadata, readStoredScenes, writeMetadata, writeScenes } from "../storage";
3
- var LONG_STRING = "This is a very long string, long enough that it dwarfs the size of other example data used in this test. Its purpose is to test how the functions in the \"storage\" module evict data from local storage when the quota for local storage size is exceeded. The local storage quota is set to five thousand in this test environment, which is much smaller than most browsers will provide. At one thousand two hundred and thirty-four characters, this string represents a little less than a quarter of the total size of local storage in this test environment. Therefore, the tests below can reliably predict that up to three objects containing this string in one of its properties will fit in local storage, and that inserting a fourth one will trigger an eviction. They can also predict that a single object containing four or more copies of this string will not be allowed in local storage at all. This is slightly imprecise because adding items to local storage using the functions tested in this module incurs some additional storage penalties for the storage key, the stringified JSON surrounding the value, and the key and value of the least-recently-used queue. The size of local storage in this test environment is set in jest.config.js.";
3
+ var LONG_STRING = "This is a very long string, long enough that it dwarfs the size of other example data used in this test. Its purpose is to test how the functions in the \"storage\" module evict data from local storage when the quota for local storage size is exceeded. The local storage quota is set to five thousand in this test environment, which is much smaller than most browsers will provide. At one thousand two hundred and thirty-four characters, this string represents a little less than a quarter of the total size of local storage in this test environment. Therefore, the tests below can reliably predict that up to three objects containing this string in one of its properties will fit in local storage, and that inserting a fourth one will trigger an eviction. They can also predict that a single object containing four or more copies of this string will not be allowed in local storage at all. This is slightly imprecise because adding items to local storage using the functions tested in this module incurs some additional storage penalties for the storage key, the stringified JSON surrounding the value, and the key and value of the least-recently-used queue. The size of local storage in this test environment is set in vitest.config.ts.";
4
4
  var LARGE_ENTRY = {
5
5
  data: LONG_STRING
6
6
  };
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "@jest/globals";
1
+ import { describe, expect, it } from "vitest";
2
2
  import { makeChannelIndexGrouping, matchChannel } from "../viewerChannelSettings";
3
3
  describe("viewer settings", function () {
4
4
  describe("matching names", function () {