@aics/vole-app 3.3.0 → 3.4.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 (60) hide show
  1. package/LICENSE +21 -25
  2. package/es/aics-image-viewer/components/App/index.js +11 -9
  3. package/es/aics-image-viewer/components/BottomPanel/index.js +48 -19
  4. package/es/aics-image-viewer/components/BottomPanel/styles.css +16 -7
  5. package/es/aics-image-viewer/components/CellViewerCanvasWrapper/index.js +39 -19
  6. package/es/aics-image-viewer/components/ChannelsWidget.js +2 -2
  7. package/es/aics-image-viewer/components/ControlPanel/index.js +17 -11
  8. package/es/aics-image-viewer/components/ControlPanel/styles.css +5 -5
  9. package/es/aics-image-viewer/components/ErrorAlert/index.js +91 -64
  10. package/es/aics-image-viewer/components/ErrorAlert/styles.css +33 -4
  11. package/es/aics-image-viewer/components/StyleProvider/index.js +42 -22
  12. package/es/aics-image-viewer/components/TfEditor/index.js +8 -1
  13. package/es/aics-image-viewer/components/Toolbar/index.js +33 -12
  14. package/es/aics-image-viewer/components/Toolbar/styles.css +21 -130
  15. package/es/aics-image-viewer/components/dimension_sliders/AxisClipSliders.js +148 -0
  16. package/es/aics-image-viewer/components/dimension_sliders/RotationSliders.js +165 -0
  17. package/es/aics-image-viewer/components/dimension_sliders/SliderRows.js +167 -0
  18. package/es/aics-image-viewer/components/{AxisClipSliders → dimension_sliders}/styles.css +7 -1
  19. package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +1 -1
  20. package/es/aics-image-viewer/components/shared/NumericInput/index.js +4 -2
  21. package/es/aics-image-viewer/components/shared/SliderRow/index.js +2 -0
  22. package/es/aics-image-viewer/components/shared/SliderRow/styles.css +2 -1
  23. package/es/aics-image-viewer/components/useVolume.js +3 -0
  24. package/es/aics-image-viewer/shared/constants.js +2 -2
  25. package/es/aics-image-viewer/shared/utils/camera.js +122 -0
  26. package/es/aics-image-viewer/shared/utils/playControls.js +12 -1
  27. package/es/aics-image-viewer/shared/utils/sceneStore.js +8 -0
  28. package/es/aics-image-viewer/shared/utils/test/camera.test.js +127 -0
  29. package/es/aics-image-viewer/shared/utils/test/urlParsing.test.js +23 -702
  30. package/es/aics-image-viewer/shared/utils/urlParsing.js +14 -828
  31. package/es/aics-image-viewer/shared/utils/viewerChannelSettings.js +3 -4
  32. package/es/aics-image-viewer/state/deserialize.js +437 -0
  33. package/es/aics-image-viewer/state/serialize.js +145 -0
  34. package/es/aics-image-viewer/state/test/deserialize.test.js +432 -0
  35. package/es/aics-image-viewer/state/test/serialize.test.js +97 -0
  36. package/es/aics-image-viewer/state/test/test_data.js +168 -0
  37. package/es/aics-image-viewer/state/types.js +265 -1
  38. package/package.json +6 -5
  39. package/type-declarations/aics-image-viewer/components/App/types.d.ts +2 -2
  40. package/type-declarations/aics-image-viewer/components/BottomPanel/index.d.ts +6 -3
  41. package/type-declarations/aics-image-viewer/components/CellViewerCanvasWrapper/index.d.ts +1 -0
  42. package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +4 -5
  43. package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +8 -5
  44. package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +2 -1
  45. package/type-declarations/aics-image-viewer/components/{AxisClipSliders/index.d.ts → dimension_sliders/AxisClipSliders.d.ts} +2 -3
  46. package/type-declarations/aics-image-viewer/components/dimension_sliders/RotationSliders.d.ts +6 -0
  47. package/type-declarations/aics-image-viewer/components/dimension_sliders/SliderRows.d.ts +31 -0
  48. package/type-declarations/aics-image-viewer/components/shared/NumericInput/index.d.ts +1 -0
  49. package/type-declarations/aics-image-viewer/components/shared/SliderRow/index.d.ts +3 -1
  50. package/type-declarations/aics-image-viewer/components/useVolume.d.ts +1 -1
  51. package/type-declarations/aics-image-viewer/shared/constants.d.ts +1 -1
  52. package/type-declarations/aics-image-viewer/shared/utils/camera.d.ts +19 -0
  53. package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +1 -0
  54. package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +2 -1
  55. package/type-declarations/aics-image-viewer/shared/utils/urlParsing.d.ts +1 -307
  56. package/type-declarations/aics-image-viewer/state/deserialize.d.ts +70 -0
  57. package/type-declarations/aics-image-viewer/state/serialize.d.ts +20 -0
  58. package/type-declarations/aics-image-viewer/state/types.d.ts +216 -0
  59. package/LICENSE.txt +0 -26
  60. package/es/aics-image-viewer/components/AxisClipSliders/index.js +0 -295
