import type { DialogProps, HTMLDivProps, OverlayProps, } from '@blueprintjs/core'; import { Button, Classes, H6, Icon, IconSize, Overlay2, mergeRefs, } from '@blueprintjs/core'; import { SmallCross } from '@blueprintjs/icons'; import { Global } from '@emotion/react'; import styled from '@emotion/styled'; import type { ReactNode, RefObject } from 'react'; import { useLayoutEffect, useRef } from 'react'; const Container = styled.div` position: absolute; top: 0; left: 0; min-height: 100%; pointer-events: none; user-select: none; width: 100%; `; interface Position { x: number; y: number; } type DialogPlacement = | 'top' | 'bottom' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center-left' | 'center-right'; interface HeaderElement { headerLeftElement?: ReactNode; headerRightElement?: ReactNode; } interface DraggableDialogProps extends Omit, Pick, HeaderElement { placement?: DialogPlacement; } interface InnerDraggableDialogProps extends DraggableDialogProps { innerDialogRef: RefObject; } export function DraggableDialog(props: DraggableDialogProps) { const { onClose, headerLeftElement, headerRightElement, placement, hasBackdrop, ...otherProps } = props; const dialogRef = useRef(null); return ( <> ); } function InnerDraggableDialog(props: InnerDraggableDialogProps) { const { children, containerRef, role = 'dialog', style, className = '', isCloseButtonShown, onClose, icon, title, headerLeftElement, headerRightElement, placement = 'center', innerDialogRef, } = props; const offsetRef = useRef({ x: 0, y: 0, }); const containerRefInternal = useRef(null); useLayoutEffect(() => { const updateTransform = () => { if (!innerDialogRef.current || !containerRefInternal.current) { return; } const dialogRect = innerDialogRef.current.getBoundingClientRect(); const parentContainerRect = containerRefInternal.current.getBoundingClientRect(); const { transformX, transformY } = calculateTransform(placement, { dialogRect, parentContainerRect, }); innerDialogRef.current.style.transform = `translate(${transformX}px, ${transformY}px)`; }; const frameId = requestAnimationFrame(updateTransform); return () => { cancelAnimationFrame(frameId); }; }, [innerDialogRef, placement]); function handleMouseDown(event: React.MouseEvent) { const target = event.currentTarget as HTMLElement; if (!containerRefInternal.current) { return; } const dialogRect = target.getBoundingClientRect(); const containerRect = containerRefInternal.current.getBoundingClientRect(); const offsetX = event.clientX - (dialogRect.left - containerRect.left); const offsetY = event.clientY - (dialogRect.top - containerRect.top); offsetRef.current = { x: offsetX, y: offsetY, }; function handleMouseMove(event: MouseEvent) { target.style.cursor = 'move'; if (!innerDialogRef.current || !offsetRef.current) { return; } const offsetX = event.clientX - offsetRef.current.x; const offsetY = event.clientY - offsetRef.current.y; innerDialogRef.current.style.transform = `translate(${offsetX}px, ${offsetY}px)`; } function handleMouseUp() { target.style.cursor = 'default'; globalThis.removeEventListener('mousemove', handleMouseMove); globalThis.removeEventListener('mouseup', handleMouseUp); } globalThis.addEventListener('mousemove', handleMouseMove); globalThis.addEventListener('mouseup', handleMouseUp); } return (
{children}
); } function CloseButton( props: Pick, ) { const { isCloseButtonShown = true, onClose } = props; if (!isCloseButtonShown) { return null; } return (