feat: Add new annotate tool using new dialog service (#1211)

* Testing dialog

* Refactor modal and add dialog component to simple dialog

* Use existent dialog

* Expect event from getText callback (annotation)

* Bump cornerstone-tools version

* Use simple dialog

* bump cornersotne version

* CR Update: Update dialgo method names and default values

* CR Update: Bump overlay and show only if theres at least one overlay prop set to true

* CR Update: Use percentage over view height in draggable area

* Fix broken test vtk checks WWWC tool

* Comment test (non-deterministic)
This commit is contained in:
Igor Octaviano authored and Danny Brown committed 2019-11-25 17:13:42 -05:00
1 parent 1334ba8eb0
commit 8fd3af1e13
18 files changed
+372 -254

No files matched your search

+143 -109
View File
@@ -34,49 +34,45 @@ const DialogProvider = ({ children, service }) => {
}, [create, dismiss, service]);
/**
* Creates a dialog and return its id.
* UI Dialog
*
* @returns id
* @typedef {Object} DialogProps
* @property {string} id The dialog id.
* @property {DialogContent} content The dialog content.
* @property {Object} contentProps The dialog content props.
* @property {boolean} isDraggable Controls if dialog content is draggable or not.
* @property {boolean} showOverlay Controls dialog overlay.
* @property {ElementPosition} defaultPosition Specifies the `x` and `y` that the dragged item should start at.
* @property {ElementPosition} position If this property is present, the item becomes 'controlled' and is not responsive to user input.
* @property {Function} onStart Called when dragging starts. If `false` is returned any handler, the action will cancel.
* @property {Function} onStop Called when dragging stops.
* @property {Function} onDrag Called while dragging.
*/
const create = useCallback(
({
id,
content,
onSubmit,
onClose,
onDrag,
onStop,
isDraggable,
defaultPosition,
position,
}) => {
let dialogId = id;
if (!dialogId) {
dialogId = utils.guid();
}
const newDialog = {
id: dialogId,
content,
onSubmit,
onClose,
onDrag,
onStop,
isDraggable,
defaultPosition,
position,
};
/**
* Creates a new dialog and return its id.
*
* @param {DialogProps} props The dialog props.
* @returns The new dialog id.
*/
const create = useCallback(props => {
const { id } = props;
setDialogs(dialogs => [...dialogs, newDialog]);
let dialogId = id;
if (!dialogId) {
dialogId = utils.guid();
}
return dialogId;
},
[]
);
setDialogs(dialogs => [...dialogs, { ...props, id: dialogId }]);
return dialogId;
}, []);
/**
* Dismisses the dialog with a given id.
*
* @param {Object} props -
* @property {string} props.id The dialog id.
* @returns void
*/
const dismiss = useCallback(({ id }) => {
@@ -92,18 +88,102 @@ const DialogProvider = ({ children, service }) => {
setDialogs([]);
};
/**
* Indicate if there are no dialogs present.
*
* @returns True if no dialogs are present.
*/
const isEmpty = () => dialogs && dialogs.length < 1;
/**
* Moves the dialog to the foreground if clicked.
*
* @param {string} id The dialog id.
* @returns void
*/
const _bringToFront = id => {
setDialogs(dialogs => {
const topDialog = dialogs.find(dialog => dialog.id === id);
return topDialog
? [...dialogs.filter(dialog => dialog.id !== id), topDialog]
: [];
});
};
const renderDialogs = () =>
dialogs.map(dialog => {
const {
id,
content: DialogContent,
contentProps,
position,
defaultPosition,
isDraggable = true,
onStart,
onStop,
onDrag,
} = dialog;
return (
<Draggable
key={id}
disabled={!isDraggable}
position={position}
defaultPosition={lastDialogPosition || defaultPosition}
bounds="parent"
onStart={event => {
const e = event || window.event;
const target = e.target || e.srcElement;
const BLACKLIST = [
'SVG',
'BUTTON',
'PATH',
'INPUT',
'SPAN',
'LABEL',
];
if (BLACKLIST.includes(target.tagName.toUpperCase())) {
return false;
}
if (validCallback(onStart)) {
return onStart(event);
}
}}
onStop={event => {
setIsDragging(false);
if (validCallback(onStop)) {
return onStop(event);
}
}}
onDrag={event => {
setIsDragging(true);
_bringToFront(id);
_updateLastDialogPosition(id);
if (validCallback(onDrag)) {
return onDrag(event);
}
}}
>
<div
id={`draggableItem-${id}`}
className={classNames('DraggableItem', isDragging && 'dragging')}
style={{ zIndex: '999', position: 'absolute' }}
onClick={() => _bringToFront(id)}
>
<DialogContent {...dialog} {...contentProps} />
</div>
</Draggable>
);
});
/**
* Update the last dialog position to be used as the new default position.
*
* @returns void
*/
const _reorder = id => {
setDialogs(dialogs => [
...dialogs.filter(dialog => dialog.id !== id),
dialogs.find(dialog => dialog.id === id),
]);
};
const _updateLastDialogPosition = dialogId => {
const draggableItemBounds = document
.querySelector(`#draggableItem-${dialogId}`)
@@ -114,70 +194,36 @@ const DialogProvider = ({ children, service }) => {
});
};
const validCallback = callback => callback && typeof callback === 'function';
return (
<DialogContext.Provider value={{ create, dismiss, dismissAll, dialogs }}>
<DialogContext.Provider value={{ create, dismiss, dismissAll, isEmpty }}>
<div className="DraggableArea">
{dialogs.map(dialog => {
const {
id,
content: Dialog,
position /* Position of the dialog. {{x: 0, y: 0}} */,
defaultPosition,
isDraggable = true,
onStart = () => {},
onStop = () => {},
onDrag = () => {},
} = dialog;
return (
<Draggable
key={id}
disabled={!isDraggable}
position={position}
defaultPosition={lastDialogPosition || defaultPosition}
bounds="parent"
onStart={event => {
const e = event || window.event;
const target = e.target || e.srcElement;
const BLACKLIST = ['SVG', 'BUTTON', 'PATH', 'INPUT'];
if (BLACKLIST.includes(target.tagName.toUpperCase())) {
return false;
}
onStart(event);
}}
onStop={event => {
onStop(event);
setIsDragging(false);
return;
}}
onDrag={event => {
setIsDragging(true);
_reorder(id);
_updateLastDialogPosition(id);
onDrag(event);
}}
>
<div
id={`draggableItem-${id}`}
className={classNames(
'DraggableItem',
isDragging && 'dragging'
)}
style={{ zIndex: '999', position: 'absolute' }}
onClick={() => _reorder(id)}
>
<Dialog {...dialog} />
</div>
</Draggable>
);
})}
{dialogs.some(dialog => dialog.showOverlay) ? (
<div className="Overlay active">{renderDialogs()}</div>
) : (
renderDialogs()
)}
</div>
{children}
</DialogContext.Provider>
);
};
/**
*
* High Order Component to use the dialog methods through a Class Component
*
*/
export const withDialog = Component => {
return function WrappedComponent(props) {
const { create, dismiss, dismissAll, isEmpty } = useDialog();
return (
<Component {...props} dialog={{ create, dismiss, dismissAll, isEmpty }} />
);
};
};
DialogProvider.defaultProps = {
service: null,
};
@@ -193,16 +239,4 @@ DialogProvider.propTypes = {
}),
};
/**
*
* High Order Component to use the dialog methods through a Class Component
*
*/
export const withDialog = Component => {
return function WrappedComponent(props) {
const { create, dismiss, dismissAll } = useDialog();
return <Component {...props} dialog={{ create, dismiss, dismissAll }} />;
};
};
export default DialogProvider;