package/LICENSE CHANGED
@@ -1,33 +1,29 @@
1
- Allen Institute Software License – This software license is the 2-clause BSD
2
- license plus clause a third clause that prohibits redistribution and use for
3
- commercial purposes without further permission.
1
+ BSD 3-Clause License
4
2
 
5
- Copyright © 2020. Allen Institute. All rights reserved.
3
+ Copyright (c) 2017-2026, Allen Institute
4
+ All rights reserved.
6
5
 
7
- Redistribution and use in source and binary forms, with or without
6
+ Redistribution and use in source and binary forms, with or without
8
7
  modification, are permitted provided that the following conditions are met:
9
8
 
10
- 1. Redistributions of source code must retain the above copyright notice, this
11
- list of conditions and the following disclaimer.
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
12
11
 
13
- 2. Redistributions in binary form must reproduce the above copyright notice,
14
- this list of conditions and the following disclaimer in the documentation
15
- and/or other materials provided with the distribution.
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
16
15
 
17
- 3. Redistributions and use for commercial purposes are not permitted without
18
- the Allen Institute’s written permission. For purposes of this license,
19
- commercial purposes are the incorporation of the Allen Institute's software
20
- into anything for which you will charge fees or other compensation or use of
21
- the software to perform a commercial service for a third party. Contact
22
- terms@alleninstitute.org for commercial licensing opportunities.
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
23
19
 
