diff --git a/extensions/cornerstone-dicom-seg/src/index.tsx b/extensions/cornerstone-dicom-seg/src/index.tsx index e4ea1944c..fde3d95a9 100644 --- a/extensions/cornerstone-dicom-seg/src/index.tsx +++ b/extensions/cornerstone-dicom-seg/src/index.tsx @@ -30,17 +30,6 @@ const extension = { */ id, - /** - * Perform any pre-registration tasks here. This is called before the extension - * is registered. Usually we run tasks such as: configuring the libraries - * (e.g. cornerstone, cornerstoneTools, ...) or registering any services that - * this extension is providing. - */ - preRegistration: ({ - servicesManager, - commandsManager, - configuration = {}, - }) => {}, /** * PanelModule should provide a list of panels that will be available in OHIF * for Modes to consume and render. Each panel is defined by a {name, diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json index 76e8fe82b..a566c0c0d 100644 --- a/extensions/cornerstone-dicom-sr/package.json +++ b/extensions/cornerstone-dicom-sr/package.json @@ -32,8 +32,8 @@ "test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests" }, "peerDependencies": { - "@ohif/core": "^3.0.0", - "@ohif/extension-cornerstone": "^3.0.0", + "@ohif/core": ">=3.0.0", + "@ohif/extension-cornerstone": ">=3.0.0", "@ohif/extension-measurement-tracking": "^3.0.0", "@ohif/ui": "^2.0.0", "dcmjs": "^0.29.5", diff --git a/extensions/cornerstone-dicom-sr/src/viewports/OHIFCornerstoneSRViewport.tsx b/extensions/cornerstone-dicom-sr/src/viewports/OHIFCornerstoneSRViewport.tsx index c16b6a334..c3db19b8c 100644 --- a/extensions/cornerstone-dicom-sr/src/viewports/OHIFCornerstoneSRViewport.tsx +++ b/extensions/cornerstone-dicom-sr/src/viewports/OHIFCornerstoneSRViewport.tsx @@ -2,6 +2,8 @@ import PropTypes from 'prop-types'; import React, { useCallback, useContext, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import OHIF, { utils, ServicesManager, ExtensionManager } from '@ohif/core'; +import { CornerstoneServices } from '@ohif/extension-cornerstone/types'; + import { setTrackingUniqueIdentifiersForElement } from '../tools/modules/dicomSRModule'; import { @@ -37,7 +39,7 @@ function OHIFCornerstoneSRViewport(props) { displaySetService, cornerstoneViewportService, measurementService, - } = servicesManager.services; + } = servicesManager.services as CornerstoneServices; // SR viewport will always have a single display set if (displaySets.length > 1) { @@ -91,10 +93,12 @@ function OHIFCornerstoneSRViewport(props) { SeriesInstanceUIDs[0] ); if (displaySets.length) { - viewportGridService.setDisplaySetsForViewport({ - viewportIndex: activeViewportIndex, - displaySetInstanceUIDs: [displaySets[0].displaySetInstanceUID], - }); + viewportGridService.setDisplaySetsForViewports([ + { + viewportIndex: activeViewportIndex, + displaySetInstanceUIDs: [displaySets[0].displaySetInstanceUID], + }, + ]); } }; } @@ -422,6 +426,7 @@ OHIFCornerstoneSRViewport.propTypes = { children: PropTypes.node, customProps: PropTypes.object, viewportOptions: PropTypes.object, + viewportLabel: PropTypes.string, servicesManager: PropTypes.instanceOf(ServicesManager).isRequired, extensionManager: PropTypes.instanceOf(ExtensionManager).isRequired, }; diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index cae1befd0..55a5b76d9 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -7,6 +7,11 @@ "repository": "OHIF/Viewers", "main": "dist/index.umd.js", "module": "src/index.tsx", + "types": "src/types/index.ts", + "exports": { + ".": "./src/index.tsx", + "./types": "./src/types/index.ts" + }, "engines": { "node": ">=10", "npm": ">=6", diff --git a/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx b/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx index fb51ccdd6..0a9d8ac89 100644 --- a/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx +++ b/extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx @@ -10,17 +10,18 @@ import { utilities as csUtils, CONSTANTS, } from '@cornerstonejs/core'; +import { CinePlayer, useCine, useViewportGrid } from '@ohif/ui'; +import { + IStackViewport, + IVolumeViewport, +} from '@cornerstonejs/core/dist/esm/types'; import { setEnabledElement } from '../state'; import './OHIFCornerstoneViewport.css'; import CornerstoneOverlays from './Overlays/CornerstoneOverlays'; -import { - IStackViewport, - IVolumeViewport, -} from '@cornerstonejs/core/dist/esm/types'; import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/getSOPInstanceAttributes'; -import { CinePlayer, useCine, useViewportGrid } from '@ohif/ui'; +import CornerstoneServices from '../types/CornerstoneServices'; const STACK = 'stack'; @@ -129,7 +130,7 @@ const OHIFCornerstoneViewport = React.memo(props => { cornerstoneCacheService, viewportGridService, stateSyncService, - } = servicesManager.services; + } = servicesManager.services as CornerstoneServices; const cineHandler = () => { if (!cines || !cines[viewportIndex] || !enabledVPElement) { diff --git a/extensions/cornerstone/src/index.tsx b/extensions/cornerstone/src/index.tsx index f1ec22f16..165d70cd9 100644 --- a/extensions/cornerstone/src/index.tsx +++ b/extensions/cornerstone/src/index.tsx @@ -7,7 +7,7 @@ import { imageRetrievalPoolManager, } from '@cornerstonejs/core'; import { Enums as cs3DToolsEnums } from '@cornerstonejs/tools'; -import { Types } from '@ohif/core'; +import { ServicesManager, Types } from '@ohif/core'; import init from './init'; import getCommandsModule from './commandsModule'; @@ -16,10 +16,11 @@ import ToolGroupService from './services/ToolGroupService'; import SyncGroupService from './services/SyncGroupService'; import SegmentationService from './services/SegmentationService'; import CornerstoneCacheService from './services/CornerstoneCacheService'; +import CornerstoneViewportService from './services/ViewportService/CornerstoneViewportService'; +import * as CornerstoneExtensionTypes from './types'; import { toolNames } from './initCornerstoneTools'; import { getEnabledElement, reset as enabledElementReset } from './state'; -import CornerstoneViewportService from './services/ViewportService/CornerstoneViewportService'; import dicomLoaderService from './utils/dicomLoaderService'; import { registerColormap } from './utils/colormap/transferFunctionHelpers'; @@ -72,18 +73,11 @@ const cornerstoneExtension: Types.Extensions.Extension = { props: Types.Extensions.ExtensionParams ): Promise { const { servicesManager } = props; - // Todo: we should be consistent with how services get registered. Use REGISTRATION static method for all - servicesManager.registerService( - CornerstoneViewportService(servicesManager) - ); - servicesManager.registerService( - ToolGroupService.REGISTRATION(servicesManager) - ); - servicesManager.registerService(SyncGroupService(servicesManager)); - servicesManager.registerService(SegmentationService(servicesManager)); - servicesManager.registerService( - CornerstoneCacheService.REGISTRATION(servicesManager) - ); + servicesManager.registerService(CornerstoneViewportService.REGISTRATION); + servicesManager.registerService(ToolGroupService.REGISTRATION); + servicesManager.registerService(SyncGroupService.REGISTRATION); + servicesManager.registerService(SegmentationService.REGISTRATION); + servicesManager.registerService(CornerstoneCacheService.REGISTRATION); return init.call(this, props); }, @@ -145,5 +139,5 @@ const cornerstoneExtension: Types.Extensions.Extension = { }; export type { PublicViewportOptions }; -export { measurementMappingUtils }; +export { measurementMappingUtils, CornerstoneExtensionTypes }; export default cornerstoneExtension; diff --git a/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts b/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts index 56c8d6fa5..7eb2d6751 100644 --- a/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts +++ b/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts @@ -1,4 +1,4 @@ -import { ServicesManager } from '@ohif/core'; +import { ServicesManager, Types } from '@ohif/core'; import { cache as cs3DCache, Enums, volumeLoader } from '@cornerstonejs/core'; import getCornerstoneViewportType from '../../utils/getCornerstoneViewportType'; @@ -10,20 +10,21 @@ import { const VOLUME_LOADER_SCHEME = 'cornerstoneStreamingImageVolume'; class CornerstoneCacheService { - static REGISTRATION = (serviceManager: ServicesManager) => { - return { - name: 'cornerstoneCacheService', - altName: 'CornerstoneCacheService', - create: ({ configuration = {} }) => { - return new CornerstoneCacheService(serviceManager); - }, - }; + static REGISTRATION = { + name: 'cornerstoneCacheService', + altName: 'CornerstoneCacheService', + create: ({ + servicesManager, + }: Types.Extensions.ExtensionParams): CornerstoneCacheService => { + return new CornerstoneCacheService(servicesManager); + }, }; stackImageIds: Map = new Map(); volumeImageIds: Map = new Map(); + readonly servicesManager: ServicesManager; - constructor(servicesManager) { + constructor(servicesManager: ServicesManager) { this.servicesManager = servicesManager; } diff --git a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts index 658ee816f..d4c25bee4 100644 --- a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts +++ b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts @@ -1,5 +1,6 @@ import cloneDeep from 'lodash.clonedeep'; +import { Types as OhifTypes, ServicesManager, PubSubService } from '@ohif/core'; import { cache, eventTarget, @@ -16,7 +17,6 @@ import { Types as cstTypes, utilities as cstUtils, } from '@cornerstonejs/tools'; -import { pubSubServiceInterface } from '@ohif/core'; import isEqual from 'lodash.isequal'; import { easeInOutBell } from '../../utils/transitions'; import { @@ -47,19 +47,26 @@ const EVENTS = { const VALUE_TYPES = {}; -class SegmentationService { - listeners = {}; +class SegmentationService extends PubSubService { + static REGISTRATION = { + name: 'segmentationService', + altName: 'SegmentationService', + create: ({ + servicesManager, + }: OhifTypes.Extensions.ExtensionParams): SegmentationService => { + return new SegmentationService({ servicesManager }); + }, + }; + segmentations: Record; - servicesManager = null; + readonly servicesManager: ServicesManager; highlightIntervalId = null; - _broadcastEvent: (eventName: string, callbackProps: any) => void; readonly EVENTS = EVENTS; constructor({ servicesManager }) { + super(EVENTS); this.segmentations = {}; - this.listeners = {}; - Object.assign(this, pubSubServiceInterface); this.servicesManager = servicesManager; this._initSegmentationService(); diff --git a/extensions/cornerstone/src/services/SegmentationService/index.js b/extensions/cornerstone/src/services/SegmentationService/index.js index 7b89d9bec..848c25ef9 100644 --- a/extensions/cornerstone/src/services/SegmentationService/index.js +++ b/extensions/cornerstone/src/services/SegmentationService/index.js @@ -1,11 +1,3 @@ import SegmentationService from './SegmentationService'; -export default function ExtendedSegmentationService(servicesManager) { - return { - name: 'segmentationService', - altName: 'SegmentationService', - create: ({ configuration = {} }) => { - return new SegmentationService({ servicesManager }); - }, - }; -} +export default SegmentationService; diff --git a/extensions/cornerstone/src/services/SyncGroupService/SyncGroupService.ts b/extensions/cornerstone/src/services/SyncGroupService/SyncGroupService.ts index 6acfce70a..39e919fc5 100644 --- a/extensions/cornerstone/src/services/SyncGroupService/SyncGroupService.ts +++ b/extensions/cornerstone/src/services/SyncGroupService/SyncGroupService.ts @@ -4,7 +4,7 @@ import { Synchronizer, } from '@cornerstonejs/tools'; -import { pubSubServiceInterface } from '@ohif/core'; +import { pubSubServiceInterface, Types, ServicesManager } from '@ohif/core'; const EVENTS = { TOOL_GROUP_CREATED: 'event::cornerstone::syncgroupservice:toolgroupcreated', @@ -37,7 +37,17 @@ const asSyncGroup = (syncGroup: string | SyncGroup): SyncGroup => typeof syncGroup === 'string' ? { type: syncGroup } : syncGroup; export default class SyncGroupService { - serviceManager: any; + static REGISTRATION = { + name: 'syncGroupService', + altName: 'SyncGroupService', + create: ({ + servicesManager, + }: Types.Extensions.ExtensionParams): SyncGroupService => { + return new SyncGroupService(servicesManager); + }, + }; + + servicesManager: ServicesManager; listeners: { [key: string]: (...args: any[]) => void } = {}; EVENTS: { [key: string]: string }; synchronizerCreators: Record = { @@ -47,8 +57,8 @@ export default class SyncGroupService { [STACKIMAGE]: synchronizers.createStackImageSynchronizer, }; - constructor(serviceManager) { - this.serviceManager = serviceManager; + constructor(serviceManager: ServicesManager) { + this.servicesManager = serviceManager; this.listeners = {}; this.EVENTS = EVENTS; // diff --git a/extensions/cornerstone/src/services/SyncGroupService/index.js b/extensions/cornerstone/src/services/SyncGroupService/index.js index 64cb989fe..1e0a21819 100644 --- a/extensions/cornerstone/src/services/SyncGroupService/index.js +++ b/extensions/cornerstone/src/services/SyncGroupService/index.js @@ -1,11 +1,3 @@ import SyncGroupService from './SyncGroupService'; -export default function ExtendedSyncGroupService(serviceManager) { - return { - altName: 'SyncGroupService', - name: 'syncGroupService', - create: ({ configuration = {} }) => { - return new SyncGroupService(serviceManager); - }, - }; -} +export default SyncGroupService; diff --git a/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts b/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts index f0f0bf4be..4f5512ecf 100644 --- a/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts +++ b/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts @@ -1,6 +1,6 @@ import { ToolGroupManager, Enums, Types } from '@cornerstonejs/tools'; -import { pubSubServiceInterface } from '@ohif/core'; +import { Types as OhifTypes, pubSubServiceInterface } from '@ohif/core'; const EVENTS = { VIEWPORT_ADDED: 'event::cornerstone::toolgroupservice:viewportadded', @@ -20,14 +20,14 @@ type Tools = { }; export default class ToolGroupService { - public static REGISTRATION = serviceManager => { - return { - name: 'toolGroupService', - altName: 'ToolGroupService', - create: ({ configuration = {} }) => { - return new ToolGroupService(serviceManager); - }, - }; + public static REGISTRATION = { + name: 'toolGroupService', + altName: 'ToolGroupService', + create: ({ + servicesManager, + }: OhifTypes.Extensions.ExtensionParams): ToolGroupService => { + return new ToolGroupService(servicesManager); + }, }; serviceManager: any; diff --git a/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts b/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts index 946dee124..a99083d8b 100644 --- a/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts +++ b/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts @@ -1,4 +1,5 @@ -import { PubSubService } from '@ohif/core'; +import { PubSubService, ServicesManager } from '@ohif/core'; +import * as OhifTypes from '@ohif/core/types'; import { RenderingEngine, StackViewport, @@ -43,6 +44,16 @@ const EVENTS = { */ class CornerstoneViewportService extends PubSubService implements IViewportService { + static REGISTRATION = { + name: 'cornerstoneViewportService', + altName: 'CornerstoneViewportService', + create: ({ + servicesManager, + }: OhifTypes.Extensions.ExtensionParams): CornerstoneViewportService => { + return new CornerstoneViewportService(servicesManager); + }, + }; + renderingEngine: Types.IRenderingEngine | null; viewportsInfo: Map = new Map(); viewportsById: Map = new Map(); @@ -55,7 +66,7 @@ class CornerstoneViewportService extends PubSubService resizeRefreshMode: 'debounce'; servicesManager = null; - constructor(servicesManager) { + constructor(servicesManager: ServicesManager) { super(EVENTS); this.renderingEngine = null; this.viewportGridResizeObserver = null; @@ -71,7 +82,7 @@ class CornerstoneViewportService extends PubSubService viewportIndex: number, viewportOptions: PublicViewportOptions, elementRef: HTMLDivElement - ) { + ): void { // Use the provided viewportId // Not providing a viewportId is frowned upon because it does weird things // on moving them around, but it does mostly work. @@ -855,14 +866,4 @@ class CornerstoneViewportService extends PubSubService } } -export default function CornerstoneViewportServiceRegistration(serviceManager) { - return { - name: 'cornerstoneViewportService', - altName: 'CornerstoneViewportService', - create: ({ configuration = {} }) => { - return new CornerstoneViewportService(serviceManager); - }, - }; -} - -export { CornerstoneViewportService, CornerstoneViewportServiceRegistration }; +export default CornerstoneViewportService; diff --git a/extensions/cornerstone/src/types/CornerstoneServices.ts b/extensions/cornerstone/src/types/CornerstoneServices.ts new file mode 100644 index 000000000..2f52dc9ff --- /dev/null +++ b/extensions/cornerstone/src/types/CornerstoneServices.ts @@ -0,0 +1,16 @@ +import { Types } from '@ohif/core'; +import ToolGroupService from './services/ToolGroupService'; +import SyncGroupService from './services/SyncGroupService'; +import SegmentationService from './services/SegmentationService'; +import CornerstoneCacheService from './services/CornerstoneCacheService'; +import CornerstoneViewportService from './services/ViewportService/CornerstoneViewportService'; + +interface CornerstoneServices extends Types.Services { + cornerstoneViewportService: CornerstoneViewportService; + toolGroupService: ToolGroupService; + syncGroupService: SyncGroupService; + segmentationService: SegmentationService; + cornerstoneCacheService: CornerstoneCacheService; +} + +export default CornerstoneServices; diff --git a/extensions/cornerstone/src/types/index.ts b/extensions/cornerstone/src/types/index.ts index 8c8e32e98..6c729817d 100644 --- a/extensions/cornerstone/src/types/index.ts +++ b/extensions/cornerstone/src/types/index.ts @@ -1,5 +1,7 @@ import * as CornerstoneCacheService from './CornerstoneCacheService' +import CornerstoneServices from './CornerstoneServices'; export type { - CornerstoneCacheService + CornerstoneCacheService, + CornerstoneServices, } diff --git a/extensions/default/src/CustomizeableContextMenu/index.ts b/extensions/default/src/CustomizeableContextMenu/index.ts index d630bcad9..7dc08dd3d 100644 --- a/extensions/default/src/CustomizeableContextMenu/index.ts +++ b/extensions/default/src/CustomizeableContextMenu/index.ts @@ -1,5 +1,5 @@ import ContextMenuController from './ContextMenuController'; -import ContextMenuItemsBuilder from './ContextMenuItemsBuilder'; +import * as ContextMenuItemsBuilder from './ContextMenuItemsBuilder'; import defaultContextMenu from './defaultContextMenu'; import * as CustomizeableContextMenuTypes from './types'; diff --git a/platform/core/package.json b/platform/core/package.json index cb97a9eab..afd26b6cb 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -7,6 +7,7 @@ "repository": "OHIF/Viewers", "main": "dist/index.umd.js", "module": "src/index.ts", + "types": "src/types/index.ts", "sideEffects": "false", "publishConfig": { "access": "public" diff --git a/platform/core/src/extensions/ExtensionManager.ts b/platform/core/src/extensions/ExtensionManager.ts index 188da5add..9c26d7370 100644 --- a/platform/core/src/extensions/ExtensionManager.ts +++ b/platform/core/src/extensions/ExtensionManager.ts @@ -37,9 +37,12 @@ export interface ExtensionParams extends ExtensionConstructor { export interface Extension { id: string; preRegistration?: (p: ExtensionParams) => Promise | void; - onModeExit?: () => void; getHangingProtocolModule?: (p: ExtensionParams) => unknown; getCommandsModule?: (p: ExtensionParams) => CommandsModule; + getViewportModule?: (p: ExtensionParams) => unknown; + getUtilityModule?: (p: ExtensionParams) => unknown; + onModeEnter?: () => void; + onModeExit?: () => void; } export type ExtensionRegister = { diff --git a/platform/core/src/services/UIModalService/index.js b/platform/core/src/services/UIModalService/index.js deleted file mode 100644 index babeb6e5c..000000000 --- a/platform/core/src/services/UIModalService/index.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * UI Modal - * - * @typedef {Object} ModalProps - * @property {ReactElement|HTMLElement} [content=null] Modal content. - * @property {Object} [contentProps=null] Modal content props. - * @property {boolean} [shouldCloseOnEsc=false] Modal is dismissible via the esc key. - * @property {boolean} [isOpen=true] Make the Modal visible or hidden. - * @property {boolean} [closeButton=true] Should the modal body render the close button. - * @property {string} [title=null] Should the modal render the title independently of the body content. - * @property {string} [customClassName=null] The custom class to style the modal. - */ - -const name = 'uiModalService'; - -const publicAPI = { - name, - hide: _hide, - show: _show, - setServiceImplementation, -}; - -const serviceImplementation = { - _hide: () => console.warn('hide() NOT IMPLEMENTED'), - _show: () => console.warn('show() NOT IMPLEMENTED'), -}; - -/** - * Show a new UI modal; - * - * @param {ModalProps} props { content, contentProps, shouldCloseOnEsc, isOpen, closeButton, title, customClassName } - */ -function _show({ - content = null, - contentProps = null, - shouldCloseOnEsc = true, - isOpen = true, - closeButton = true, - title = null, - customClassName = null, -}) { - return serviceImplementation._show({ - content, - contentProps, - shouldCloseOnEsc, - isOpen, - closeButton, - title, - customClassName, - }); -} - -/** - * Hides/dismisses the modal, if currently shown - * - * @returns void - */ -function _hide() { - return serviceImplementation._hide(); -} - -/** - * - * - * @param {*} { - * hide: hideImplementation, - * show: showImplementation, - * } - */ -function setServiceImplementation({ - hide: hideImplementation, - show: showImplementation, -}) { - if (hideImplementation) { - serviceImplementation._hide = hideImplementation; - } - if (showImplementation) { - serviceImplementation._show = showImplementation; - } -} - -// TODO - export TS Type -export default { - REGISTRATION: { - name, - altName: 'UIModalService', - create: ({ configuration = {} }) => { - return publicAPI; - }, - }, -}; diff --git a/platform/core/src/services/UIModalService/index.ts b/platform/core/src/services/UIModalService/index.ts new file mode 100644 index 000000000..3b33d3806 --- /dev/null +++ b/platform/core/src/services/UIModalService/index.ts @@ -0,0 +1,87 @@ +/** + * UI Modal + * + * @typedef {Object} ModalProps + * @property {ReactElement|HTMLElement} [content=null] Modal content. + * @property {Object} [contentProps=null] Modal content props. + * @property {boolean} [shouldCloseOnEsc=false] Modal is dismissible via the esc key. + * @property {boolean} [isOpen=true] Make the Modal visible or hidden. + * @property {boolean} [closeButton=true] Should the modal body render the close button. + * @property {string} [title=null] Should the modal render the title independently of the body content. + * @property {string} [customClassName=null] The custom class to style the modal. + */ + +const name = 'uiModalService'; + +const serviceImplementation = { + _hide: () => console.warn('hide() NOT IMPLEMENTED'), + _show: () => console.warn('show() NOT IMPLEMENTED'), +}; + +class UIModalService { + static REGISTRATION = { + name, + altName: 'UIModalService', + create: (): UIModalService => { + return new UIModalService(); + }, + }; + + readonly name = name; + + /** + * Show a new UI modal; + * + * @param {ModalProps} props { content, contentProps, shouldCloseOnEsc, isOpen, closeButton, title, customClassName } + */ + show({ + content = null, + contentProps = null, + shouldCloseOnEsc = true, + isOpen = true, + closeButton = true, + title = null, + customClassName = null, + }) { + return serviceImplementation._show({ + content, + contentProps, + shouldCloseOnEsc, + isOpen, + closeButton, + title, + customClassName, + }); + } + + /** + * Hides/dismisses the modal, if currently shown + * + * @returns void + */ + hide() { + return serviceImplementation._hide(); + } + + /** + * + * + * @param {*} { + * hide: hideImplementation, + * show: showImplementation, + * } + */ + setServiceImplementation({ + hide: hideImplementation, + show: showImplementation, + }) { + if (hideImplementation) { + serviceImplementation._hide = hideImplementation; + } + if (showImplementation) { + serviceImplementation._show = showImplementation; + } + } +} + +export default UIModalService; diff --git a/platform/core/src/services/UINotificationService/index.js b/platform/core/src/services/UINotificationService/index.js deleted file mode 100644 index a21033759..000000000 --- a/platform/core/src/services/UINotificationService/index.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * A UI Notification - * - * @typedef {Object} Notification - * @property {string} title - - * @property {string} message - - * @property {number} [duration=5000] - in ms - * @property {string} [position="bottomRight"] -"topLeft" | "topCenter | "topRight" | "bottomLeft" | "bottomCenter" | "bottomRight" - * @property {string} [type="info"] - "info" | "error" | "warning" | "success" - * @property {boolean} [autoClose=true] - */ - -const name = 'uiNotificationService'; - -const serviceShowRequestQueue = []; - -const publicAPI = { - name, - hide: _hide, - show: _show, - setServiceImplementation, -}; - -const serviceImplementation = { - _hide: () => console.warn('hide() NOT IMPLEMENTED'), - _show: showArguments => { - serviceShowRequestQueue.push(showArguments); - - console.warn('show() NOT IMPLEMENTED'); - }, -}; - -/** - * Create and show a new UI notification; returns the - * ID of the created notification. - * - * @param {Notification} notification { title, message, duration, position, type, autoClose} - * @returns {number} id - */ -function _show({ - title, - message, - duration = 5000, - position = 'bottomRight', - type = 'info', - autoClose = true, -}) { - return serviceImplementation._show({ - title, - message, - duration, - position, - type, - autoClose, - }); -} - -/** - * Hides/dismisses the notification, if currently shown - * - * @param {number} id - id of the notification to hide/dismiss - * @returns undefined - */ -function _hide(id) { - return serviceImplementation._hide({ id }); -} - -/** - * - * - * @param {*} { - * hide: hideImplementation, - * show: showImplementation, - * } - */ -function setServiceImplementation({ - hide: hideImplementation, - show: showImplementation, -}) { - if (hideImplementation) { - serviceImplementation._hide = hideImplementation; - } - if (showImplementation) { - serviceImplementation._show = showImplementation; - - while (serviceShowRequestQueue.length > 0) { - const showArguments = serviceShowRequestQueue.pop(); - serviceImplementation._show(showArguments); - } - } -} - -export default { - REGISTRATION: { - name, - altName: 'UINotificationService', - create: ({ configuration = {} }) => { - return publicAPI; - }, - }, -}; diff --git a/platform/core/src/services/UINotificationService/index.ts b/platform/core/src/services/UINotificationService/index.ts new file mode 100644 index 000000000..78a2882af --- /dev/null +++ b/platform/core/src/services/UINotificationService/index.ts @@ -0,0 +1,94 @@ +/** + * A UI Notification + * + * @typedef {Object} Notification + * @property {string} title - + * @property {string} message - + * @property {number} [duration=5000] - in ms + * @property {string} [position="bottomRight"] -"topLeft" | "topCenter | "topRight" | "bottomLeft" | "bottomCenter" | "bottomRight" + * @property {string} [type="info"] - "info" | "error" | "warning" | "success" + * @property {boolean} [autoClose=true] + */ + +const serviceShowRequestQueue = []; + +const serviceImplementation = { + _hide: () => console.warn('hide() NOT IMPLEMENTED'), + _show: showArguments => { + serviceShowRequestQueue.push(showArguments); + + console.warn('show() NOT IMPLEMENTED'); + }, +}; + +class UINotificationService { + static REGISTRATION = { + name: 'uiNotificationService', + altName: 'UINotificationService', + create: (): UINotificationService => { + return new UINotificationService(); + }, + }; + + /** + * + * + * @param {*} { + * hide: hideImplementation, + * show: showImplementation, + * } + */ + public setServiceImplementation({ + hide: hideImplementation, + show: showImplementation, + }): void { + if (hideImplementation) { + serviceImplementation._hide = hideImplementation; + } + if (showImplementation) { + serviceImplementation._show = showImplementation; + + while (serviceShowRequestQueue.length > 0) { + const showArguments = serviceShowRequestQueue.pop(); + serviceImplementation._show(showArguments); + } + } + } + + /** + * Hides/dismisses the notification, if currently shown + * + * @param {number} id - id of the notification to hide/dismiss + * @returns undefined + */ + public hide(id: string) { + return serviceImplementation._hide({ id }); + } + + /** + * Create and show a new UI notification; returns the + * ID of the created notification. + * + * @param {Notification} notification { title, message, duration, position, type, autoClose} + * @returns {number} id + */ + show({ + title, + message, + duration = 5000, + position = 'bottomRight', + type = 'info', + autoClose = true, + }) { + return serviceImplementation._show({ + title, + message, + duration, + position, + type, + autoClose, + }); + } +} + +export default UINotificationService; diff --git a/platform/core/src/types/Services.ts b/platform/core/src/types/Services.ts index ca73361ca..abc6b09be 100644 --- a/platform/core/src/types/Services.ts +++ b/platform/core/src/types/Services.ts @@ -6,6 +6,8 @@ import { ToolbarService, DisplaySetService, StateSyncService, + UINotificationService, + UIModalService, } from '../services'; /** @@ -22,8 +24,8 @@ export default interface Services { cornerstoneViewportService?: Record; uiDialogService?: Record; toolGroupService?: Record; - uiNotificationService?: Record; - uiModalService?: Record; + uiNotificationService?: UINotificationService; + uiModalService?: UIModalService; uiViewportDialogService?: Record; viewportGridService?: ViewportGridService; syncGroupService?: Record; diff --git a/platform/ui/src/types/index.ts b/platform/ui/src/types/index.ts index 78b560486..5d0729fbe 100644 --- a/platform/ui/src/types/index.ts +++ b/platform/ui/src/types/index.ts @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import ThumbnailType from './ThumbnailType'; -import { PresentationIds } from '../contextProviders/getPresentationIds'; +import type { PresentationIds } from '../contextProviders/getPresentationIds'; // A few miscellaneous types declared inline here.