diff --git a/docs/latest/advanced/extensions.md b/docs/latest/advanced/extensions.md
index b2c8b71a6..d9e1718e4 100644
--- a/docs/latest/advanced/extensions.md
+++ b/docs/latest/advanced/extensions.md
@@ -160,6 +160,7 @@ An extension can register a Toolbar Module by providing a `getToolbarModule()`
method that returns a React Component. The component does not receive any props.
If you want to modify or react to state, you will need to connect to the redux
store.
+The given toolbar must determine its set of elements and the context of them. The set of elements will be listed on toolbar `definitions`.

@@ -170,6 +171,31 @@ Toolbar components are rendered in the `ToolbarRow` component.
For a complete example implementation,
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/toolbarModule.js).
+##### Toolbar Custom Component
+
+Toolbar elements can define its own custom react component to be consumed when rendering it. So far, it accepts `Functional` and `Class` Components. For that, you just need to expose your `CustomToolbarComponent` as the value of key `CustomComponent`. In case the property `CustomComponent` is not present, a default toolbar component will be used to render it. See bellow
+
+```js
+definitions: [
+...
+ {
+ id: 'Custom',
+ label: 'Custom',
+ icon: 'custom-icon',
+ CustomComponent: CustomToolbarComponent,
+ }
+...
+]
+
+```
+`CustomComponent` components will receive the following props:
+- parentContext: parent context. (In most of the cases it will be a ToolbarRow instance)
+- toolbarClickCallback: callback method when clicking on toolbar
+- button: its own definition object
+- key: react key prop
+- activeButtons: list of active elements
+- isActive: if current
+
#### SopClassHandler
...
diff --git a/platform/viewer/src/connectedComponents/ToolbarRow.js b/platform/viewer/src/connectedComponents/ToolbarRow.js
index 0ddad8b7c..1612f44e0 100644
--- a/platform/viewer/src/connectedComponents/ToolbarRow.js
+++ b/platform/viewer/src/connectedComponents/ToolbarRow.js
@@ -150,45 +150,82 @@ class ToolbarRow extends Component {
}
}
+function _getCustomButtonComponent(button, activeButtons) {
+ const CustomComponent = button.CustomComponent;
+ const isValidComponent = typeof CustomComponent === 'function';
+
+ // Check if its a valid customComponent. Later on an CustomToolbarComponent interface could be implemented.
+ if (isValidComponent) {
+ const parentContext = this;
+ const isActive = activeButtons.includes(button.id);
+
+ return (
+
+ );
+ }
+}
+
+function _getExpandableButtonComponent(button, activeButtons) {
+ // Iterate over button definitions and update `onClick` behavior
+ let activeCommand;
+ const childButtons = button.buttons.map(childButton => {
+ childButton.onClick = _handleToolbarButtonClick.bind(this, childButton);
+
+ if (activeButtons.indexOf(childButton.id) > -1) {
+ activeCommand = childButton.id;
+ }
+
+ return childButton;
+ });
+
+ return (
+
+ );
+}
+
+function _getDefaultButtonComponent(button, activeButtons) {
+ return (
+
+ );
+}
/**
* Determine which extension buttons should be showing, if they're
* active, and what their onClick behavior should be.
*/
function _getButtonComponents(toolbarButtons, activeButtons) {
- return toolbarButtons.map((button, index) => {
- let activeCommand = undefined;
+ const _this = this;
+ return toolbarButtons.map(button => {
+ const hasCustomComponent = button.CustomComponent;
+ const hasNestedButtonDefinitions = button.buttons && button.buttons.length;
- if (button.buttons && button.buttons.length) {
- // Iterate over button definitions and update `onClick` behavior
- const childButtons = button.buttons.map(childButton => {
- childButton.onClick = _handleToolbarButtonClick.bind(this, childButton);
-
- if (activeButtons.indexOf(childButton.id) > -1) {
- activeCommand = childButton.id;
- }
-
- return childButton;
- });
-
- return (
-
- );
+ if (hasCustomComponent) {
+ return _getCustomButtonComponent.call(_this, button, activeButtons);
}
- return (
-
- );
+
+ if (hasNestedButtonDefinitions) {
+ return _getExpandableButtonComponent.call(_this, button, activeButtons);
+ }
+
+ return _getDefaultButtonComponent.call(_this, button, activeButtons);
});
}