@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
@@ -13,7 +13,7 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
13
13
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
14
14
  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); }
15
15
  import { VolumeLoadErrorType } from "@aics/vole-core";
16
- import { RightOutlined } from "@ant-design/icons";
16
+ import { LeftOutlined, RightOutlined, WarningOutlined } from "@ant-design/icons";
17
17
  import { Alert, Button } from "antd";
18
18
  import React from "react";
19
19
  import { useConstructor } from "../../shared/utils/hooks";
@@ -40,115 +40,142 @@ var getErrorTitle = function getErrorTitle(error) {
40
40
  var _error$toString;
41
41
  return error instanceof Error && ((_error$toString = error.toString) === null || _error$toString === void 0 ? void 0 : _error$toString.call(error)) || typeof error === "string" && error || _typeof(error) === "object" && error !== null && error.title || "Unknown error";
42
42
  };
43
- var getErrorDescription = function getErrorDescription(error) {
43
+ var getErrorDescription = function getErrorDescription(_ref2) {
44
44
  var _ERROR_TYPE_DESCRIPTI2;
45
+ var error = _ref2.error,
46
+ dims = _ref2.dims;
45
47
  var type = error.type;
46
48
  if (!type) {
47
49
  return _typeof(error) === "object" && error !== null && error.description || UNKNOWN_ERROR_DESCRIPTION;
48
50
  }
49
51
  if (type === VolumeLoadErrorType.TOO_LARGE && useViewerState.getState().useExactScaleLevel) {
50
- return /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer cannot load this resolution level within memory limits. Try again with a smaller resolution level.");
52
+ var dimsDetail = "";
53
+ if (Array.isArray(dims)) {
54
+ var _dims = _slicedToArray(dims, 5),
55
+ _t = _dims[0],
56
+ _c = _dims[1],
57
+ z = _dims[2],
58
+ y = _dims[3],
59
+ x = _dims[4];
60
+ dimsDetail = " (".concat(x, " x ").concat(y, " x ").concat(z, ")");
61
+ }
62
+ return /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer cannot load this resolution level", dimsDetail, " within memory limits. Try again with a smaller resolution level.");
51
63
  }
52
64
  return (_ERROR_TYPE_DESCRIPTI2 = ERROR_TYPE_DESCRIPTIONS[type]) !== null && _ERROR_TYPE_DESCRIPTI2 !== void 0 ? _ERROR_TYPE_DESCRIPTI2 : UNKNOWN_ERROR_DESCRIPTION;
53
65
  };
54
- var ErrorAlert = function ErrorAlert(_ref2) {
55
- var errors = _ref2.errors,
56
- _ref2$firstErrorCount = _ref2.firstErrorCount,
57
- firstErrorCount = _ref2$firstErrorCount === void 0 ? 0 : _ref2$firstErrorCount,
58
- _afterClose = _ref2.afterClose,
59
- onSkipError = _ref2.onSkipError;
66
+ var ErrorAlert = function ErrorAlert(_ref3) {
67
+ var errors = _ref3.errors,
68
+ afterClose = _ref3.afterClose;
60
69
  var _React$useState = React.useState(false),
61
70
  _React$useState2 = _slicedToArray(_React$useState, 2),
62
71
  showDetails = _React$useState2[0],
63
72
  setShowDetails = _React$useState2[1];
64
73
  var _React$useState3 = React.useState(0),
65
74
  _React$useState4 = _slicedToArray(_React$useState3, 2),
66
- errorsSeenCount = _React$useState4[0],
67
- setErrorsSeenCount = _React$useState4[1];
68
- var error = Array.isArray(errors) ? errors[0] : errors;
75
+ errorIndex = _React$useState4[0],
76
+ setErrorIndex = _React$useState4[1];
77
+ var _React$useState5 = React.useState(false),
78
+ _React$useState6 = _slicedToArray(_React$useState5, 2),
79
+ flash = _React$useState6[0],
80
+ setFlash = _React$useState6[1];
81
+ var error = errors[errorIndex];
69
82
  var infoStyle = {
70
83
  display: showDetails ? undefined : "none"
71
84
  };
72
- var errorMessage = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
85
+ React.useEffect(function () {
86
+ setErrorIndex(errors.length - 1);
87
+ setFlash(errors.length > 1);
88
+ window.setTimeout(function () {
89
+ return setFlash(false);
90
+ }, 100);
91
+ }, [errors]);
92
+ var cause = error.error.cause;
93
+ var msg = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
73
94
  className: "error-title"
74
- }, getErrorTitle(error) + (firstErrorCount > 1 ? " (".concat(firstErrorCount, ")") : ""), " ", /*#__PURE__*/React.createElement(Button, {
95
+ }, getErrorTitle(error.error) + (error.count > 1 ? " (".concat(error.count, ")") : ""), " ", /*#__PURE__*/React.createElement(Button, {
75
96
  type: "text",
76
97
  onClick: function onClick() {
77
98
  return setShowDetails(!showDetails);
78
99
  }
79
100
  }, showDetails ? "Show less info" : "Show more info")), /*#__PURE__*/React.createElement("div", {
80
101
  style: infoStyle
81
- }, getErrorDescription(error)), error.cause !== undefined && /*#__PURE__*/React.createElement("div", {
102
+ }, getErrorDescription(error)), cause !== undefined && /*#__PURE__*/React.createElement("div", {
82
103
  className: "error-cause",
83
104
  style: infoStyle
84
- }, "Caused by ", getErrorTitle(error.cause)));
85
- var skipErrorButton = Array.isArray(errors) && errors.length > 1 && /*#__PURE__*/React.createElement(Button, {
86
- type: "text",
87
- onClick: function onClick() {
88
- setErrorsSeenCount(function (count) {
89
- return count + 1;
90
- });
91
- onSkipError === null || onSkipError === void 0 || onSkipError();
105
+ }, "Caused by ", getErrorTitle(cause)));
106
+ var pageButton = undefined;
107
+ if (errors.length > 1) {
108
+ if (errorIndex === errors.length - 1) {
109
+ pageButton = /*#__PURE__*/React.createElement(Button, {
110
+ type: "text",
111
+ onClick: function onClick() {
112
+ return setErrorIndex(function (i) {
113
+ return i - 1;
114
+ });
115
+ }
116
+ }, /*#__PURE__*/React.createElement(LeftOutlined, null), " ", errors.length - 1, " previous error", errors.length > 2 ? "s" : "");
117
+ } else {
118
+ pageButton = /*#__PURE__*/React.createElement(React.Fragment, null, errorIndex > 0 && /*#__PURE__*/React.createElement(Button, {
119
+ type: "text",
120
+ onClick: function onClick() {
121
+ return setErrorIndex(function (i) {
122
+ return i - 1;
123
+ });
124
+ }
125
+ }, /*#__PURE__*/React.createElement(LeftOutlined, null)), "Error ", errorIndex + 1, " of ", errors.length, /*#__PURE__*/React.createElement(Button, {
126
+ type: "text",
127
+ onClick: function onClick() {
128
+ return setErrorIndex(function (i) {
129
+ return i + 1;
130
+ });
131
+ }
132
+ }, /*#__PURE__*/React.createElement(RightOutlined, null)));
92
133
  }
93
- }, "Error ", errorsSeenCount + 1, " of ", errors.length + errorsSeenCount, " ", /*#__PURE__*/React.createElement(RightOutlined, null));
134
+ }
135
+ var alertClass = flash ? "load-error-alert error-flash" : "load-error-alert";
94
136
  return /*#__PURE__*/React.createElement(Alert, {
95
137
  showIcon: true,
96
- type: "error",
97
- className: "load-error-alert",
98
- message: errorMessage,
99
138
  closable: true,
100
- afterClose: function afterClose() {
101
- setErrorsSeenCount(0);
102
- _afterClose === null || _afterClose === void 0 || _afterClose();
103
- },
104
- action: skipErrorButton
139
+ type: "error",
140
+ icon: /*#__PURE__*/React.createElement(WarningOutlined, null),
141
+ className: alertClass,
142
+ message: msg,
143
+ afterClose: afterClose,
144
+ action: pageButton
105
145
  });