24
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
29
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -41,6 +41,7 @@ var defaultVisibleControls = {
41
41
  alphaMaskSlider: true,
42
42
  autoRotateButton: true,
43
43
  axisClipSliders: true,
44
+ rotationSliders: true,
44
45
  brightnessSlider: true,
45
46
  backgroundColorPicker: true,
46
47
  boundingBoxColorPicker: true,
@@ -54,7 +55,8 @@ var defaultVisibleControls = {
54
55
  resetCameraButton: true,
55
56
  showAxesButton: true,
56
57
  showBoundingBoxButton: true,
57
- metadataViewer: true
58
+ metadataViewer: true,
59
+ scaleLevelControls: true
58
60
  };
59
61
  var defaultProps = {
60
62
  // rawData has a "dtype" which is expected to be "uint8", a "shape":[c,z,y,x] and a "buffer" which is a DataView
@@ -151,8 +153,8 @@ var App = function App(props) {
151
153
  var showError = (_props$showError = props.showError) !== null && _props$showError !== void 0 ? _props$showError : _showError;
152
154
  useEffect(function () {
153
155
  // Get notifications of loading errors which occur after the initial load, e.g. on time change or new channel load
154
- view3d.setLoadErrorHandler(function (_vol, e) {
155
- return showError(e);
156
+ view3d.setLoadErrorHandler(function (vol, e) {
157
+ return showError(e, vol);
156
158
  });
157
159
  return function () {
158
160
  return view3d.setLoadErrorHandler(undefined);
@@ -323,17 +325,17 @@ var App = function App(props) {
323
325
 
324
326
  // save the channel's new range for remapping next time
325
327
  channelRangesRef.current[channelIndex] = [thisChannel.rawMin, thisChannel.rawMax];
326
- view3d.updateLuts(image);
328
+
329
+ // Note: updateLuts and updateActiveChannels are not called here because the
330
+ // channelVersion bump (via onChannelDataLoaded) will trigger ChannelUpdater
331
+ // effects that apply LUT/color settings and call updateLuts with the final state.
327
332
  view3d.onVolumeData(image, [channelIndex]);
328
333
  if (image.channelNames[channelIndex] === maskChannelName) {
329
334
  view3d.setVolumeChannelAsMask(image, channelIndex);
330
335
  }
331
- if (image.isLoaded()) {
332
- view3d.updateActiveChannels(image);
333
- }
334
336
  }, [view3d, changeChannelSetting, maskChannelName, props.viewerChannelSettings]);
335
- var onError = useCallback(function (error) {
336
- showError(error);
337
+ var onError = useCallback(function (error, image) {
338
+ showError(error, image);
337
339
  onImageTitleChange === null || onImageTitleChange === void 0 || onImageTitleChange(undefined);
338
340
  }, [showError, onImageTitleChange]);
339
341
  var volume = useVolume(scenes, {
@@ -5,37 +5,66 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
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
7
  import { Button, Drawer } from "antd";
8
- import React, { useCallback, useState } from "react";
8
+ import React, { useCallback, useEffect, useState } from "react";
9
9
  import ViewerIcon from "../shared/ViewerIcon";
10
10
  import "./styles.css";
11
11
  var BottomPanel = function BottomPanel(_ref) {
12
- var children = _ref.children,
12
+ var _contents$page;
13
+ var contents = _ref.contents,
13
14
  openProp = _ref.open,
14
- title = _ref.title,
15
+ pageProp = _ref.pageIndex,
15
16
  height = _ref.height,
16
- onOpenChange = _ref.onOpenChange;
17
+ onPageChange = _ref.onPageChange;
17
18
  var _useState = useState(true),
18
19
  _useState2 = _slicedToArray(_useState, 2),
19
20
  openState = _useState2[0],
20
21
  setOpenState = _useState2[1];
22
+ var _useState3 = useState(0),
23
+ _useState4 = _slicedToArray(_useState3, 2),
24
+ pageState = _useState4[0],
25
+ setPageState = _useState4[1];
21
26
  var open = openProp !== null && openProp !== void 0 ? openProp : openState;
22
- var toggleDrawer = useCallback(function () {
27
+ var page = pageProp !== null && pageProp !== void 0 ? pageProp : pageState;
28
+ var setPage = useCallback(function (index) {
29
+ var nextOpen = !open || index !== page;
23
30
  if (openProp === undefined) {
24
- setOpenState(!open);
31
+ setOpenState(nextOpen);
25
32
  }
26
- onOpenChange === null || onOpenChange === void 0 || onOpenChange(!open);
27
- }, [open, openProp, onOpenChange]);
28
- var optionsButton = /*#__PURE__*/React.createElement(Button, {
29
- className: "options-button",
30
- size: "small",
31
- onClick: toggleDrawer
32
- }, title || "Options", /*#__PURE__*/React.createElement(ViewerIcon, {
33
- type: "closePanel",
34
- className: "button-arrow",
35
- style: {
36
- fontSize: "15px"
33
+ if (pageProp === undefined) {
34
+ setPageState(index);
37
35
  }
38
- }));
36
+ onPageChange === null || onPageChange === void 0 || onPageChange(nextOpen ? index : null);
37
+ }, [open, openProp, page, pageProp, onPageChange]);
38
+
39
+ // If length of `contents` decreases, ensure we're still on a valid page
40
+ useEffect(function () {
41
+ if (page >= contents.length && contents.length > 0) {
42
+ var nextPage = contents.length - 1;
43
+ if (pageProp === undefined) {
44
+ setPageState(nextPage);
45
+ }
46
+ onPageChange === null || onPageChange === void 0 || onPageChange(open ? nextPage : null);
47
+ }
48
+ }, [contents.length, onPageChange, open, page, pageProp]);
49
+ var optionsButton = /*#__PURE__*/React.createElement("div", {
50
+ className: "options-button-container"
51
+ }, contents.map(function (_ref2, index) {
52
+ var title = _ref2.title;
53
+ return /*#__PURE__*/React.createElement(Button, {
54
+ key: index,
55
+ className: open && page === index ? "options-button button-open" : "options-button",
56
+ size: "small",
57
+ onClick: function onClick() {
58
+ return setPage(index);
59
+ }
60
+ }, title, /*#__PURE__*/React.createElement(ViewerIcon, {
61
+ type: "closePanel",
62
+ className: "button-arrow",
63
+ style: {
64
+ fontSize: "15px"
65
+ }
66
+ }));
67
+ }).reverse());
39
68
  return /*#__PURE__*/React.createElement("div", {
40
69
  className: "bottom-panel"
41
70
  }, /*#__PURE__*/React.createElement(Drawer, {
@@ -49,6 +78,6 @@ var BottomPanel = function BottomPanel(_ref) {
49
78
  height: height !== null && height !== void 0 ? height : 190
50
79
  }, /*#__PURE__*/React.createElement("div", {
51
80
  className: "drawer-body-wrapper"
52
- }, children)));
81
+ }, open !== null && ((_contents$page = contents[page]) === null || _contents$page === void 0 ? void 0 : _contents$page.children))));
53
82
  };
54
83
  export default BottomPanel;
@@ -46,18 +46,27 @@
46
46
  color:white;
47
47
  }
48
48
 
49
+ .bottom-panel .options-button-container{
50
+ position:absolute;
51
+ right:0;
52
+ }
53
+
49
54
  .bottom-panel .options-button{
55
+ bottom:0;
56
+ transition:bottom 0.1s linear;
50
57
  border:none;
51
58
  box-shadow:none;
52
59
  margin-right:0.8em;
53
60
  margin-bottom:0.2em;
54
- position:absolute;
55
- right:0;
56
61
  }
57
62
 
58
63
  .bottom-panel .button-arrow{
59
64
  transform:rotate(270deg);
60
- transition:transform 0.2s linear !important;
65
+ transition:transform 0.1s linear !important;
66
+ }
67
+
68
+ .bottom-panel .options-button.button-open .button-arrow{
69
+ transform:rotate(90deg);
61
70
  }
62
71
 
63
72
  .bottom-panel .drawer-body-wrapper{
@@ -65,6 +74,10 @@
65
74
  width:100%;
66
75
  }
67
76
 
77
+ .bottom-panel .ant-drawer.ant-drawer-open .options-button:not(.button-open){
78
+ bottom:0.8em;
79
+ }
80
+
68
81
  .bottom-panel .ant-drawer.ant-drawer-open .ant-drawer-content-wrapper{
69
82
  transform:none;
70
83
  box-shadow:none;
@@ -79,7 +92,3 @@
79
92
  .bottom-panel .ant-drawer.ant-drawer-open .ant-drawer-title .ant-btn.ant-btn-default{
80
93
  background-color:var(--color-controlpanel-drawer-bg);
81
94
  }
82
-
83
- .bottom-panel .ant-drawer.ant-drawer-open .button-arrow{
84
- transform:rotate(90deg);
85
- }
@@ -9,8 +9,9 @@ import React from "react";
9
9
  import { CLIPPING_PANEL_HEIGHT_DEFAULT, CLIPPING_PANEL_HEIGHT_TALL } from "../../shared/constants";
10
10
  import { ViewMode } from "../../shared/enums";
11
11
  import { select, useViewerState } from "../../state/store";
12
- import AxisClipSliders from "../AxisClipSliders";
13
12
  import BottomPanel from "../BottomPanel";
13
+ import { AxisClipSliders } from "../dimension_sliders/AxisClipSliders";
14
+ import { RotationSliders } from "../dimension_sliders/RotationSliders";
14
15
  import "./styles.css";
15
16
  var ViewerWrapper = function ViewerWrapper(props) {
16
17
  var view3dviewerRef = /*#__PURE__*/React.createRef();
@@ -47,6 +48,36 @@ var ViewerWrapper = function ViewerWrapper(props) {
47
48
  var time = useViewerState(select("time"));
48
49
  var scene = useViewerState(select("scene"));
49
50
  var clippingPanelTall = numTimesteps > 1 && numScenes > 1 && viewMode === ViewMode.threeD;
51
+ var bottomPanelContents = [];
52
+ if (visibleControls.axisClipSliders && !!props.image) {
53
+ bottomPanelContents.push({
54
+ title: "Clipping",
55
+ children: /*#__PURE__*/React.createElement(AxisClipSliders, {
56
+ mode: viewMode,
57
+ image: props.image,
58
+ changeViewerSetting: changeViewerSetting,
59
+ numSlices: props.numSlices,
60
+ numSlicesLoaded: props.numSlicesLoaded,
61
+ numScenes: numScenes,
62
+ region: region,
63
+ slices: slice,
64
+ numTimesteps: numTimesteps,
65
+ time: time,
66
+ scene: scene,
67
+ playControls: props.playControls,
68
+ playingAxis: props.playingAxis
69
+ })
70
+ });
71
+ }
72
+ if (visibleControls.rotationSliders) {
73
+ bottomPanelContents.push({
74
+ title: "Rotation",
75
+ children: /*#__PURE__*/React.createElement(RotationSliders, {
76
+ view3d: props.view3d,
77
+ disable: viewMode !== ViewMode.threeD
78
+ })
79
+ });
80
+ }
50
81
  return /*#__PURE__*/React.createElement("div", {
51
82
  className: "cell-canvas",
52
83
  style: _objectSpread(_objectSpread({}, STYLES.viewer), {}, {
@@ -56,25 +87,14 @@ var ViewerWrapper = function ViewerWrapper(props) {
56
87
  ref: view3dviewerRef,
57
88
  style: STYLES.view3d
58
89
  }), /*#__PURE__*/React.createElement(BottomPanel, {
59
- title: "Clipping",
60
90
  open: props.clippingPanelOpen,
61
- onOpenChange: props.onClippingPanelOpenChange,
62
- height: clippingPanelTall ? CLIPPING_PANEL_HEIGHT_TALL : CLIPPING_PANEL_HEIGHT_DEFAULT
63
- }, visibleControls.axisClipSliders && !!props.image && /*#__PURE__*/React.createElement(AxisClipSliders, {
64
- mode: viewMode,
65
- image: props.image,
66
- changeViewerSetting: changeViewerSetting,
67
- numSlices: props.numSlices,
68
- numSlicesLoaded: props.numSlicesLoaded,
69
- numScenes: numScenes,
70
- region: region,
71
- slices: slice,
72
- numTimesteps: numTimesteps,
73
- time: time,
74
- scene: scene,
75
- playControls: props.playControls,
76
- playingAxis: props.playingAxis
77
- })), renderOverlay());
91
+ onPageChange: function onPageChange(open) {
92
+ var _props$onClippingPane;
93
+ return (_props$onClippingPane = props.onClippingPanelOpenChange) === null || _props$onClippingPane === void 0 ? void 0 : _props$onClippingPane.call(props, open !== null);
94
+ },
95
+ height: clippingPanelTall ? CLIPPING_PANEL_HEIGHT_TALL : CLIPPING_PANEL_HEIGHT_DEFAULT,
96
+ contents: bottomPanelContents
97
+ }), renderOverlay());
78
98
  };
79
99
  export default ViewerWrapper;
80
100
  var STYLES = {
@@ -139,14 +139,14 @@ var ChannelsWidget = function ChannelsWidget(props) {
139
139
  };
140
140
  var renderChannelRow = function renderChannelRow(channelIndex) {
141
141
  var channelName = channelNames[channelIndex];
142
- return channelName ? /*#__PURE__*/React.createElement(ChannelsWidgetRow, {
142
+ return /*#__PURE__*/React.createElement(ChannelsWidgetRow, {
143
143
  key: channelIndex,
144
144
  index: channelIndex,
145
145
  channelDataForChannel: channelDataChannels[channelIndex],
146
146
  name: getDisplayName(channelName, channelIndex, viewerChannelSettings),
147
147
  onColorChangeComplete: props.onColorChangeComplete,
148
148
  saveIsosurface: props.saveIsosurface
149
- }) : null;
149
+ });
150
150
  };
151
151
  var rows = channelDataChannels && Object.entries(channelGroupedByType).filter(function (_ref3) {
152
152
  var _ref4 = _slicedToArray(_ref3, 2),
@@ -1,4 +1,3 @@
1
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
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); }
3
2
  function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
4
3
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@@ -38,10 +37,11 @@ function ControlPanel(props) {
38
37
  var resetToDefaultViewerState = useViewerState(select("resetToDefaultViewerState"));
39
38
  var singleChannelMode = useViewerState(select("singleChannelMode"));
40
39
  var changeViewerSetting = useViewerState(select("changeViewerSetting"));
41
- var controlPanelContainerRef = React.useRef(null);
42
- var getDropdownContainer = controlPanelContainerRef.current ? function () {
43
- return controlPanelContainerRef.current;
44
- } : undefined;
40
+ var containerRef = React.useRef(null);
41
+ var getDropdownContainer = function getDropdownContainer() {
42
+ var _containerRef$current;
43
+ return (_containerRef$current = containerRef.current) !== null && _containerRef$current !== void 0 ? _containerRef$current : document.body;
44
+ };
45
45
  var viewerChannelSettings = props.viewerChannelSettings,
46
46
  visibleControls = props.visibleControls,
47
47
  hasImage = props.hasImage;
@@ -98,12 +98,11 @@ function ControlPanel(props) {
98
98
  }, "Single channel mode"))));
99
99
  };
100
100
  var renderTab = function renderTab(thisTab, icon) {
101
- return /*#__PURE__*/React.createElement(Tooltip, _extends({
101
+ return /*#__PURE__*/React.createElement(Tooltip, {
102
102
  title: ControlTabNames[thisTab],
103
103
  placement: "right"
104
- }, !props.collapsed && {
105
- open: false
106
- }), /*#__PURE__*/React.createElement(Button, {
104
+ }, /*#__PURE__*/React.createElement(Button, {
105
+ "aria-label": ControlTabNames[thisTab],
107
106
  className: tab === thisTab ? "ant-btn-icon-only btn-tabactive" : "ant-btn-icon-only",
108
107
  onClick: function onClick() {
109
108
  return setTab(thisTab);
@@ -111,6 +110,8 @@ function ControlPanel(props) {
111
110
  icon: typeof icon === "string" ? icon : undefined
112
111
  }, _typeof(icon) === "object" && icon));
113
112
  };
113
+
114
+ // TODO this can just be a component...?
114
115
  var renderAdvancedSettings = function renderAdvancedSettings() {
115
116
  var items = [{
116
117
  key: 0,
@@ -151,22 +152,27 @@ function ControlPanel(props) {
151
152
  onClick: resetToDefaultViewerState
152
153
  }, "Clear all settings"))));
153
154
  };
155
+ var collapseLabel = props.collapsed ? "Show panel" : "Hide panel";
154
156
  return /*#__PURE__*/React.createElement("div", {
155
157
  className: "control-panel-col-container",
156
- ref: controlPanelContainerRef
158
+ ref: containerRef
157
159
  }, /*#__PURE__*/React.createElement("div", {
158
160
  className: "control-panel-tab-col",
159
161
  style: {
160
162
  flex: "0 0 50px"
161
163
  }
164
+ }, /*#__PURE__*/React.createElement(Tooltip, {
165
+ title: collapseLabel,
166
+ placement: "right"
162
167
  }, /*#__PURE__*/React.createElement(Button, {
168
+ "aria-label": collapseLabel,
163
169
  className: "ant-btn-icon-only btn-collapse" + (props.collapsed ? " btn-collapse-collapsed" : ""),
164
170
  onClick: function onClick() {
165
171
  return props.setCollapsed(!props.collapsed);
166
172
  }
167
173
  }, /*#__PURE__*/React.createElement(ViewerIcon, {
168
174
  type: "closePanel"
169
- })), /*#__PURE__*/React.createElement("div", {
175
+ }))), /*#__PURE__*/React.createElement("div", {
170
176
  className: "tab-divider"
171
177
  }), renderTab(ControlTab.Channels, /*#__PURE__*/React.createElement(ViewerIcon, {
172
178
  type: "channels"
@@ -20,16 +20,16 @@
20
20
  }
21
21
 
22
22
  .control-panel-col-container .control-panel-tab-col .ant-btn:not([disabled]).btn-tabactive{
23
- color:var(--color-button-icon-activated-text);
24
- background-color:var(--color-button-icon-activated-bg);
25
- border-color:var(--color-button-icon-activated-outline);
23
+ color:var(--color-button-icon-active-text);
24
+ background-color:var(--color-button-icon-active-bg);
25
+ border-color:var(--color-button-icon-active-outline);
26
26
  }
27
27
 
28
28
  .control-panel-col-container .control-panel-tab-col .ant-btn:not([disabled]):hover,
29
29
  .control-panel-col-container .control-panel-tab-col .ant-btn:not([disabled]):focus-visible{
30
- color:var(--color-button-icon-activated-text);
30
+ color:var(--color-button-icon-active-text);
31
31
  background-color:var(--color-button-primary-hover-bg);
32
- border-color:var(--color-button-icon-activated-outline);
32
+ border-color:var(--color-button-icon-active-outline);
33
33
  }
34
34
 
35
35
  .control-panel-col-container .control-panel-tab-col .btn-collapse svg{