feat: Notification provider and service (#1703)

* Create basic structure for Viewport dialog provier and Dialog component

* Implementation of a UIViewportDialogService

* Update viewportDialogProvider docz

* Create example of use of UIViewportDialogService
This commit is contained in:
Gustavo André Lelis authored and James A. Petts committed 2020-05-15 13:59:28 +02:00
1 parent cee09fcf8d
commit e633eb80eb
11 files changed
+395 -23

No files matched your search

+3
View File
@@ -8,6 +8,8 @@ export {
ModalConsumer,
useModal,
withModal,
ViewportDialogProvider,
useViewportDialog,
} from './src/contextProviders';
/** COMPONENTS */
@@ -15,6 +17,7 @@ export {
Button,
ButtonGroup,
DateRange,
Dialog,
EmptyStudies,
Icon,
IconButton,
@@ -0,0 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
const Dialog = ({ children }) => {
return <div className="absolute top-0 left-0">{children}</div>;
};
Dialog.propTypes = {
children: PropTypes.node,
};
export default Dialog;
@@ -0,0 +1,2 @@
import Dialog from './Dialog';
export default Dialog;
+2
View File
@@ -1,6 +1,7 @@
import Button from './Button';
import ButtonGroup from './ButtonGroup';
import DateRange from './DateRange';
import Dialog from './Dialog';
import EmptyStudies from './EmptyStudies';
import Icon from './Icon';
import IconButton from './IconButton';
@@ -47,6 +48,7 @@ export {
Button,
ButtonGroup,
DateRange,
Dialog,
EmptyStudies,
Icon,
IconButton,
@@ -0,0 +1,79 @@
import React, {
useState,
createContext,
useContext,
useCallback,
useEffect,
} from 'react';
import PropTypes from 'prop-types';
const DEFAULT_OPTIONS = {
content: null,
contentProps: null,
customClassName: null,
};
const ViewportDialogContext = createContext(null);
const { Provider } = ViewportDialogContext;
export const useViewportDialog = () => useContext(ViewportDialogContext);
const ViewportDialogProvider = ({
children,
dialog: Dialog,
service,
viewportIndex,
}) => {
const [options, setOptions] = useState(DEFAULT_OPTIONS);
const show = useCallback((props) => setOptions({ ...options, ...props }), [
options,
]);
const hide = useCallback(() => setOptions(DEFAULT_OPTIONS), []);
useEffect(() => {
if (service) {
service.setServiceImplementation({ hide, show, viewportIndex });
}
}, [hide, service, show, viewportIndex]);
const {
content: ViewportDialogContent,
contentProps,
customClassName,
} = options;
return (
<Provider value={{ show, hide }}>
<div className="relative w-full h-full">
{ViewportDialogContent && (
<Dialog className={customClassName}>
<ViewportDialogContent {...contentProps} show={show} hide={hide} />
</Dialog>
)}
{children}
</div>
</Provider>
);
};
ViewportDialogProvider.propTypes = {
/** Children that will be wrapped with Modal Context */
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
/** dialog component */
dialog: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.func,
]).isRequired,
service: PropTypes.shape({
setServiceImplementation: PropTypes.func,
}),
viewportIndex: PropTypes.number,
};
export default ViewportDialogProvider;
@@ -0,0 +1,165 @@
---
name: ViewportDialogProvider
route: customHooks/viewportDialogProvider
---
import { Playground, Props } from 'docz';
<!-- This is a workaround to import things from ohif/core as docz does not allow us to access window element and @ohif/core does use it once we import to instanciate cornerstone -->
import { UIViewportDialogService, ServicesManager } from './../../../core/src/services';
import {
ViewportDialogProvider,
Dialog,
Button,
useViewportDialog,
Notification,
} from '@ohif/ui';
# Viewport Dialog Provider
This is a context provider that allow the application to share the modal
component across all application.
## Sample
<Playground>
{() => {
const ViewportNotification = ({ hide }) => {
return (
<Notification
text="Track all measurement for this series?"
type="info"
actionButtons={
<div>
<Button onClick={hide}>No</Button>
<Button onClick={hide} className="ml-2">
No, do not ask again
</Button>
<Button onClick={hide} className="ml-2" color="primary">
Yes
</Button>
</div>
}
/>
);
};
const ViewportActionButtons = () => {
const dialog = useViewportDialog();
return (
<Button
onClick={() =>
dialog.show({
content: ViewportNotification,
})
}
>
Open Dialog
</Button>
);
};
return (
<div className="w-full flex flex-row p-4" style={{height: '400px'}}>
<div className="flex flex-1 items-center justify-center h-full w-full bg-black text-white border border-primary-main">
<ViewportDialogProvider dialog={Dialog}>
<div className="flex flex-1 flex-col items-center justify-center h-full">
<ViewportActionButtons />
<span>CONTENT 1</span>
</div>
</ViewportDialogProvider>
</div>
<div className="flex flex-1 items-center justify-center h-full w-full bg-black text-white border border-primary-main">
<ViewportDialogProvider dialog={Dialog}>
<div className="flex flex-1 flex-col items-center justify-center h-full">
<ViewportActionButtons />
<span>CONTENT 1</span>
</div>
</ViewportDialogProvider>
</div>
</div>
);
}}
</Playground>
## Example using UIViewportDialogService
<Playground>
{() => {
const ViewportNotification = ({ hide }) => {
return (
<Notification
text="Track all measurement for this series?"
type="info"
actionButtons={
<div>
<Button onClick={hide}>No</Button>
<Button className="ml-2">No, do not ask again</Button>
<Button className="ml-2" color="primary">
Yes
</Button>
</div>
}
/>
);
};
// Creating servicesManager and register services should be in the root of your app
const servicesManager = new ServicesManager();
servicesManager.registerServices([UIViewportDialogService]);
// Get service instance
const _UIViewportDialogService =
servicesManager.services.UIViewportDialogService;
return (
<div className="w-full flex flex-col p-4" style={{height: '400px'}}>
<div className="flex flex-2">
<Button
className="mr-4 mb-4"
onClick={() =>
_UIViewportDialogService.show({
content: ViewportNotification,
viewportIndex: 0,
})
}
>
Open dialog on 0
</Button>
<Button
className="mr-4 mb-4"
onClick={() =>
_UIViewportDialogService.show({
content: ViewportNotification,
viewportIndex: 1,
})
}
>
Open dialog on 1
</Button>
</div>
<div className="flex flex-1 w-full flex-row">
<ViewportDialogProvider
dialog={Dialog}
service={_UIViewportDialogService}
viewportIndex={0}
>
<div className="flex flex-1 items-center justify-center h-full bg-black text-white border border-primary-main">
CONTENT 0
</div>
</ViewportDialogProvider>
<ViewportDialogProvider
dialog={Dialog}
service={_UIViewportDialogService}
viewportIndex={1}
>
<div className="flex flex-1 items-center justify-center h-full bg-black text-white border border-primary-main">
CONTENT 1
</div>
</ViewportDialogProvider>
</div>
</div>
);
}}
</Playground>
## Properties:
<Props of={ViewportDialogProvider} />
+6 -1
View File
@@ -3,4 +3,9 @@ export {
useModal,
withModal,
ModalConsumer,
} from './ModalProvider.js';
} from './ModalProvider';
export {
default as ViewportDialogProvider,
useViewportDialog,
} from './ViewportDialogProvider';
@@ -15,7 +15,7 @@ export const Sidebar = React.forwardRef((props, ref) => {
const menus = useMenus({ query });
const currentDoc = useCurrentDoc();
const currentDocRef = useRef();
const handleChange = ev => {
const handleChange = (ev) => {
setQuery(ev.target.value);
};
useEffect(() => {
@@ -40,26 +40,26 @@ export const Sidebar = React.forwardRef((props, ref) => {
'Data Display',
'Other',
],
'Custom Hooks': ['ModalProvider'],
'Custom Hooks': ['ModalProvider', 'ViewportDialogProvider'],
Examples: ['Views'],
System: ['Colors'],
};
const renderMenuCategories = () => {
return Object.keys(customMenus).map(menuName => {
return Object.keys(customMenus).map((menuName) => {
return (
<div key={menuName}>
<h2 className="pl-2 border-l-8 -ml-4 border-secondary-active">
{menuName}
</h2>
{customMenus[menuName].map(item => item)}
{customMenus[menuName].map((item) => item)}
</div>
);
});
};
const getMenuCategory = menuName => {
return Object.keys(MENU_CATEGORIES).find(category => {
const getMenuCategory = (menuName) => {
return Object.keys(MENU_CATEGORIES).find((category) => {
if (MENU_CATEGORIES[category].includes(menuName)) {
return category;
}
@@ -99,7 +99,7 @@ export const Sidebar = React.forwardRef((props, ref) => {
onChange={handleChange}
/>
{menus &&
menus.map(menu => {
menus.map((menu) => {
const isGroup = !!menu.menu;
const Component = isGroup ? NavGroup : NavLink;
const menuCategory = getMenuCategory(menu.name) || null;