106
146
  };
107
147
  export var useErrorAlert = function useErrorAlert() {
108
- var _React$useState5 = React.useState([]),
109
- _React$useState6 = _slicedToArray(_React$useState5, 2),
110
- errorList = _React$useState6[0],
111
- setErrorList = _React$useState6[1];
148
+ var _React$useState7 = React.useState([]),
149
+ _React$useState8 = _slicedToArray(_React$useState7, 2),
150
+ errors = _React$useState8[0],
151
+ setErrors = _React$useState8[1];
112
152
  // Keep track of which errors have been seen and how many times
113
153
  var seenErrors = useConstructor(function () {
114
154
  return new Map();
115
155
  });
116
- var _React$useState7 = React.useState([]),
117
- _React$useState8 = _slicedToArray(_React$useState7, 2),
118
- errorCounts = _React$useState8[0],
119
- setErrorCounts = _React$useState8[1];
120
- var addError = React.useCallback(function (error) {
156
+ var addError = React.useCallback(function (error, image) {
121
157
  var _seenErrors$get;
122
158
  var errorTitle = getErrorTitle(error);
123
159
  console.error(error instanceof Error ? error : errorTitle);
124
- var errorSeenCount = ((_seenErrors$get = seenErrors.get(errorTitle)) !== null && _seenErrors$get !== void 0 ? _seenErrors$get : 0) + 1;
125
- setErrorList(function (prev) {
126
- return [].concat(_toConsumableArray(prev), [error]);
160
+ var count = ((_seenErrors$get = seenErrors.get(errorTitle)) !== null && _seenErrors$get !== void 0 ? _seenErrors$get : 0) + 1;
161
+ var imageInfo = image === null || image === void 0 ? void 0 : image.imageInfo.imageInfo;
162
+ var dims = imageInfo && imageInfo.multiscaleLevelDims[imageInfo.multiscaleLevel].shape;
163
+ setErrors(function (prev) {
164
+ return [].concat(_toConsumableArray(prev), [{
165
+ error: error,
166
+ count: count,
167
+ dims: dims
168
+ }]);
127
169
  });
128
- setErrorCounts(function (prev) {
129
- return [].concat(_toConsumableArray(prev), [errorSeenCount]);
130
- });
131
- seenErrors.set(errorTitle, errorSeenCount);
170
+ seenErrors.set(errorTitle, count);
132
171
  }, [seenErrors]);
133
- var onSkipError = React.useCallback(function () {
134
- setErrorList(function (prev) {
135
- return prev.slice(1);
136
- });
137
- setErrorCounts(function (prev) {
138
- return prev.slice(1);
139
- });
140
- }, []);
141
172
  var afterClose = React.useCallback(function () {
142
- setErrorList([]);
143
- setErrorCounts([]);
173
+ return setErrors([]);
144
174
  }, []);
145
- var errCount = errorCounts[0];
146
- var alertComponent = errorList.length > 0 && /*#__PURE__*/React.createElement(ErrorAlert, {
147
- errors: errorList,
148
- firstErrorCount: errCount,
149
- onSkipError: onSkipError,
175
+ var alertNode = errors.length > 0 && /*#__PURE__*/React.createElement(ErrorAlert, {
176
+ errors: errors,
150
177
  afterClose: afterClose
151
178
  });
152
- return [alertComponent, addError];
179
+ return [alertNode, addError];
153
180
  };
154
181
  export default ErrorAlert;
@@ -5,24 +5,53 @@
5
5
  width:40vw;
6
6
  align-items:start;
7
7
  z-index:5000;
8
- border-color:#dc4446;
8
+ border-color:var(--color-text-error);
9
9
  padding:12px 30px;
10
10
  color:var(--color-text-section);
11
11
  }
12
+
13
+ .load-error-alert.error-flash{
14
+ background-color:var(--color-text-error);
15
+ }
16
+
12
17
  .load-error-alert .ant-alert-icon,
13
18
  .load-error-alert .ant-alert-close-icon,
14
19
  .load-error-alert .ant-alert-message div{
15
20
  min-height:24px;
16
21
  }
17
- .load-error-alert .ant-btn-text{
22
+
23
+ .load-error-alert .ant-alert-close-icon{
24
+ margin-inline-start:14px;
25
+ }
26
+
27
+ .load-error-alert .ant-alert-action{
28
+ display:inline-flex;
29
+ align-items:center;
30
+ gap:4px;
31
+ }
32
+
33
+ .load-error-alert .ant-alert-action > button{
34
+ gap:4px;
35
+ border:none !important;
36
+ }
37
+
38
+ .load-error-alert .ant-btn-text,
39
+ .load-error-alert .ant-alert-action{
18
40
  color:var(--color-text-link);
19
41
  }
42
+
20
43
  .load-error-alert .ant-btn-text:hover{
21
- color:#25affe !important;
22
- }
44
+ color:#25affe !important;
45
+ }
46
+
47
+ .load-error-alert .anticon{
48
+ font-size:21px;
49
+ }
50
+
23
51
  .load-error-alert .ant-alert-message > div.error-title{
24
52
  font-weight:600;
25
53
  }
54
+
26
55
  .load-error-alert .ant-alert-message > div.error-cause{
27
56
  font-style:italic;
28
57
  color:var(--color-text-body);
@@ -1,8 +1,8 @@
1
- var _templateObject, _templateObject2;
1
+ var _templateObject, _templateObject2, _templateObject3;
2
2
  function _taggedTemplateLiteral(e, t) { return t || (t = e.slice(0)), Object.freeze(Object.defineProperties(e, { raw: { value: Object.freeze(t) } })); }
3
3
  import { theme as AntTheme, ConfigProvider } from "antd";
4
4
  import React from "react";
5
- import styled, { css } from "styled-components";
5
+ import styled, { createGlobalStyle, css } from "styled-components";
6
6
  var palette = {
7
7
  black: "#000000",
8
8
  white: "#ffffff",
@@ -18,7 +18,7 @@ var palette = {
18
18
  darkPurple: "#7e46d4",
19
19
  veryDarkPurple: "#5f369f",
20
20
  veryLtPurple: "#e7e4f2",
21
- brightRed: "#ff4d4d",
21
+ brightRed: "#dc4446",
22
22
  brightYellow: "#e39b0d",
23
23
  brightGreen: "#61d900",
24
24
  veryBrightGreen: "#61ff00",
@@ -79,10 +79,10 @@ var theme = {
79
79
  outline: palette.ltGrey,
80
80
  hoverOutline: palette.ltPurple,
81
81
  hoverText: palette.ltPurple,
82
- activeOutline: palette.medPurple,
83
- activatedText: palette.white,
84
- activatedBg: palette.medDarkGrey,
85
- activatedOutline: palette.purpleGrey,
82
+ activeText: palette.white,
83
+ activeBg: palette.medDarkGrey,
84
+ activeOutline: palette.purpleGrey,
85
+ disabledOutline: palette.medGrey,
86
86
  disabledText: palette.medGrey
87
87
  }
88
88
  },
@@ -136,7 +136,7 @@ var theme = {
136
136
  }
137
137
  },
138
138
  tooltip: {
139
- bg: palette.black
139
+ bg: palette.medDarkGrey
140
140
  },
141
141
  modal: {
142
142
  maskBg: "#000000cc",
@@ -150,10 +150,11 @@ var theme = {
150
150
  }
151
151
  };
152
152
  /** Makes theme styling available to child components via CSS variables. */
153
- var CssProvider = styled.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n width: 100%;\n height: 100%;\n\n ", "\n\n h1, h2, h3, h4, p {\n font-family: var(--font-family);\n }\n\n h1 {\n color: var(--color-text-header);\n font-size: 28px;\n font-weight: 400;\n }\n\n h2 {\n color: var(--color-text-section);\n font-size: 19px;\n font-weight: 400;\n }\n\n h3 {\n color: var(--color-text-header);\n font-size: 16px;\n font-weight: 600;\n }\n\n h4 {\n color: var(--color-text-header);\n font-size: 14px;\n font-weight: 400;\n }\n\n p {\n color: var(--color-text-body);\n font-size: 14px;\n font-weight: 400;\n }\n\n a {\n color: var(--color-text-link);\n }\n\n & *::selection {\n background-color: var(--color-text-selection-bg);\n color: var(--color-text-selection-text);\n }\n\n /** TODO: Go through these styles and see if we can use Ant ConfigProvider for them instead. */\n .ant-btn-link,\n .ant-btn-text,\n .ant-btn-primary,\n .ant-btn-icon-only {\n box-shadow: none;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border-color: var(--color-button-primary-hover-bg);\n color: var(--color-button-primary-text);\n }\n\n &:active:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border: 1px solid var(--color-button-primary-active-outline);\n color: var(--color-button-primary-text);\n }\n }\n\n /* Let us use buttons with type=\"text\" as purely semantic containers - don't bring any styling! */\n .ant-btn-text {\n width: unset;\n height: unset;\n padding: unset;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: unset;\n border-color: transparent;\n }\n }\n\n .ant-btn-icon-only:disabled {\n color: var(--color-button-icon-disabled-text);\n }\n\n .ant-btn-link:not(:disabled) {\n // Change from default blue link text\n color: var(--color-button-link-text);\n }\n\n /**\n * Tertiary style buttons. Grey outline by default, turns to light\n * purple outline on hover.\n */\n .ant-btn-default:not(.ant-btn-icon-only) {\n background-color: var(--color-button-tertiary-bg);\n color: var(--color-button-tertiary-text);\n border-color: var(--color-button-tertiary-outline);\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-hover-bg);\n color: var(--color-button-tertiary-hover-text);\n }\n\n &:active:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-active-outline);\n color: var(--color-button-tertiary-active-text);\n }\n }\n\n // Overrides for checkbox styling\n & .ant-checkbox-input {\n &:hover,\n &:focus-visible {\n border: 1px solid white;\n }\n }\n\n & .ant-checkbox.ant-checkbox-checked {\n background-color: var(--color-checkbox-bg);\n }\n\n .ant-checkbox-inner {\n background-color: transparent !important;\n }\n\n // Add outlines to modals and dropdowns\n & .ant-select-dropdown,\n & .ant-dropdown-menu,\n & .ant-modal-content {\n border: 1px solid var(--color-modal-border);\n }\n\n // Force active/hovered text to be white instead of grey for better contrast\n & .ant-dropdown-menu-item-active {\n color: var(--color-menu-hover-text);\n }\n\n // Remove padding in dropdown menus and make items reactangular + flush with the edge\n & .ant-dropdown-menu,\n & .ant-select-dropdown {\n padding: 0;\n overflow: hidden;\n\n & .ant-dropdown-menu-item,\n & .ant-select-item {\n border-radius: 0;\n }\n }\n"])), function (_ref) {
153
+ var CssProvider = styled.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n width: 100%;\n height: 100%;\n\n ", "\n\n h1, h2, h3, h4, p {\n font-family: var(--font-family);\n }\n\n h1 {\n color: var(--color-text-header);\n font-size: 28px;\n font-weight: 400;\n }\n\n h2 {\n color: var(--color-text-section);\n font-size: 19px;\n font-weight: 400;\n }\n\n h3 {\n color: var(--color-text-header);\n font-size: 16px;\n font-weight: 600;\n }\n\n h4 {\n color: var(--color-text-header);\n font-size: 14px;\n font-weight: 400;\n }\n\n p {\n color: var(--color-text-body);\n font-size: 14px;\n font-weight: 400;\n }\n\n a {\n color: var(--color-text-link);\n }\n\n *::selection {\n background-color: var(--color-text-selection-bg);\n color: var(--color-text-selection-text);\n }\n\n /** TODO: Go through these styles and see if we can use Ant ConfigProvider for them instead. */\n .ant-btn-link,\n .ant-btn-text,\n .ant-btn-primary,\n .ant-btn-icon-only {\n box-shadow: none;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border-color: var(--color-button-primary-hover-bg);\n color: var(--color-button-primary-text);\n outline: none;\n }\n\n &:active:not(:disabled) {\n background-color: var(--color-button-primary-hover-bg);\n border: 1px solid var(--color-button-primary-active-outline);\n color: var(--color-button-primary-text);\n }\n }\n\n /* Let us use buttons with type=\"text\" as purely semantic containers - don't bring any styling! */\n .ant-btn-text {\n width: unset;\n height: unset;\n padding: unset;\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: unset;\n border-color: transparent;\n }\n }\n\n .ant-btn-icon-only:disabled {\n color: var(--color-button-icon-disabled-text);\n }\n\n .ant-btn-link:not(:disabled) {\n // Change from default blue link text\n color: var(--color-button-link-text);\n }\n\n /**\n * Tertiary style buttons. Grey outline by default, turns to light\n * purple outline on hover.\n */\n .ant-btn-default:not(.ant-btn-icon-only) {\n background-color: var(--color-button-tertiary-bg);\n color: var(--color-button-tertiary-text);\n border-color: var(--color-button-tertiary-outline);\n\n &:hover:not(:disabled),\n &:focus-visible:not(:disabled) {\n background-color: transparent;\n border-color: var(--color-button-tertiary-hover-outline);\n color: var(--color-button-tertiary-hover-text);\n }\n }\n\n // Overrides for checkbox styling\n .ant-checkbox-input {\n &:hover,\n &:focus-visible {\n border: 1px solid white;\n }\n }\n\n .ant-checkbox.ant-checkbox-checked {\n background-color: var(--color-checkbox-bg);\n }\n\n .ant-checkbox-inner {\n background-color: transparent !important;\n }\n\n // Add outlines to modals and dropdowns\n .ant-select-dropdown,\n .ant-dropdown-menu,\n .ant-modal-content {\n border: 1px solid var(--color-modal-border);\n }\n\n // Force active/hovered text to be white instead of grey for better contrast\n .ant-dropdown-menu-item-active {\n color: var(--color-menu-hover-text);\n }\n\n // Remove padding in dropdown menus and make items reactangular + flush with the edge\n .ant-dropdown-menu,\n .ant-select-dropdown {\n padding: 0;\n overflow: hidden;\n\n .ant-dropdown-menu-item,\n .ant-select-item:not(.ant-select-item-option-disabled) {\n border-radius: 0;\n color: var(--color-button-icon-active-text);\n }\n }\n\n .ant-select {\n &.ant-select-disabled .ant-select-selector {\n border-color: var(--color-button-icon-disabled-outline);\n }\n\n .ant-select-arrow {\n transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\n }\n\n /* Control response to hover + active menu */\n &:hover:not(.ant-select-disabled),\n &:focus-visible:not(.ant-select-disabled),\n &.ant-select.ant-select-open {\n .ant-select-selector,\n .ant-select-arrow,\n .ant-select-selection-item {\n color: var(--color-button-tertiary-hover-text);\n outline-color: var(--color-button-tertiary-hover-outline);\n }\n }\n }\n\n // Toolbar has special colors for radio buttons and will use these variables to apply them\n --color-button-radio-hover-outline: var(--color-button-tertiary-hover-outline);\n --color-button-radio-hover-text: var(--color-button-tertiary-hover-text);\n\n .ant-radio-button-wrapper {\n &::before {\n content: none;\n }\n\n &.ant-radio-button-wrapper-checked {\n color: var(--color-button-icon-active-text);\n\n &:not(:first-child) {\n box-shadow: -1px 0px 0px 0px var(--color-button-tertiary-active-outline);\n }\n }\n\n &:hover,\n &:has(:focus-visible) {\n color: var(--color-button-radio-hover-text);\n border-color: var(--color-button-radio-hover-outline);\n outline: none;\n z-index: 2;\n\n &:not(:first-child) {\n box-shadow: -1px 0px 0px 0px var(--color-button-radio-hover-outline);\n }\n }\n }\n\n"])), function (_ref) {
154
154
  var $theme = _ref.$theme;
155
- return css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n /* Component and color variables. */\n // TODO: Fix inconsistent use of border vs. outline\n // TODO: Remove variables that aren't used in other CSS files. These should be set directly\n // from the $theme object to reduce unnecessary variables.\n --color-text-link: ", ";\n --color-text-header: ", ";\n --color-text-section: ", ";\n --color-text-body: ", ";\n --color-text-error: ", ";\n\n --color-text-selection-bg: ", ";\n --color-text-selection-text: ", ";\n\n --color-header-title: ", ";\n --color-header-hover-title: ", ";\n --color-header-bg: ", ";\n --color-header-border: ", ";\n\n --color-button-primary-bg: ", ";\n --color-button-primary-text: ", ";\n --color-button-primary-hover-bg: ", ";\n --color-button-primary-active-bg: ", ";\n --color-button-primary-active-outline: ", ";\n --color-button-primary-disabled-bg: ", ";\n\n --color-button-link-text: ", ";\n\n --color-button-secondary-bg: ", ";\n --color-button-secondary-text: ", ";\n --color-button-secondary-outline: ", ";\n\n --color-button-tertiary-bg: transparent;\n --color-button-tertiary-text: ", ";\n --color-button-tertiary-outline: ", ";\n --color-button-tertiary-hover-outline: ", ";\n --color-button-tertiary-hover-text: ", ";\n --color-button-tertiary-active-outline: ", ";\n --color-button-tertiary-active-text: ", ";\n\n --color-button-icon-disabled-text: ", ";\n --color-button-icon-activated-text: ", ";\n --color-button-icon-activated-bg: ", ";\n --color-button-icon-activated-outline: ", ";\n\n --color-toolbar-button-bg: ", ";\n\n --color-controlpanel-bg: ", ";\n --color-controlpanel-border: ", ";\n --color-controlpanel-section-text: ", ";\n --color-controlpanel-text: ", ";\n --color-controlpanel-section-bg: ", ";\n --color-controlpanel-drawer-bg: ", ";\n --color-controlpanel-ramp-slider: ", ";\n --color-controlpanel-isovalue-slider: ", ";\n\n --color-landingpage-bg: ", ";\n --color-landingpage-bg-alt: ", ";\n --color-landingpage-text: ", ";\n --color-landingpage-banner-highlight-bg: ", ";\n\n --color-statusflag-border: ", ";\n --color-statusflag-text: ", ";\n\n --color-alert-warning-text: ", ";\n --color-alert-warning-bg: ", ";\n --color-alert-info-text: ", ";\n --color-alert-info-bg: ", ";\n\n --color-layout-dividers: ", ";\n\n --color-modal-border: ", ";\n\n --color-menu-hover-text: ", ";\n --color-menu-selected-text: ", ";\n\n --color-checkbox-bg: ", ";\n\n --font-family: ", ";\n "])), $theme.colors.text.link, $theme.colors.text.header, $theme.colors.text.section, $theme.colors.text.body, $theme.colors.text.error, $theme.colors.text.selectionBg, $theme.colors.text.selectionText, $theme.colors.header.title, $theme.colors.header.hoverTitle, $theme.colors.header.bg, $theme.colors.header.border, $theme.colors.button.primary.bg, $theme.colors.button.primary.text, $theme.colors.button.primary.hoverBg, $theme.colors.button.primary.hoverBg, $theme.colors.button.primary.activeOutline, $theme.colors.button.primary.disabledBg, $theme.colors.button.link.text, $theme.colors.button.secondary.bg, $theme.colors.button.secondary.text, $theme.colors.button.secondary.outline, $theme.colors.button.tertiary.text, $theme.colors.button.tertiary.outline, $theme.colors.button.tertiary.hoverOutline, $theme.colors.button.tertiary.hoverText, $theme.colors.button.tertiary.activeOutline, $theme.colors.button.tertiary.hoverText, $theme.colors.button.tertiary.disabledText, $theme.colors.button.tertiary.activatedText, $theme.colors.button.tertiary.activatedBg, $theme.colors.button.tertiary.activatedOutline, $theme.colors.toolbar.buttonBg, $theme.colors.controlPanel.bg, $theme.colors.controlPanel.border, $theme.colors.controlPanel.sectionText, $theme.colors.controlPanel.text, $theme.colors.controlPanel.sectionBg, $theme.colors.controlPanel.drawerBg, $theme.colors.controlPanel.rampSlider, $theme.colors.controlPanel.isovalueSlider, $theme.colors.landingPage.bg, $theme.colors.landingPage.bgAlt, $theme.colors.landingPage.text, $theme.colors.landingPage.bannerBg, $theme.colors.statusFlag.border, $theme.colors.statusFlag.text, $theme.colors.alert.warning.text, $theme.colors.alert.warning.bg, $theme.colors.alert.info.text, $theme.colors.alert.info.bg, $theme.colors.layout.dividers, $theme.colors.modal.border, $theme.colors.menu.hoverText, $theme.colors.menu.selectedText, $theme.colors.checkbox.bg, $theme.fonts.family);
155
+ return css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n /* Component and color variables. */\n // TODO: Fix inconsistent use of border vs. outline\n // TODO: Remove variables that aren't used in other CSS files. These should be set directly\n // from the $theme object to reduce unnecessary variables.\n --color-text-link: ", ";\n --color-text-header: ", ";\n --color-text-section: ", ";\n --color-text-body: ", ";\n --color-text-error: ", ";\n\n --color-text-selection-bg: ", ";\n --color-text-selection-text: ", ";\n\n --color-header-title: ", ";\n --color-header-hover-title: ", ";\n --color-header-bg: ", ";\n --color-header-border: ", ";\n\n --color-button-primary-bg: ", ";\n --color-button-primary-text: ", ";\n --color-button-primary-hover-bg: ", ";\n --color-button-primary-active-bg: ", ";\n --color-button-primary-active-outline: ", ";\n --color-button-primary-disabled-bg: ", ";\n\n --color-button-link-text: ", ";\n\n --color-button-secondary-bg: ", ";\n --color-button-secondary-text: ", ";\n --color-button-secondary-outline: ", ";\n\n --color-button-tertiary-bg: transparent;\n --color-button-tertiary-text: ", ";\n --color-button-tertiary-outline: ", ";\n --color-button-tertiary-hover-outline: ", ";\n --color-button-tertiary-hover-text: ", ";\n --color-button-tertiary-active-outline: ", ";\n --color-button-tertiary-active-text: ", ";\n\n --color-button-icon-disabled-outline: ", ";\n --color-button-icon-disabled-text: ", ";\n --color-button-icon-active-text: ", ";\n --color-button-icon-active-bg: ", ";\n --color-button-icon-active-outline: ", ";\n\n --color-toolbar-button-bg: ", ";\n\n --color-controlpanel-bg: ", ";\n --color-controlpanel-border: ", ";\n --color-controlpanel-section-text: ", ";\n --color-controlpanel-text: ", ";\n --color-controlpanel-section-bg: ", ";\n --color-controlpanel-drawer-bg: ", ";\n --color-controlpanel-ramp-slider: ", ";\n --color-controlpanel-isovalue-slider: ", ";\n\n --color-landingpage-bg: ", ";\n --color-landingpage-bg-alt: ", ";\n --color-landingpage-text: ", ";\n --color-landingpage-banner-highlight-bg: ", ";\n\n --color-statusflag-border: ", ";\n --color-statusflag-text: ", ";\n\n --color-alert-warning-text: ", ";\n --color-alert-warning-bg: ", ";\n --color-alert-info-text: ", ";\n --color-alert-info-bg: ", ";\n\n --color-layout-dividers: ", ";\n\n --color-modal-border: ", ";\n\n --color-menu-hover-text: ", ";\n --color-menu-selected-text: ", ";\n\n --color-checkbox-bg: ", ";\n\n --font-family: ", ";\n "])), $theme.colors.text.link, $theme.colors.text.header, $theme.colors.text.section, $theme.colors.text.body, $theme.colors.text.error, $theme.colors.text.selectionBg, $theme.colors.text.selectionText, $theme.colors.header.title, $theme.colors.header.hoverTitle, $theme.colors.header.bg, $theme.colors.header.border, $theme.colors.button.primary.bg, $theme.colors.button.primary.text, $theme.colors.button.primary.hoverBg, $theme.colors.button.primary.hoverBg, $theme.colors.button.primary.activeOutline, $theme.colors.button.primary.disabledBg, $theme.colors.button.link.text, $theme.colors.button.secondary.bg, $theme.colors.button.secondary.text, $theme.colors.button.secondary.outline, $theme.colors.button.tertiary.text, $theme.colors.button.tertiary.outline, $theme.colors.button.tertiary.hoverOutline, $theme.colors.button.tertiary.hoverText, $theme.colors.button.tertiary.activeOutline, $theme.colors.button.tertiary.hoverText, $theme.colors.button.tertiary.disabledOutline, $theme.colors.button.tertiary.disabledText, $theme.colors.button.tertiary.activeText, $theme.colors.button.tertiary.activeBg, $theme.colors.button.tertiary.activeOutline, $theme.colors.toolbar.buttonBg, $theme.colors.controlPanel.bg, $theme.colors.controlPanel.border, $theme.colors.controlPanel.sectionText, $theme.colors.controlPanel.text, $theme.colors.controlPanel.sectionBg, $theme.colors.controlPanel.drawerBg, $theme.colors.controlPanel.rampSlider, $theme.colors.controlPanel.isovalueSlider, $theme.colors.landingPage.bg, $theme.colors.landingPage.bgAlt, $theme.colors.landingPage.text, $theme.colors.landingPage.bannerBg, $theme.colors.statusFlag.border, $theme.colors.statusFlag.text, $theme.colors.alert.warning.text, $theme.colors.alert.warning.bg, $theme.colors.alert.info.text, $theme.colors.alert.info.bg, $theme.colors.layout.dividers, $theme.colors.modal.border, $theme.colors.menu.hoverText, $theme.colors.menu.selectedText, $theme.colors.checkbox.bg, $theme.fonts.family);
156
156
  });
157
+ var GlobalTooltipStyle = createGlobalStyle(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n .ant-tooltip-inner {\n display: flex;\n flex-direction: column;\n justify-content: center;\n /* !important needed: antd hardcodes text-align: start on tooltip inner */\n text-align: center !important;\n line-height: 1.4;\n font-weight: 400;\n /* !important needed: antd's CSS-in-JS injects tooltip styles into portals at higher specificity than global stylesheets */\n box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.30), 0 3px 6px -4px rgba(0, 0, 0, 0.40), 0 9px 28px 8px rgba(0, 0, 0, 0.20) !important;\n }\n\n"])));
157
158
 
158
159
  /**
159
160
  * Provides CSS variables and global styling for the image viewer.
@@ -192,7 +193,14 @@ export default function StyleProvider(props) {
192
193
  primaryColor: theme.colors.button.primary.text,
193
194
  defaultHoverBg: theme.colors.button.secondary.bg,
194
195
  defaultActiveBg: theme.colors.button.secondary.bg,
195
- defaultActiveBorderColor: theme.colors.button.tertiary.activeOutline
196
+ defaultActiveBorderColor: theme.colors.button.primary.activeOutline
197
+ },
198
+ Checkbox: {
199
+ borderRadiusSM: 2,
200
+ colorBgContainer: theme.colors.checkbox.bg,
201
+ colorPrimary: theme.colors.checkbox.bg,
202
+ colorPrimaryHover: theme.colors.checkbox.hoverBg,
203
+ colorText: theme.colors.checkbox.text
196
204
  },
197
205
  Collapse: {
198
206
  borderRadiusLG: 0,
@@ -205,26 +213,38 @@ export default function StyleProvider(props) {
205
213
  Layout: {
206
214
  siderBg: theme.colors.controlPanel.bg
207
215
  },
208
- Checkbox: {
209
- borderRadiusSM: 2,
210
- colorBgContainer: theme.colors.checkbox.bg,
211
- colorPrimary: theme.colors.checkbox.bg,
212
- colorPrimaryHover: theme.colors.checkbox.hoverBg,
213
- colorText: theme.colors.checkbox.text
214
- },
215
- Tooltip: {
216
- colorBgSpotlight: theme.colors.tooltip.bg
217
- },
218
216
  Modal: {
219
217
  colorBgMask: theme.colors.modal.maskBg,
220
218
  contentBg: theme.colors.modal.bg,
221
219
  headerBg: theme.colors.modal.bg,
222
220
  footerBg: theme.colors.modal.bg,
223
221
  titleFontSize: 19
222
+ },
223
+ Radio: {
224
+ buttonCheckedBg: theme.colors.button.tertiary.activeBg,
225
+ buttonColor: theme.colors.button.tertiary.text,
226
+ // can't style borders and text of activated buttons independently within ant's system, so we set border
227
+ // colors here and text/bg colors in custom css
228
+ colorPrimary: theme.colors.button.tertiary.activeOutline
229
+ },
230
+ Select: {
231
+ colorText: theme.colors.button.tertiary.text,
232
+ colorBorder: theme.colors.button.tertiary.outline,
233
+ // arrow color
234
+ colorTextQuaternary: theme.colors.button.tertiary.text,
235
+ colorTextDisabled: theme.colors.button.tertiary.disabledText,
236
+ colorTextPlaceholder: theme.colors.button.tertiary.hoverText,
237
+ colorBgContainerDisabled: "transparent"
238
+ },
239
+ // Additional tooltip overrides (font-weight, box-shadow, layout) are in GlobalTooltipStyle below,
240
+ // which is required because antd renders tooltips in portals outside the scoped CssProvider.
241
+ Tooltip: {
242
+ colorBgSpotlight: theme.colors.tooltip.bg,
243
+ fontSize: 12
224
244
  }
225
245
  }
226
246
  }
227
- }, /*#__PURE__*/React.createElement(CssProvider, {
247
+ }, /*#__PURE__*/React.createElement(GlobalTooltipStyle, null), /*#__PURE__*/React.createElement(CssProvider, {
228
248
  $theme: theme
229
249
  }, props.children));
230
250
  }
