feat: 🎸 React custom component on toolbar button (#935)
* feat: 🎸 React custom component on toolbar button Toolbar button can consume/render react custom components. Its only required to expose the component into toolbar definitions (toolbarModule) Closes: 924 * feat: 🎸 Core review. Minor changes on documentation Closes: 924 * feat: 🎸 Code review * feat: 🎸 Code review. Changing function call to variable decl
This commit is contained in:
parent
5b523c2afa
commit
a90605c82d
@ -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.
|
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
|
If you want to modify or react to state, you will need to connect to the redux
|
||||||
store.
|
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,
|
For a complete example implementation,
|
||||||
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/toolbarModule.js).
|
[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
|
#### SopClassHandler
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
@ -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 (
|
||||||
|
<CustomComponent
|
||||||
|
parentContext={parentContext}
|
||||||
|
toolbarClickCallback={_handleToolbarButtonClick.bind(this)}
|
||||||
|
button={button}
|
||||||
|
key={button.id}
|
||||||
|
activeButtons={activeButtons}
|
||||||
|
isActive={isActive}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<ExpandableToolMenu
|
||||||
|
key={button.id}
|
||||||
|
label={button.label}
|
||||||
|
icon={button.icon}
|
||||||
|
buttons={childButtons}
|
||||||
|
activeCommand={activeCommand}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getDefaultButtonComponent(button, activeButtons) {
|
||||||
|
return (
|
||||||
|
<ToolbarButton
|
||||||
|
key={button.id}
|
||||||
|
label={button.label}
|
||||||
|
icon={button.icon}
|
||||||
|
onClick={_handleToolbarButtonClick.bind(this, button)}
|
||||||
|
isActive={activeButtons.includes(button.id)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Determine which extension buttons should be showing, if they're
|
* Determine which extension buttons should be showing, if they're
|
||||||
* active, and what their onClick behavior should be.
|
* active, and what their onClick behavior should be.
|
||||||
*/
|
*/
|
||||||
function _getButtonComponents(toolbarButtons, activeButtons) {
|
function _getButtonComponents(toolbarButtons, activeButtons) {
|
||||||
return toolbarButtons.map((button, index) => {
|
const _this = this;
|
||||||
let activeCommand = undefined;
|
return toolbarButtons.map(button => {
|
||||||
|
const hasCustomComponent = button.CustomComponent;
|
||||||
|
const hasNestedButtonDefinitions = button.buttons && button.buttons.length;
|
||||||
|
|
||||||
if (button.buttons && button.buttons.length) {
|
if (hasCustomComponent) {
|
||||||
// Iterate over button definitions and update `onClick` behavior
|
return _getCustomButtonComponent.call(_this, button, activeButtons);
|
||||||
const childButtons = button.buttons.map(childButton => {
|
|
||||||
childButton.onClick = _handleToolbarButtonClick.bind(this, childButton);
|
|
||||||
|
|
||||||
if (activeButtons.indexOf(childButton.id) > -1) {
|
|
||||||
activeCommand = childButton.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return childButton;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ExpandableToolMenu
|
|
||||||
key={button.id}
|
|
||||||
label={button.label}
|
|
||||||
icon={button.icon}
|
|
||||||
buttons={childButtons}
|
|
||||||
activeCommand={activeCommand}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
<ToolbarButton
|
if (hasNestedButtonDefinitions) {
|
||||||
key={button.id}
|
return _getExpandableButtonComponent.call(_this, button, activeButtons);
|
||||||
label={button.label}
|
}
|
||||||
icon={button.icon}
|
|
||||||
onClick={_handleToolbarButtonClick.bind(this, button)}
|
return _getDefaultButtonComponent.call(_this, button, activeButtons);
|
||||||
isActive={activeButtons.includes(button.id)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user