@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
@@ -17,6 +17,7 @@ import CustomizeWidget from "../CustomizeWidget";
17
17
  import GlobalVolumeControls from "../GlobalVolumeControls";
18
18
  import MetadataViewer from "../MetadataViewer";
19
19
  import ViewerIcon from "../shared/ViewerIcon";
20
+ import CopySettingsButton from "./CopySettingsButton";
20
21
  import "./styles.css";
21
22
  var ControlTab = /*#__PURE__*/function (ControlTab) {
22
23
  ControlTab[ControlTab["Channels"] = 0] = "Channels";
@@ -38,6 +39,7 @@ function ControlPanel(props) {
38
39
  var singleChannelMode = useViewerState(select("singleChannelMode"));
39
40
  var changeViewerSetting = useViewerState(select("changeViewerSetting"));
40
41
  var containerRef = React.useRef(null);
42
+ var columnRef = React.useRef(null);
41
43
  var getDropdownContainer = function getDropdownContainer() {
42
44
  var _containerRef$current;
43
45
  return (_containerRef$current = containerRef.current) !== null && _containerRef$current !== void 0 ? _containerRef$current : document.body;
@@ -184,10 +186,16 @@ function ControlPanel(props) {
184
186
  className: "control-panel-col",
185
187
  style: {
186
188
  flex: "0 0 450px"
187
- }
188
- }, /*#__PURE__*/React.createElement("h2", {
189
- className: "control-panel-title"
190
- }, ControlTabNames[tab]), visibleControls.colorPresetsDropdown && tab === ControlTab.Channels && renderChannelSettingsHeader(), hasImage && /*#__PURE__*/React.createElement("div", {
189
+ },
190
+ ref: columnRef
191
+ }, /*#__PURE__*/React.createElement("div", {
192
+ className: "control-panel-title-container"
193
+ }, /*#__PURE__*/React.createElement("h2", null, ControlTabNames[tab]), tab === ControlTab.Channels && /*#__PURE__*/React.createElement(CopySettingsButton, {
194
+ imageName: props.imageName,
195
+ scrollContainer: columnRef.current,
196
+ hide: props.collapsed,
197
+ getDropdownContainer: getDropdownContainer
198
+ })), visibleControls.colorPresetsDropdown && tab === ControlTab.Channels && renderChannelSettingsHeader(), hasImage && /*#__PURE__*/React.createElement("div", {
191
199
  className: "control-panel-content"
192
200
  }, tab === ControlTab.Channels && /*#__PURE__*/React.createElement(ChannelsWidget, {
193
201
  channelDataChannels: props.channelDataChannels,
@@ -196,7 +204,10 @@ function ControlPanel(props) {
196
204
  onColorChangeComplete: props.onColorChangeComplete,
197
205
  onApplyColorPresets: props.onApplyColorPresets,
198
206
  filterFunc: props.filterFunc,
199
- viewerChannelSettings: viewerChannelSettings
207
+ viewerChannelSettings: viewerChannelSettings,
208
+ getDropdownContainer: getDropdownContainer,
209
+ scrollContainer: columnRef.current,
210
+ controlPanelCollapsed: props.collapsed
200
211
  }), tab === ControlTab.Advanced && renderAdvancedSettings(), tab === ControlTab.Metadata && /*#__PURE__*/React.createElement(MetadataViewer, {
201
212
  metadata: props.metadata
202
213
  }))));
@@ -57,12 +57,18 @@
57
57
  display:none;
58
58
  }
59
59
 
60
- .control-panel-col-container .control-panel-col .control-panel-title{
60
+ .control-panel-col-container .control-panel-col .control-panel-title-container{
61
61
  margin:16px;
62
62
  max-height:24px;
63
- font-size:1.4em;
63
+ display:flex;
64
+ align-items:center;
65
+ justify-content:space-between;
64
66
  }
65
67
 
68
+ .control-panel-col-container .control-panel-col .control-panel-title-container > *{
69
+ font-size:1.4em;
70
+ }
71
+
66
72
  .control-panel-col-container .control-panel-col .channel-settings-header{
67
73
  margin:0 16px 16px;
68
74
  display:flex;
@@ -177,3 +183,24 @@
177
183
  font-size:10px;
178
184
  top:calc(100% + 3px);
179
185
  }
186
+
187
+ .control-panel-col-container .ant-modal.modal-settings-import .ant-upload.ant-upload-drag{
188
+ transition-property:background-color, border-color;
189
+ }
190
+
191
+ .control-panel-col-container .ant-modal.modal-settings-import .ant-upload.ant-upload-drag:hover{
192
+ background-color:#ffffff20;
193
+ }
194
+
195
+ .control-panel-col-container .ant-dropdown .import-dropdown-menu-item-include-color{
196
+ white-space:nowrap;
197
+ padding-bottom:9px;
198
+ }
199
+
200
+ .control-panel-col-container .ant-dropdown .import-dropdown-menu-item-include-color.ant-dropdown-menu-item-active{
201
+ background-color:transparent;
202
+ }
203
+
204
+ .control-panel-col-container .ant-dropdown .ant-dropdown-menu-item-divider{
205
+ background-color:var(--color-controlpanel-border);
206
+ }
@@ -20,7 +20,8 @@ var palette = {
20
20
  veryLtPurple: "#e7e4f2",
21
21
  brightRed: "#dc4446",
22
22
  brightYellow: "#e39b0d",
23
- brightGreen: "#61d900",
23
+ darkGreen: "#294c2f",
24
+ brightGreen: "#0ccf4d",
24
25
  veryBrightGreen: "#61ff00",
25
26
  brightBlue: "#0099ff",
26
27
  veryBrightBlue: "#0dc4d9",
@@ -126,6 +127,10 @@ var theme = {
126
127
  textPlaceholder: palette.ltPurple
127
128
  },
128
129
  alert: {
130
+ success: {
131
+ text: palette.brightGreen,
132
+ bg: palette.darkGreen
133
+ },
129
134
  warning: {
130
135
  text: palette.brightYellow,
131
136
  bg: palette.darkYellow
@@ -150,7 +155,7 @@ var theme = {
150
155
  }
151
156
  };
152
157
  /** 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 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) {
158
+ 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"])), function (_ref) {
154
159
  var $theme = _ref.$theme;
155
160
  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
161
  });
@@ -172,6 +177,10 @@ export default function StyleProvider(props) {
172
177
  colorBgContainer: "transparent",
173
178
  colorSplit: theme.colors.layout.split,
174
179
  colorPrimaryTextHover: theme.colors.text.selectionText,
180
+ colorSuccess: theme.colors.alert.success.text,
181
+ colorSuccessBg: theme.colors.alert.success.bg,
182
+ colorSuccessBorder: theme.colors.alert.success.text,
183
+ colorSuccessText: theme.colors.alert.success.text,
175
184
  colorWarning: theme.colors.alert.warning.text,
176
185
  colorWarningBg: theme.colors.alert.warning.bg,
177
186
  colorWarningBorder: theme.colors.alert.warning.text,
@@ -236,11 +245,17 @@ export default function StyleProvider(props) {
236
245
  colorTextPlaceholder: theme.colors.button.tertiary.hoverText,
237
246
  colorBgContainerDisabled: "transparent"
238
247
  },
248
+ Tabs: {
249
+ horizontalItemPaddingLG: "5px 0"
250
+ },
239
251
  // Additional tooltip overrides (font-weight, box-shadow, layout) are in GlobalTooltipStyle below,
240
252
  // which is required because antd renders tooltips in portals outside the scoped CssProvider.
241
253
  Tooltip: {
242
254
  colorBgSpotlight: theme.colors.tooltip.bg,
243
255
  fontSize: 12
256
+ },
257
+ Upload: {
258
+ padding: 32
244
259
  }
245
260
  }
246
261
  }
@@ -1,6 +1,6 @@
1
1
  import { Radio } from "antd";
2
2
  import React from "react";
3
- import { ViewMode } from "../../shared/enums";
3
+ import { ViewMode } from "../../state/types";
4
4
  var viewModes = [ViewMode.threeD, ViewMode.xy, ViewMode.xz, ViewMode.yz];
5
5
  var ViewModeRadioButtons = function ViewModeRadioButtons(props) {
6
6
  var onChangeButton = function onChangeButton(_ref) {
@@ -8,8 +8,8 @@ import { ReloadOutlined } from "@ant-design/icons";
8
8
  import { Button, Radio, Select, Tooltip } from "antd";
9
9
  import { debounce } from "lodash";
10
10
  import React from "react";
11
- import { ImageType, RenderMode, ViewMode } from "../../shared/enums";
12
11
  import { select, useViewerState } from "../../state/store";
12
+ import { ImageType, RenderMode, ViewMode } from "../../state/types";
13
13
  import ViewerIcon from "../shared/ViewerIcon";
14
14
  import DownloadButton from "./DownloadButton";
15
15
  import ViewModeRadioButtons from "./ViewModeRadioButtons";
@@ -3,7 +3,6 @@
3
3
  width:100%;
4
4
  z-index:250;
5
5
  }
6
-
7
6
  .viewer-toolbar-container .viewer-toolbar-scroll-left,
8
7
  .viewer-toolbar-container .viewer-toolbar-scroll-right{
9
8
  height:100%;
@@ -17,28 +16,22 @@
17
16
  z-index:255;
18
17
  transition:color 0.3s;
19
18
  }
20
-
21
19
  .viewer-toolbar-container .viewer-toolbar-scroll-left:hover, .viewer-toolbar-container .viewer-toolbar-scroll-right:hover{
22
20
  color:white;
23
21
  }
24
-
25
22
  .viewer-toolbar-container .viewer-toolbar-scroll-left{
26
23
  left:0;
27
24
  }
28
-
29
25
  .viewer-toolbar-container .viewer-toolbar-scroll-right{
30
26
  right:0;
31
27
  }
32
-
33
28
  .viewer-toolbar-container.viewer-toolbar-scroll{
34
29
  border-bottom:1px solid var(--color-layout-dividers);
35
30
  }
36
-
37
31
  .viewer-toolbar-container.viewer-toolbar-scroll .viewer-toolbar-scroll-left,
38
32
  .viewer-toolbar-container.viewer-toolbar-scroll .viewer-toolbar-scroll-right{
39
33
  display:flex;
40
34
  }
41
-
42
35
  .viewer-toolbar-container.viewer-toolbar-scroll .viewer-toolbar{
43
36
  white-space:nowrap;
44
37
  justify-content:normal;
@@ -46,16 +39,13 @@
46
39
  overflow-x:scroll;
47
40
  scrollbar-width:none;
48
41
  }
49
-
50
42
  .viewer-toolbar-container.viewer-toolbar-scroll .viewer-toolbar::-webkit-scrollbar{
51
43
  display:none;
52
44
  }
53
-
54
45
  .viewer-toolbar-container.viewer-toolbar-scroll .viewer-toolbar .viewer-toolbar-left{
55
46
  position:static;
56
47
  margin-left:15px;
57
48
  }
58
-
59
49
  .viewer-toolbar-container.viewer-toolbar-scroll .viewer-toolbar .viewer-toolbar-right{
60
50
  position:static;
61
51
  margin-right:15px;
@@ -7,8 +7,8 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
7
7
  import { LoadingOutlined } from "@ant-design/icons";
8
8
  import React from "react";
9
9
  import { CLIPPING_PANEL_HEIGHT_DEFAULT, CLIPPING_PANEL_HEIGHT_TALL } from "../../shared/constants";
10
- import { ViewMode } from "../../shared/enums";
11
10
  import { select, useViewerState } from "../../state/store";
11
+ import { ViewMode } from "../../state/types";
12
12
  import BottomPanel from "../BottomPanel";
13
13
  import { AxisClipSliders } from "../dimension_sliders/AxisClipSliders";
14
14
  import { RotationSliders } from "../dimension_sliders/RotationSliders";
@@ -65,7 +65,8 @@ var ViewerWrapper = function ViewerWrapper(props) {
65
65
  time: time,
66
66
  scene: scene,
67
67
  playControls: props.playControls,
68
- playingAxis: props.playingAxis
68
+ playingAxis: props.playingAxis,
69
+ setScrubbingAxis: props.setScrubbingAxis
69
70
  })
70
71
  });
71
72
  }
@@ -25,13 +25,25 @@ export var AxisClipSliders = function AxisClipSliders(props) {
25
25
  changeViewerSetting("region", _defineProperty({}, axis, [start, end]));
26
26
  };
27
27
  var updateSlice = function updateSlice(axis, slice) {
28
+ var isScrubbing = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28
29
  pauseOnInput(axis);
30
+ if (isScrubbing) {
31
+ props.setScrubbingAxis(axis);
32
+ }
29
33
  props.changeViewerSetting("slice", _defineProperty({}, axis, slice / props.numSlices[axis]));
30
34
  };
31
35
  var updateTime = function updateTime(time) {
36
+ var isScrubbing = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
32
37
  pauseOnInput("t");
38
+ if (isScrubbing) {
39
+ props.setScrubbingAxis("t");
40
+ }
33
41
  props.changeViewerSetting("time", time);
34
42
  };
43
+ var endScrub = function endScrub() {
44
+ props.setScrubbingAxis(null);
45
+ props.playControls.endHold();
46
+ };
35
47
 
36
48
  // Pause when view mode or volume size has changed
37
49
  useEffect(function () {
@@ -54,20 +66,20 @@ export var AxisClipSliders = function AxisClipSliders(props) {
54
66
  label: axis.toUpperCase(),
55
67
  val: Math.round(props.slices[axis] * numSlices),
56
68
  max: numSlices,
69
+ onSlide: function onSlide(val) {
70
+ return updateSlice(axis, val, true);
71
+ },
57
72
  onChange: function onChange(val) {
58
73
  return updateSlice(axis, val);
59
74
  },
60
75
  onStart: function onStart() {
61
76
  return props.playControls.startHold(axis);
62
77
  },
63
- onEnd: function onEnd() {
64
- return props.playControls.endHold();
65
- },
78
+ onEnd: endScrub,
66
79
  playing: props.playingAxis === axis,
67
80
  onTogglePlayback: function onTogglePlayback(willPlay) {
68
81
  return handlePlayPause(axis, willPlay);
69
- },
70
- updateWhileSliding: numSlices === numSlicesLoaded
82
+ }
71
83
  }));
72
84
  };
73
85
  var create3dAxisSlider = function create3dAxisSlider(axis) {
@@ -119,15 +131,16 @@ export var AxisClipSliders = function AxisClipSliders(props) {
119
131
  onTogglePlayback: function onTogglePlayback(willPlay) {
120
132
  return handlePlayPause("t", willPlay);
121
133
  },
134
+ onSlide: function onSlide(time) {
135
+ return updateTime(time, true);
136
+ },
122
137
  onChange: function onChange(time) {
123
138
  return updateTime(time);
124
139
  },
125
140
  onStart: function onStart() {
126
141
  return props.playControls.startHold("t");
127
142
  },
128
- onEnd: function onEnd() {
129
- return props.playControls.endHold();
130
- }
143
+ onEnd: endScrub
131
144
  })))), props.numScenes > 1 && /*#__PURE__*/React.createElement("span", {
132
145
  className: "slider-group"
133
146
  }, /*#__PURE__*/React.createElement("span", {
@@ -12,9 +12,9 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
12
12
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
13
13
  import { Button, Space } from "antd";
14
14
  import React, { useCallback, useEffect, useRef, useState } from "react";
15
- import { ViewMode } from "../../shared/enums";
16
15
  import { applyMatrix, defaultOrientedCamera, getRotationAngles, rotationMatrix, useCameraCallback } from "../../shared/utils/camera";
17
16
  import { select, useViewerState } from "../../state/store";
17
+ import { ViewMode } from "../../state/types";
18
18
  import { DimensionSliderRow } from "./SliderRows";
19
19
 
20
20
  /** Convert an angle from degrees to radians */
@@ -100,21 +100,19 @@ export var RotationSliders = function RotationSliders(_ref) {
100
100
 
101
101
  // Set up event listeners on mount.
102
102
  useEffect(function () {
103
- // TODO this is *extremely brittle*: setting this clears away any other listener for render events.
104
- // At time of writing, `setOnRenderCallback` appears not to be used anywhere else in either this package or
105
- // vole-core, but that could change at any time.
106
- // Ideally `View3d` would have an `addEventListener`/`removeEventListener` model.
107
- view3d.setOnRenderCallback(function () {
103
+ var renderListener = function renderListener() {
108
104
  if (!hasControlRef.current) {
109
105
  setRotation(getRotationAngles(view3d.getCameraState()));
110
106
  }
111
- });
107
+ };
108
+ view3d.addEventListener("render", renderListener);
112
109
  var clickListener = function clickListener() {
113
110
  return hasControlRef.current = false;
114
111
  };
115
112
  view3d.getDOMElement().addEventListener("mousedown", clickListener);
116
113
  return function () {
117
- return view3d.getDOMElement().removeEventListener("mousedown", clickListener);
114
+ view3d.removeEventListener("render", renderListener);
115
+ view3d.getDOMElement().removeEventListener("mousedown", clickListener);
118
116
  };
119
117
  }, [view3d]);
120
118
  var createRotateSlider = function createRotateSlider(axis) {
@@ -116,6 +116,7 @@ export var IndexSliderRow = function IndexSliderRow(props) {
116
116
  /** Wrapper around `SliderRow` that adds a play button and accounts for the case where not all of an axis is loaded. */
117
117
  export var PlaySliderRow = function PlaySliderRow(props) {
118
118
  var onChange = props.onChange,
119
+ onSlide = props.onSlide,
119
120
  onStart = props.onStart,
120
121
  onEnd = props.onEnd;
121
122
  // In partially-loaded axes, stores the displayed value of the slider while the user is sliding it
@@ -131,9 +132,10 @@ export var PlaySliderRow = function PlaySliderRow(props) {
131
132
  var wrappedOnChange = useCallback(function (val) {
132
133
  return onChange === null || onChange === void 0 ? void 0 : onChange(val);
133
134
  }, [onChange]);
134
- var wrappedSetValReadout = useCallback(function (val) {
135
- return setValReadout(val);
136
- }, []);
135
+ var wrappedOnSlide = useCallback(function (val) {
136
+ setValReadout(val);
137
+ onSlide === null || onSlide === void 0 || onSlide(val);
138
+ }, [onSlide]);
137
139
  var wrappedOnStart = useCallback(function () {
138
140
  setValReadout(props.val);
139
141
  setSliderHeld(true);
@@ -146,10 +148,10 @@ export var PlaySliderRow = function PlaySliderRow(props) {
146
148
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(IndexSliderRow, {
147
149
  label: props.label,
148
150
  val: props.val,
149
- valReadout: props.updateWhileSliding || !sliderHeld ? undefined : valReadout,
151
+ valReadout: !sliderHeld ? undefined : valReadout,
150
152
  max: props.max,
151
- onSlide: props.updateWhileSliding ? wrappedOnChange : wrappedSetValReadout,
152
- onChange: props.updateWhileSliding ? undefined : wrappedOnChange,
153
+ onSlide: wrappedOnSlide,
154
+ onChange: wrappedOnChange,
153
155
  onStart: wrappedOnStart,
154
156
  onEnd: wrappedOnEnd
155
157
  }), props.max > 1 && /*#__PURE__*/React.createElement(Tooltip, {
@@ -0,0 +1,101 @@
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 _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); }
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
+ 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; }
6
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
7
+ 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); }
8
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
9
+ 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."); }
10
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
11
+ 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; }
12
+ 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; } }
13
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
14
+ import { Alert } from "antd";
15
+ import React from "react";
16
+ import { createPortal } from "react-dom";
17
+ var ALERT_STYLE = {
18
+ position: "absolute",
19
+ bottom: "auto",
20
+ right: "auto",
21
+ zIndex: 1000
22
+ };
23
+
24
+ /**
25
+ * Antd's `Alert`, but positioned immediately under a `target` element to provide contextual information.
26
+ *
27
+ * This is relatively specialized to the use case of attaching to components inside the control panel. Since the
28
+ * control panel can be vertically scrolled and hidden, it has specific props for responding to both.
29
+ */
30
+ export var ContextualAlert = function ContextualAlert(props) {
31
+ var message = props.message,
32
+ target = props.target,
33
+ scrollContainer = props.scrollContainer,
34
+ hide = props.hide;
35
+ var _React$useState = React.useState({
36
+ top: 0,
37
+ left: 0
38
+ }),
39
+ _React$useState2 = _slicedToArray(_React$useState, 2),
40
+ alertPosition = _React$useState2[0],
41
+ setAlertPosition = _React$useState2[1];
42
+ React.useEffect(function () {
43
+ var setPosition = function setPosition() {
44
+ if (target !== null) {
45
+ var rect = target.getBoundingClientRect();
46
+ setAlertPosition({
47
+ top: rect.bottom + 10,
48
+ left: rect.left
49
+ });
50
+ }
51
+ };
52
+ setPosition();
53
+ if (scrollContainer) {
54
+ scrollContainer.addEventListener("scroll", setPosition);
55
+ return function () {
56
+ return scrollContainer.removeEventListener("scroll", setPosition);
57
+ };
58
+ }
59
+ return undefined;
60
+ }, [scrollContainer, target]);
61
+ return /*#__PURE__*/createPortal(/*#__PURE__*/React.createElement("div", {
62
+ style: _objectSpread(_objectSpread(_objectSpread({}, ALERT_STYLE), alertPosition), {}, {
63
+ display: !message || hide ? "none" : "block"
64
+ })
65
+ }, /*#__PURE__*/React.createElement(Alert, props)), document.body);
66
+ };
67
+
68
+ /**
69
+ * Creates an `antd` `Alert` element that stays positioned beneath the `target` element, and a function to show
70
+ * time-limited messages in the `Alert`.
71
+ *
72
+ * This is relatively specialized to the use case of attaching to components inside the control panel. Since the
73
+ * control panel can be vertically scrolled and hidden, it has specific props for responding to both.
74
+ */
75
+ export var useContextualAlert = function useContextualAlert(target, options) {
76
+ var _React$useState3 = React.useState(undefined),
77
+ _React$useState4 = _slicedToArray(_React$useState3, 2),
78
+ message = _React$useState4[0],
79
+ setMessage = _React$useState4[1];
80
+ var _React$useState5 = React.useState(undefined),
81
+ _React$useState6 = _slicedToArray(_React$useState5, 2),
82
+ messageType = _React$useState6[0],
83
+ setMessageType = _React$useState6[1];
84
+ var messageTimeoutRef = React.useRef(undefined);
85
+ var showMessage = React.useCallback(function (message, messageType) {
86
+ if (messageTimeoutRef.current !== undefined) {
87
+ window.clearTimeout(messageTimeoutRef.current);
88
+ }
89
+ messageTimeoutRef.current = window.setTimeout(function () {
90
+ return setMessage(undefined);
91
+ }, options.timeout);
92
+ setMessage(message);
93
+ setMessageType(messageType);
94
+ }, [options.timeout]);
95
+ var alert = /*#__PURE__*/React.createElement(ContextualAlert, _extends({
96
+ message: message,
97
+ target: target,
98
+ type: messageType !== null && messageType !== void 0 ? messageType : "success"
99
+ }, options));
100
+ return [alert, showMessage];
101
+ };
@@ -31,7 +31,7 @@ var ControlPanelRow = function ControlPanelRow(inputProps) {
31
31
  var style = {
32
32
  "--control-panel-row-vertical-margin": props.verticalMargin + "px"
33
33
  };
34
- var createTitle = props.title !== undefined || props.showColorPicker;
34
+ var createTitle = props.title !== undefined || props.icon !== undefined || props.showColorPicker;
35
35
  var baseClass = "control-panel-row".concat(props.highlight ? " control-panel-row-highlight" : "");
36
36
  var className = props.className ? "".concat(baseClass, " ").concat(props.className) : baseClass;
37
37
  return /*#__PURE__*/React.createElement("div", {
@@ -40,7 +40,9 @@ var ControlPanelRow = function ControlPanelRow(inputProps) {
40
40
  onClick: props.onClick
41
41
  }, createTitle && /*#__PURE__*/React.createElement("div", {
42
42
  className: "control-panel-row-title"
43
- }, props.showColorPicker && /*#__PURE__*/React.createElement(ColorPicker, _extends({
43
+ }, props.icon && /*#__PURE__*/React.createElement("div", {
44
+ className: "control-panel-row-icon"
45
+ }, props.icon), props.showColorPicker && /*#__PURE__*/React.createElement(ColorPicker, _extends({
44
46
  disableAlpha: true,
45
47
  width: 18
46
48
  }, colorPickerProps)), props.title && /*#__PURE__*/React.createElement("h4", null, props.title)), props.children);
@@ -16,8 +16,10 @@
16
16
  flex-grow:1;
17
17
  }
18
18
 
19
- .control-panel-col .control-panel-row .control-panel-row-title .color-picker{
20
- margin-right:16px;
19
+ .control-panel-col .control-panel-row .control-panel-row-title .color-picker,
20
+ .control-panel-col .control-panel-row .control-panel-row-title .control-panel-row-icon{
21
+ margin-right:10px;
22
+ font-size:12px;
21
23
  }
22
24
 
23
25
  .control-panel-col .control-panel-row .control-panel-row-title h4{
@@ -58,7 +60,6 @@
58
60
  width:100%;
59
61
  border-bottom:1px solid var(--color-controlpanel-border);
60
62
  }
61
-
62
63
  .control-panel-col .ant-collapse-item:not(:last-child) .control-panel-row:last-child::after{
63
64
  border-bottom:none;
64
65
  }