Skip to main content
Version: 3.11.0-beta.37 (Latest)

toolbarService

Key Changes:

  • ViewportActionCornersService Removed: The ViewportActionCornersService and its associated provider (ViewportActionCornersProvider) and hook (useViewportActionCorners) have been removed. Functionality for viewport corner items is now integrated into the ToolbarService and standard toolbar components.
  • Viewport Corner Items as Toolbar Buttons: Items previously managed by ViewportActionCornersService are now configured as regular toolbar buttons. They are assigned to specific toolbar sections (e.g., viewportActionMenu.topLeft) and rendered using Toolbar components within the viewport corners.
  • ToolbarService API Updates:
    • ToolbarService.addButtons() has been renamed to ToolbarService.register() to better reflect its purpose of registering button definitions rather than just adding them.
    • ToolbarService.createButtonSection() has been renamed to ToolbarService.updateSection() to better reflect that it is not about creating new sections but updating existing ones.
    • ToolbarService now has a sections property (e.g., toolbarService.sections.viewportActionMenu.topLeft) providing predefined section names.
  • Enhanced useToolbar Hook:
    • The useToolbar hook now returns additional state management functions for toolbar items:
      • openItem, closeItem, isItemOpen (for managing dropdown/popover states).
      • lockItem, unlockItem, toggleLock, isItemLocked.
      • showItem, hideItem, toggleVisibility, isItemVisible.
    • The onInteraction callback now receives itemId and viewportId.
  • Toolbar Button Configuration:
    • The groupId prop in button configurations (e.g., for ohif.toolButtonList, ohif.toolBoxButtonGroup) is generally replaced by directly using buttonSection to define the set of buttons.
    • Button evaluate functions can now leverage evaluateProps.hideWhenDisabled to automatically hide a button when it's disabled.
  • New UI Components & Hooks for Viewport Corners:
    • Specialized components like ModalityLoadBadge, NavigationComponent, TrackingStatus, ViewportDataOverlayMenuWrapper, ViewportOrientationMenuWrapper, WindowLevelActionMenuWrapper are now used as toolbar buttons, typically in viewport action menu sections.
    • useViewportHover hook can be used to determine if a viewport is hovered or active, controlling the visibility of corner toolbars.
  • IconPresentationProvider: A new IconPresentationProvider and useIconPresentation hook have been introduced to standardize icon sizing and styling within toolbars and related components.
  • Legacy Toolbar Components Removed: ToolbarSplitButtonWithServicesLegacy and ToolbarButtonGroupWithServicesLegacy have been removed.

