@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
110 lines (109 loc) • 3.98 kB
JavaScript
import * as React from 'react';
import { Resizable } from 're-resizable';
import useDraggable from '../utils/useDraggable';
import { isBrowserDocumentAvailable } from '../../View/UIHelper';
import { createPortal } from 'react-dom';
import { useStacking } from './useStacking';
let portalElement;
const ensurePortalElement = () => {
if (!isBrowserDocumentAvailable()) {
return;
}
if (portalElement) {
return;
}
portalElement = document.createElement('div');
portalElement.classList.add('ab-cmp-modal-window');
document.body.appendChild(portalElement);
};
const normalizeTopLeft = (position) => (position < 0 ? 0 : position);
const getResizePositionDelta = (direction, delta) => {
const positionDelta = { x: 0, y: 0 };
const left = -delta.width;
const top = -delta.height;
const directions = ['top', 'left', 'topLeft', 'bottomLeft', 'topRight'];
if (directions.indexOf(direction) !== -1) {
if (direction === 'bottomLeft') {
positionDelta.x += left;
}
else if (direction === 'topRight') {
positionDelta.y += top;
}
else {
positionDelta.x += left;
positionDelta.y += top;
}
return positionDelta;
}
return null;
};
export const WindowModal = (props) => {
ensurePortalElement();
const positionDeltaRef = React.useRef(null);
const normalizedPosition = {
x: normalizeTopLeft(props.position?.x),
y: normalizeTopLeft(props.position?.y),
};
const positionRef = React.useRef(normalizedPosition);
const stacking = useStacking();
/**
* This is needed because the function called in onDrop is saved when
* it gets attached to the DOM element event handler.
* This handler changes only when the underlying node changes.
*/
positionRef.current = normalizedPosition;
const style = {
zIndex: stacking.zIndex,
position: 'absolute',
left: normalizedPosition.x,
top: normalizedPosition.y,
};
const handleDrop = (dx, dy) => {
const newPosition = {
x: positionRef.current.x + dx,
y: positionRef.current.y + dy,
};
props.onChange({
position: newPosition,
size: props.size,
});
};
const { targetRef, applyTransform } = useDraggable({
handleSelector: props.handleSelector,
onDrop: handleDrop,
});
const handleResizeStop = (event, direction, elementRef, delta) => {
let newPosition = normalizedPosition;
if (positionDeltaRef.current) {
newPosition = {
x: normalizedPosition.x + positionDeltaRef.current.x,
y: normalizedPosition.y + positionDeltaRef.current.y,
};
positionDeltaRef.current = null;
applyTransform(0, 0);
}
const newSize = {
width: props.size.width + delta.width,
height: props.size.height + delta.height,
};
props.onChange({
position: newPosition,
size: newSize,
});
};
const handleResize = React.useCallback((event, direction, elementRef, delta) => {
const positionDelta = getResizePositionDelta(direction, delta);
if (positionDelta) {
positionDeltaRef.current = positionDelta;
applyTransform(positionDelta.x, positionDelta.y);
}
}, []);
const ResizableCmp = Resizable;
return createPortal(React.createElement("div", { style: style,
//@ts-ignore
ref: targetRef, onMouseDown: stacking.bringInFront },
React.createElement(ResizableCmp, { minWidth: props.minWidth, minHeight: props.minHeight, onResizeStop: handleResizeStop, onResize: handleResize, bounds: "window", defaultSize: {
width: props.size.width,
height: props.size.height,
} }, props.children)), portalElement);
};