ohif-viewer/platform/ui/src/components/ViewportPane/ViewportPane.jsx
2020-07-10 15:52:17 -04:00

111 lines
3.1 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useDrop } from 'react-dnd';
// NOTE: If we found a way to make `useDrop` conditional,
// Or we provided a HOC of this component, we could provide
// this UI without the DragAndDropContext dependency.
function ViewportPane({
children,
className,
isActive,
onDrop,
onDoubleClick,
onInteraction,
acceptDropsFor,
}) {
let dropElement = null;
const [{ isHovered, isHighlighted }, drop] = useDrop({
accept: acceptDropsFor,
// TODO: pass in as prop?
drop: (droppedItem, monitor) => {
const canDrop = monitor.canDrop();
const isOver = monitor.isOver();
if (canDrop && isOver && onDrop) {
onInteractionHandler();
onDrop(droppedItem);
}
},
// Monitor, and collect props; returned as values by `useDrop`
collect: monitor => ({
isHighlighted: monitor.canDrop(),
isHovered: monitor.isOver(),
}),
});
const focus = () => {
if (dropElement) {
dropElement.focus();
}
};
const onInteractionHandler = (event) => {
focus();
onInteraction(event);
};
const refHandler = element => {
drop(element);
dropElement = element;
};
return (
<div
ref={refHandler}
// onInteractionHandler...
// https://reactjs.org/docs/events.html#mouse-events
// https://stackoverflow.com/questions/8378243/catch-scrolling-event-on-overflowhidden-element
onMouseDown={onInteractionHandler}
onDoubleClick={onDoubleClick}
onClick={onInteractionHandler}
onScroll={onInteractionHandler}
onWheel={onInteractionHandler}
className={classnames(
'flex flex-col',
'rounded-lg hover:border-primary-light transition duration-300 outline-none overflow-hidden',
{
'border-2 border-primary-light': isActive,
'border border-secondary-light': !isActive,
},
className
)}
// Normally, we'd use tailwindcss classes here, but margin and border classes use different units
// m-# (rem), border-# (px). To make sure we don't change the box size of our viewports
// and trigger a canvas resize, we have to use this little trick for margin.
// Assumes a :root font-fize of `16px`
style={{
margin: isActive ? '3px' : '4px',
}}
>
{children}
</div>
);
}
ViewportPane.propTypes = {
/** The ViewportComp */
children: PropTypes.node.isRequired,
/** Classes to append to container */
className: PropTypes.string,
/** Bool to show active styling */
isActive: PropTypes.bool.isRequired,
/** Indicates drag items we should accept for drops */
acceptDropsFor: PropTypes.string.isRequired,
/** Function that handles drop events */
onDrop: PropTypes.func.isRequired,
/** Called when the viewportPane is interacted with by the user */
onInteraction: PropTypes.func.isRequired,
/** Executed when the pane is double clicked */
onDoubleClick: PropTypes.func,
};
const noop = () => { };
ViewportPane.defaultProps = {
onInteraction: noop,
};
export default ViewportPane;