feat(toolbox): Refactor Toolbar and Toolbox to enable sections (#4825)
This commit is contained in:
1 parent
86c12246ac
commit
cc5cdfb081
79 files changed
+3527
-2992
No files matched your search
@@ -0,0 +1,122 @@
|
||||
import React from 'react';
|
||||
import { PanelSection, ToolSettings } from '@ohif/ui-next';
|
||||
import { useSystem, useToolbar } from '@ohif/core';
|
||||
import classnames from 'classnames';
|
||||
|
||||
interface ButtonProps {
|
||||
isActive?: boolean;
|
||||
options?: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* A toolbox is a collection of buttons and commands that they invoke, used to provide
|
||||
* custom control panels to users. This component is a generic UI component that
|
||||
* interacts with services and commands in a generic fashion. While it might
|
||||
* seem unconventional to import it from the UI and integrate it into the JSX,
|
||||
* it belongs in the UI components as there isn't anything in this component that
|
||||
* couldn't be used for a completely different type of app. It plays a crucial
|
||||
* role in enhancing the app with a toolbox by providing a way to integrate
|
||||
* and display various tools and their corresponding options
|
||||
*/
|
||||
export function Toolbox({ buttonSectionId, title }: { buttonSectionId: string; title: string }) {
|
||||
const { servicesManager } = useSystem();
|
||||
const { toolbarService } = servicesManager.services;
|
||||
|
||||
const { toolbarButtons: toolboxSections, onInteraction } = useToolbar({
|
||||
servicesManager,
|
||||
buttonSection: buttonSectionId,
|
||||
});
|
||||
|
||||
if (!toolboxSections.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure we have proper button sections at the top level.
|
||||
if (!toolboxSections.every(section => section.componentProps.buttonSection)) {
|
||||
throw new Error(
|
||||
'Toolbox accepts only button sections at the top level, not buttons. Create at least one button section.'
|
||||
);
|
||||
}
|
||||
|
||||
// Helper to check a list of buttons for an active tool.
|
||||
const findActiveOptions = (buttons: any[]): unknown => {
|
||||
for (const tool of buttons) {
|
||||
if (tool.componentProps.isActive) {
|
||||
return tool.componentProps.options;
|
||||
}
|
||||
if (tool.componentProps.buttonSection) {
|
||||
const nestedButtons = toolbarService.getButtonPropsInButtonSection(
|
||||
tool.componentProps.buttonSection
|
||||
) as ButtonProps[];
|
||||
const activeNested = nestedButtons.find(nested => nested.isActive);
|
||||
if (activeNested) {
|
||||
return activeNested.options;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Look for active tool options across all sections.
|
||||
const activeToolOptions = toolboxSections.reduce((activeOptions, section) => {
|
||||
if (activeOptions) {
|
||||
return activeOptions;
|
||||
}
|
||||
const sectionId = section.componentProps.buttonSection;
|
||||
const buttons = toolbarService.getButtonSection(sectionId);
|
||||
return findActiveOptions(buttons);
|
||||
}, null);
|
||||
|
||||
// Define the interaction handler once.
|
||||
const handleInteraction = ({ itemId }: { itemId: string }) => {
|
||||
onInteraction?.({ itemId });
|
||||
};
|
||||
|
||||
return (
|
||||
<PanelSection>
|
||||
<PanelSection.Header>
|
||||
<span>{title}</span>
|
||||
</PanelSection.Header>
|
||||
<PanelSection.Content className="flex-shrink-0 border-none">
|
||||
{toolboxSections.map(section => {
|
||||
const sectionId = section.componentProps.buttonSection;
|
||||
const buttons = toolbarService.getButtonSection(sectionId) as any[];
|
||||
|
||||
return (
|
||||
<div
|
||||
key={sectionId}
|
||||
className="bg-muted flex flex-wrap space-x-2 py-2 px-1"
|
||||
>
|
||||
{buttons.map(tool => {
|
||||
if (!tool) {
|
||||
return null;
|
||||
}
|
||||
const { id, Component, componentProps } = tool;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={id}
|
||||
className={classnames('ml-1')}
|
||||
>
|
||||
<Component
|
||||
{...componentProps}
|
||||
id={id}
|
||||
onInteraction={handleInteraction}
|
||||
size="toolbox"
|
||||
servicesManager={servicesManager}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{activeToolOptions && (
|
||||
<div className="bg-primary-dark h-auto px-2">
|
||||
<ToolSettings options={activeToolOptions} />
|
||||
</div>
|
||||
)}
|
||||
</PanelSection.Content>
|
||||
</PanelSection>
|
||||
);
|
||||
}
|
||||
@@ -57,6 +57,10 @@ export async function callInputDialog({
|
||||
submitOnEnter = true,
|
||||
}: {
|
||||
uiDialogService: AppTypes.UIDialogService;
|
||||
defaultValue?: string;
|
||||
title?: string;
|
||||
placeholder?: string;
|
||||
submitOnEnter?: boolean;
|
||||
}) {
|
||||
const dialogId = 'dialog-enter-annotation';
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { addIcon } from './addIcon';
|
||||
export * from './Toolbox';
|
||||
Reference in new issue
Block a user