@@ -317,6 +317,7 @@ var TfEditor = function TfEditor(props) {
317
317
  colorPickerPosition = _useState8[0],
318
318
  setColorPickerPosition = _useState8[1];
319
319
  var lastColorRef = useRef(TFEDITOR_DEFAULT_COLOR);
320
+ var dropdownContainerRef = useRef(null);
320
321
  var svgRef = useRef(null); // need access to SVG element to measure mouse position
321
322
 
322
323
  var histogram = props.channelData.histogram;
@@ -765,7 +766,9 @@ var TfEditor = function TfEditor(props) {
765
766
  }
766
767
  })))), props.volumeEnabled && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h4", null, "Volume settings"), /*#__PURE__*/React.createElement("div", {
767
768
  className: "tf-editor-control-row"
768
- }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Dropdown, {
769
+ }, /*#__PURE__*/React.createElement("div", {
770
+ ref: dropdownContainerRef
771
+ }, /*#__PURE__*/React.createElement(Dropdown, {
769
772
  trigger: ["click"],
770
773
  menu: {
771
774
  items: [{
@@ -785,6 +788,10 @@ var TfEditor = function TfEditor(props) {
785
788
  var key = _ref5.key;
786
789
  return applyTFGenerator(key);
787
790
  }
791
+ },
792
+ getPopupContainer: function getPopupContainer() {
793
+ var _dropdownContainerRef;
794
+ return (_dropdownContainerRef = dropdownContainerRef.current) !== null && _dropdownContainerRef !== void 0 ? _dropdownContainerRef : document.body;
788
795
  }
789
796
  }, /*#__PURE__*/React.createElement(Button, {
790
797
  size: "small"
@@ -4,8 +4,6 @@ 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
- // TODO this really ought to be exported at the top level...
8
-
9
7
  import { ReloadOutlined } from "@ant-design/icons";
10
8
  import { Button, Radio, Select, Tooltip } from "antd";
11
9
  import { debounce } from "lodash";
@@ -35,6 +33,7 @@ var Toolbar = function Toolbar(props) {
35
33
  var leftRef = React.useRef(null);
36
34
  var rightRef = React.useRef(null);
37
35
  var centerRef = React.useRef(null);
36
+ var resizeObserver = React.useRef();
38
37
  var _React$useState = React.useState(false),
39
38
  _React$useState2 = _slicedToArray(_React$useState, 2),
40
39
  scrollMode = _React$useState2[0],
@@ -65,7 +64,7 @@ var Toolbar = function Toolbar(props) {
65
64
  return;
66
65
  }
67
66
  setScrollBtnLeft(barEl.scrollLeft > 0);
68
- setScrollBtnRight(barEl.scrollLeft < barEl.scrollWidth - barEl.clientWidth);
67
+ setScrollBtnRight(Math.ceil(barEl.scrollLeft) < barEl.scrollWidth - barEl.clientWidth);
69
68
  }, []);
70
69
 
71
70
  // This is effectively a `useCallback` - it memoizes a function - but since we're feeding the whole function into
@@ -93,15 +92,30 @@ var Toolbar = function Toolbar(props) {
93
92
  return leftRect.right > centerRect.left || centerRect.right > rightRect.left;
94
93
  }
95
94
  });
96
- checkScrollBtnVisible();
95
+ window.setTimeout(checkScrollBtnVisible, 0);
97
96
  }, RESIZE_DEBOUNCE_DELAY);
98
97
  }, [checkScrollBtnVisible]);
