UNPKG

@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
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); };