Migration Steps:

  1. Update ToolbarService Method Calls:

    • Although the previous method also works but gives warning in the console when used.
    • Replace all instances of toolbarService.addButtons(...) with toolbarService.register(...).
    • Replace all instances of toolbarService.createButtonSection(...) with toolbarService.updateSection(...).
    // Before
    - toolbarService.addButtons(toolbarButtons);
    - toolbarService.createButtonSection('primary', ['Zoom', 'Pan']);

    // After
    + toolbarService.register(toolbarButtons);
    + toolbarService.updateSection('primary', ['Zoom', 'Pan']);
  2. Migrate Viewport Action Corner Items:

    • Remove any direct usage of the old ViewportActionCornersService, useViewportActionCorners, or ViewportActionCornersProvider.
    • Define your viewport corner items (like orientation menu, W/L menu, data overlay menu) as standard toolbar buttons using toolbarService.register().
    • Assign these buttons to the new dedicated viewport action menu sections. You can access these section names via toolbarService.sections.viewportActionMenu.<location>, e.g., toolbarService.sections.viewportActionMenu.topLeft.
    // Before: Customization in viewportActionMenuCustomizations.ts (now deleted)
    // or direct use of ViewportActionCornersService.addComponent
    - // Example: viewportActionCornersService.addComponent({ viewportId, id: 'orientationMenu', component: MyOrientationMenu, location: 'topLeft' });

    // After: In your mode's onModeEnter or similar setup
    + const myViewportCornerButtons = [
    + {
    + id: 'orientationMenu',
    + uiType: 'ohif.orientationMenu', // Or your custom component registered as a UI type
    + props: { /* ... props for your component ... */ }
    + },
    + // ... other corner buttons
    + ];
    + toolbarService.register(myViewportCornerButtons);
    + toolbarService.updateSection(
    + toolbarService.sections.viewportActionMenu.topLeft,
    + ['orientationMenu', /* other button IDs */]
    + );
    • The OHIFViewportActionCorners.tsx component now internally uses Toolbar components for each corner, which are populated by these sections.
    • For custom components that act as menus (e.g., popovers), use the onOpen, onClose, isOpen props passed down by the Toolbar component (which get these from useToolbar).
    // Before: Custom component might have managed its own open state
    - // const [isMenuOpen, setIsMenuOpen] = useState(false);
    - // const handleOpenChange = (open) => setIsMenuOpen(open);

    // After: Custom component receives isOpen, onOpen, onClose from Toolbar
    + function MyCustomMenuButton({ isOpen, onOpen, onClose, ...rest }) {
    + const handleOpenChange = (openState: boolean) => {
    + if (openState) {
    + onOpen?.();
    + } else {
    + onClose?.();
    + }
    + };
    +
    + return (
    + <Popover open={isOpen} onOpenChange={handleOpenChange}>
    + {/* ... PopoverTrigger and PopoverContent ... */}
    + </Popover>
    + );
    + }
  3. Adapt Toolbar Button and Component Configurations:

    The configuration of toolbar buttons, especially how they relate to sections

    • Button Section Association via props.buttonSection:

      The toolbar service now offers two ways to define this association:

      • A. Simple Approach: buttonSection: true (Implicitly Uses Button's Own ID)

        If a button definition includes props: { buttonSection: true }, the ToolbarService automatically sets the effective buttonSection ID to be the same as the button's own id.

        // Example: A ToolButtonList component's definition in toolbarButtons.ts
        // {
        // id: 'MeasurementTools', // ID of this ToolButtonList component
        // uiType: 'ohif.toolButtonList',
        // props: {
        // buttonSection: true // This ToolButtonList will render the section named 'MeasurementTools'
        // }
        // }

        later you can use it like

        toolbarService.updateSection('MeasurementTools', ['Length', 'Bidirectional', ...]);
      • B. Flexible Approach: buttonSection: 'customSectionName' (Explicit Section ID)

        You can explicitly provide a string for props.buttonSection if the button should be associated with a section ID that is different from its own id, or if you prefer explicit naming.

        // Example: A ToolButtonList component's definition
        // {
        // id: 'MySpecialToolList', // ID of this ToolButtonList component
        // uiType: 'ohif.toolButtonList',
        // props: {
        // buttonSection: 'toolsForAdvancedUsers', // This list renders 'toolsForAdvancedUsers' section
        // }
        // }
    • evaluate Function Enhancement:

      • Button evaluate functions can now leverage evaluateProps: { hideWhenDisabled: true } in your button definition to automatically hide a button when it's disabled.
    • Wrapper Component onInteraction (e.g., ToolButtonListWrapper):

      • Update wrappers like ToolBoxButtonGroupWrapper and ToolButtonListWrapper:
        • The groupId prop is replaced by id (which is the ID of the wrapper button component itself).
        • The onInteraction callback in these wrappers now provides id (the wrapper's ID) instead of groupId.
  4. Adopt IconPresentationProvider (Optional but Recommended):

    • For consistent icon styling across your application's toolbars, wrap a high-level component (like your main Header or layout component) with <IconPresentationProvider size="yourDefaultSize">.
    • Custom tool button components can then use the useIconPresentation hook to get appropriate class names for icons or a pre-styled IconContainer.
    // In your main App.tsx or Header.tsx
    + import { IconPresentationProvider, ToolButton } from '@ohif/ui-next';
    // ...
    + <IconPresentationProvider
    + size="large" // Or "medium", "small", "tiny", or a number
    + IconContainer={ToolButton} // Optional: default is Button
    + containerProps={{ variant: 'primary', className: 'custom-container-class' }} // Optional
    + >
    {/* Your Header content including Toolbars */}
    + </IconPresentationProvider>

    // In a custom tool button using icons
    + import { useIconPresentation, Icons } from '@ohif/ui-next';
    + function MyCustomToolButton({ iconName }) {
    + const { className: iconClassName } = useIconPresentation();
    + return <button><Icons.ByName name={iconName} className={iconClassName} /></button>;
    + }
  5. Remove Legacy Component Usage:

    • Replace any usage of ToolbarSplitButtonWithServicesLegacy and ToolbarButtonGroupWithServicesLegacy with the newer patterns, typically by configuring individual buttons and using ToolButtonList or ButtonGroup from @ohif/ui-next directly, driven by useToolbar.