99
98
  React.useEffect(function () {
100
99
  // Make sure `checkSize` is run once on mount
101
100
  checkSize();
101
+ if (resizeObserver.current !== undefined) {
102
+ resizeObserver.current.disconnect();
103
+ }
104
+ resizeObserver.current = new ResizeObserver(checkSize);
105
+ if (leftRef.current !== null) {
106
+ resizeObserver.current.observe(leftRef.current);
107
+ }
108
+ if (centerRef.current !== null) {
109
+ resizeObserver.current.observe(centerRef.current);
110
+ }
111
+ if (rightRef.current !== null) {
112
+ resizeObserver.current.observe(rightRef.current);
113
+ }
102
114
  window.addEventListener("resize", checkSize);
103
115
  return function () {
104
- return window.removeEventListener("resize", checkSize);
116
+ var _resizeObserver$curre;
117
+ (_resizeObserver$curre = resizeObserver.current) === null || _resizeObserver$curre === void 0 || _resizeObserver$curre.disconnect();
118
+ window.removeEventListener("resize", checkSize);
105
119
  };
106
120
  }, [checkSize]);
107
121
  var scrollX = function scrollX(amount) {
@@ -126,7 +140,8 @@ var Toolbar = function Toolbar(props) {
126
140
  var classForToggleBtn = function classForToggleBtn(active) {
127
141
  return "ant-btn-icon-only btn-borderless" + (active ? " btn-active" : "");
128
142
  };
129
- var visibleControls = props.visibleControls;
143
+ var visibleControls = props.visibleControls,
144
+ multiscaleDims = props.multiscaleDims;
130
145
  var twoDMode = viewMode !== ViewMode.threeD;
131
146
  var renderGroup1 = visibleControls.viewModeRadioButtons || visibleControls.resetCameraButton || visibleControls.autoRotateButton;
132
147
  var renderGroup4 = visibleControls.showAxesButton || visibleControls.showBoundingBoxButton;
@@ -214,8 +229,9 @@ var Toolbar = function Toolbar(props) {
214
229
  }, "Full field"))), /*#__PURE__*/React.createElement("div", {
215
230
  className: "viewer-toolbar-group"
216
231
  }, /*#__PURE__*/React.createElement(Select, {
217
- className: "select-render-setting",
218
- popupClassName: "viewer-toolbar-dropdown",
232
+ style: {
233
+ minWidth: 120
234
+ },
219
235
  value: renderMode,
220
236
  onChange: function onChange(value) {
221
237
  return changeViewerSetting("renderMode", value);
@@ -249,9 +265,13 @@ var Toolbar = function Toolbar(props) {
249
265
  onClick: toggleBoundingBox
250
266
  }, /*#__PURE__*/React.createElement(ViewerIcon, {
251
267
  type: "boundingBox"
252
- })))), props.multiscaleDims !== undefined && props.multiscaleDims.length > 1 && /*#__PURE__*/React.createElement("div", {
268
+ })))), multiscaleDims !== undefined && multiscaleDims.length > 1 && visibleControls.scaleLevelControls && /*#__PURE__*/React.createElement("div", {
253
269
  className: "viewer-toolbar-group"
254
- }, /*#__PURE__*/React.createElement("span", null, "Resolution"), /*#__PURE__*/React.createElement(Radio.Group, {
270
+ }, /*#__PURE__*/React.createElement("span", {
271
+ style: {
272
+ color: "var(--color-button-tertiary-text)"
273
+ }
274
+ }, "Resolution"), /*#__PURE__*/React.createElement(Radio.Group, {
255
275
  value: useExactScaleLevel,
256
276
  onChange: function onChange(e) {
257
277
  return changeViewerSetting("useExactScaleLevel", e.target.value);
@@ -261,7 +281,8 @@ var Toolbar = function Toolbar(props) {
261
281
  }, "Auto"), /*#__PURE__*/React.createElement(Radio.Button, {
262
282
  value: true
263
283
  }, "Manual")), /*#__PURE__*/React.createElement(Select, {
264
- className: "select-render-setting",
284
+ className: "select-resolution",
285
+ getPopupContainer: getPopupContainer,
265
286
  style: {
266
287
  minWidth: 150
267
288
  },
@@ -270,7 +291,7 @@ var Toolbar = function Toolbar(props) {
270
291
  return changeViewerSetting("scaleLevelIndex", value);
271
292
  },
272
293
  disabled: !useExactScaleLevel
273
- }, props.multiscaleDims.map(function (dims, idx) {
294
+ }, multiscaleDims.map(function (dims, idx) {
274
295
  var _dims$shape = _slicedToArray(dims.shape, 5),
275
296
  _t = _dims$shape[0],
276
297
  _c = _dims$shape[1],